From 18accb2acf8562f8c69d23f7b9523f6194d641c9 Mon Sep 17 00:00:00 2001 From: Tony Cook Date: Mon, 25 Mar 2002 11:52:49 +0000 Subject: [PATCH] Ticket #369 - writing grayscale images to GIF related change to support passing const channel arrays to i_gsamp() --- Changes | 4 + datatypes.h | 4 +- image.c | 14 +-- imagei.h | 2 +- img16.c | 8 +- imgdouble.c | 8 +- maskimg.c | 8 +- palimg.c | 4 +- quant.c | 253 ++++++++++++++++++++++++++++++++++++---------------- t/t105gif.t | 57 +++++++++++- 10 files changed, 258 insertions(+), 104 deletions(-) diff --git a/Changes b/Changes index 3eaf3f8a..aa71ae4e 100644 --- a/Changes +++ b/Changes @@ -610,6 +610,10 @@ Revision history for Perl extension Imager. - make t1log optional, defaulting to off. You can enable the log with Imager::init(t1log=>1) (Ticket #369) - quote a few hash key strings to prevent warnings on 5.004 + - modify quantization code to handle 1 channel images + correctly (Ticket #365) + - make channel pointer to i_gsamp() const int * so we can pass + const arrays ================================================================= diff --git a/datatypes.h b/datatypes.h index 13bdbe82..c97c2780 100644 --- a/datatypes.h +++ b/datatypes.h @@ -85,9 +85,9 @@ typedef int (*i_f_glin_t)(i_img *im, int x, int r, int y, i_color *vals); typedef int (*i_f_glinf_t)(i_img *im, int x, int r, int y, i_fcolor *vals); typedef int (*i_f_gsamp_t)(i_img *im, int x, int r, int y, i_sample_t *samp, - int *chans, int chan_count); + const int *chans, int chan_count); typedef int (*i_f_gsampf_t)(i_img *im, int x, int r, int y, i_fsample_t *samp, - int *chan, int chan_count); + const int *chan, int chan_count); typedef int (*i_f_gpal_t)(i_img *im, int x, int r, int y, i_palidx *vals); typedef int (*i_f_ppal_t)(i_img *im, int x, int r, int y, i_palidx *vals); diff --git a/image.c b/image.c index 9e9482c4..3fab8215 100644 --- a/image.c +++ b/image.c @@ -48,10 +48,10 @@ static int i_ppixf_d(i_img *im, int x, int y, i_fcolor *val); static int i_gpixf_d(i_img *im, int x, int y, i_fcolor *val); static int i_glinf_d(i_img *im, int l, int r, int y, i_fcolor *vals); static int i_plinf_d(i_img *im, int l, int r, int y, i_fcolor *vals); -static int i_gsamp_d(i_img *im, int l, int r, int y, i_sample_t *samps, int *chans, int chan_count); -static int i_gsampf_d(i_img *im, int l, int r, int y, i_fsample_t *samps, int *chans, int chan_count); -static int i_psamp_d(i_img *im, int l, int r, int y, i_sample_t *samps, int *chans, int chan_count); -static int i_psampf_d(i_img *im, int l, int r, int y, i_fsample_t *samps, int *chans, int chan_count); +static int i_gsamp_d(i_img *im, int l, int r, int y, i_sample_t *samps, const int *chans, int chan_count); +static int i_gsampf_d(i_img *im, int l, int r, int y, i_fsample_t *samps, const int *chans, int chan_count); +/*static int i_psamp_d(i_img *im, int l, int r, int y, i_sample_t *samps, int *chans, int chan_count); + static int i_psampf_d(i_img *im, int l, int r, int y, i_fsample_t *samps, int *chans, int chan_count);*/ /* =item ICL_new_internal(r, g, b, a) @@ -1508,7 +1508,7 @@ Returns the number of samples read (which should be (r-l) * bits_set(chan_mask) static int i_gsamp_d(i_img *im, int l, int r, int y, i_sample_t *samps, - int *chans, int chan_count) { + const int *chans, int chan_count) { int ch, count, i, w; unsigned char *data; @@ -1566,7 +1566,7 @@ Returns the number of samples read (which should be (r-l) * bits_set(chan_mask) static int i_gsampf_d(i_img *im, int l, int r, int y, i_fsample_t *samps, - int *chans, int chan_count) { + const int *chans, int chan_count) { int ch, count, i, w; unsigned char *data; for (ch = 0; ch < chan_count; ++ch) { @@ -1728,7 +1728,7 @@ int i_glinf_fp(i_img *im, int l, int r, int y, i_fcolor *pix) { =cut */ int i_gsampf_fp(i_img *im, int l, int r, int y, i_fsample_t *samp, - int *chans, int chan_count) { + int const *chans, int chan_count) { i_sample_t *work; if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) { diff --git a/imagei.h b/imagei.h index fb865010..b9a8dc3a 100644 --- a/imagei.h +++ b/imagei.h @@ -15,7 +15,7 @@ extern int i_gpixf_fp(i_img *im, int x, int y, i_fcolor *pix); extern int i_plinf_fp(i_img *im, int l, int r, int y, i_fcolor *pix); extern int i_glinf_fp(i_img *im, int l, int r, int y, i_fcolor *pix); extern int i_gsampf_fp(i_img *im, int l, int r, int y, i_fsample_t *samp, - int *chans, int chan_count); + int const *chans, int chan_count); /* wrapper functions that forward palette calls to the underlying image, assuming the underlying image is the first pointer in whatever diff --git a/img16.c b/img16.c index bd08738a..53aa25a0 100644 --- a/img16.c +++ b/img16.c @@ -32,9 +32,9 @@ static int i_gpixf_d16(i_img *im, int x, int y, i_fcolor *val); static int i_glinf_d16(i_img *im, int l, int r, int y, i_fcolor *vals); static int i_plinf_d16(i_img *im, int l, int r, int y, i_fcolor *vals); static int i_gsamp_d16(i_img *im, int l, int r, int y, i_sample_t *samps, - int *chans, int chan_count); + int const *chans, int chan_count); static int i_gsampf_d16(i_img *im, int l, int r, int y, i_fsample_t *samps, - int *chans, int chan_count); + int const *chans, int chan_count); /* =item IIM_base_16bit_direct @@ -313,7 +313,7 @@ static int i_plinf_d16(i_img *im, int l, int r, int y, i_fcolor *vals) { } static int i_gsamp_d16(i_img *im, int l, int r, int y, i_sample_t *samps, - int *chans, int chan_count) { + int const *chans, int chan_count) { int ch, count, i, w; int off; @@ -358,7 +358,7 @@ static int i_gsamp_d16(i_img *im, int l, int r, int y, i_sample_t *samps, } static int i_gsampf_d16(i_img *im, int l, int r, int y, i_fsample_t *samps, - int *chans, int chan_count) { + int const *chans, int chan_count) { int ch, count, i, w; int off; diff --git a/imgdouble.c b/imgdouble.c index 0afd3dc2..90587820 100644 --- a/imgdouble.c +++ b/imgdouble.c @@ -32,9 +32,9 @@ static int i_gpixf_ddoub(i_img *im, int x, int y, i_fcolor *val); static int i_glinf_ddoub(i_img *im, int l, int r, int y, i_fcolor *vals); static int i_plinf_ddoub(i_img *im, int l, int r, int y, i_fcolor *vals); static int i_gsamp_ddoub(i_img *im, int l, int r, int y, i_sample_t *samps, - int *chans, int chan_count); + int const *chans, int chan_count); static int i_gsampf_ddoub(i_img *im, int l, int r, int y, i_fsample_t *samps, - int *chans, int chan_count); + int const *chans, int chan_count); /* =item IIM_base_16bit_direct @@ -260,7 +260,7 @@ static int i_plinf_ddoub(i_img *im, int l, int r, int y, i_fcolor *vals) { } static int i_gsamp_ddoub(i_img *im, int l, int r, int y, i_sample_t *samps, - int *chans, int chan_count) { + int const *chans, int chan_count) { int ch, count, i, w; int off; @@ -305,7 +305,7 @@ static int i_gsamp_ddoub(i_img *im, int l, int r, int y, i_sample_t *samps, } static int i_gsampf_ddoub(i_img *im, int l, int r, int y, i_fsample_t *samps, - int *chans, int chan_count) { + int const *chans, int chan_count) { int ch, count, i, w; int off; diff --git a/maskimg.c b/maskimg.c index d8656f63..bc31c8af 100644 --- a/maskimg.c +++ b/maskimg.c @@ -43,9 +43,9 @@ static int i_gpixf_masked(i_img *im, int x, int y, i_fcolor *pix); static int i_glin_masked(i_img *im, int l, int r, int y, i_color *vals); static int i_glinf_masked(i_img *im, int l, int r, int y, i_fcolor *vals); static int i_gsamp_masked(i_img *im, int l, int r, int y, i_sample_t *samp, - int *chans, int chan_count); + int const *chans, int chan_count); static int i_gsampf_masked(i_img *im, int l, int r, int y, i_fsample_t *samp, - int *chans, int chan_count); + int const *chans, int chan_count); static int i_gpal_masked(i_img *im, int l, int r, int y, i_palidx *vals); static int i_ppal_masked(i_img *im, int l, int r, int y, i_palidx *vals); @@ -438,7 +438,7 @@ static int i_glinf_masked(i_img *im, int l, int r, int y, i_fcolor *vals) { } static int i_gsamp_masked(i_img *im, int l, int r, int y, i_sample_t *samp, - int *chans, int chan_count) { + int const *chans, int chan_count) { i_img_mask_ext *ext = MASKEXT(im); if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) { if (r > im->xsize) @@ -452,7 +452,7 @@ static int i_gsamp_masked(i_img *im, int l, int r, int y, i_sample_t *samp, } static int i_gsampf_masked(i_img *im, int l, int r, int y, i_fsample_t *samp, - int *chans, int chan_count) { + int const *chans, int chan_count) { i_img_mask_ext *ext = MASKEXT(im); if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) { if (r > im->xsize) diff --git a/palimg.c b/palimg.c index 9ce30f6c..4fb43c8a 100644 --- a/palimg.c +++ b/palimg.c @@ -26,7 +26,7 @@ static int i_ppix_p(i_img *im, int x, int y, i_color *val); static int i_gpix_p(i_img *im, int x, int y, i_color *val); static int i_glin_p(i_img *im, int l, int r, int y, i_color *vals); static int i_plin_p(i_img *im, int l, int r, int y, i_color *vals); -static int i_gsamp_p(i_img *im, int l, int r, int y, i_sample_t *samps, int *chans, int chan_count); +static int i_gsamp_p(i_img *im, int l, int r, int y, i_sample_t *samps, int const *chans, int chan_count); static int i_gpal_p(i_img *pm, int l, int r, int y, i_palidx *vals); static int i_ppal_p(i_img *pm, int l, int r, int y, i_palidx *vals); static int i_addcolors_p(i_img *im, i_color *color, int count); @@ -353,7 +353,7 @@ static int i_plin_p(i_img *im, int l, int r, int y, i_color *vals) { =cut */ static int i_gsamp_p(i_img *im, int l, int r, int y, i_sample_t *samps, - int *chans, int chan_count) { + int const *chans, int chan_count) { int ch; if (y >= 0 && y < im->ysize && l < im->xsize && l >= 0) { int palsize = PALEXT(im)->count; diff --git a/quant.c b/quant.c index 023a7d42..be67662e 100644 --- a/quant.c +++ b/quant.c @@ -102,7 +102,8 @@ i_palidx *quant_translate(i_quantize *quant, i_img *img) { return result; } -#ifdef HAVE_LIBGIF +#ifdef HAVE_LIBGIF_THIS_NOT_USED + #include "gif_lib.h" #define GET_RGB(im, x, y, ri, gi, bi, col) \ @@ -112,6 +113,7 @@ i_palidx *quant_translate(i_quantize *quant, i_img *img) { static int quant_replicate(i_img *im, i_palidx *output, i_quantize *quant); + /* Use the gif_lib quantization functions to quantize the image */ static void translate_giflib(i_quantize *quant, i_img *img, i_palidx *out) { int x,y,ColorMapSize,colours_in; @@ -286,7 +288,7 @@ typedef struct { int pdc; } pbox; -static void prescan(i_img **im,int count, int cnum, cvec *clr); +static void prescan(i_img **im,int count, int cnum, cvec *clr, i_sample_t *line); static void reorder(pbox prescan[512]); static int pboxcmp(const pbox *a,const pbox *b); static void boxcenter(int box,cvec *cv); @@ -303,6 +305,9 @@ static int maxdist(int boxnum,cvec *cv); static int pixbox(i_color *ic) { return ((ic->channel[0] & 224)<<1)+ ((ic->channel[1]&224)>>2) + ((ic->channel[2] &224) >> 5); } +static int +pixbox_ch(i_sample_t *chans) { return ((chans[0] & 224)<<1)+ ((chans[1]&224)>>2) + ((chans[2] &224) >> 5); } + static unsigned char g_sat(int in) { if (in>255) { return 255; } @@ -320,10 +325,20 @@ static int eucl_d(cvec* cv,i_color *cl) { return PWR2(cv->r-cl->channel[0])+PWR2(cv->g-cl->channel[1])+PWR2(cv->b-cl->channel[2]); } +static +int +eucl_d_ch(cvec* cv,i_sample_t *chans) { + return PWR2(cv->r - chans[0]) + PWR2(cv->g - chans[1]) + + PWR2(cv->b - chans[2]); +} + static int ceucl_d(i_color *c1, i_color *c2) { return PWR2(c1->channel[0]-c2->channel[0])+PWR2(c1->channel[1]-c2->channel[1])+PWR2(c1->channel[2]-c2->channel[2]); } +static const int +gray_samples[] = { 0, 0, 0 }; + /* This quantization algorithm and implementation routines are by Arnar @@ -380,12 +395,18 @@ static void makemap_addi(i_quantize *quant, i_img **imgs, int count) { cvec *clr; int cnum, i, x, y, bst_idx=0, ld, cd, iter, currhb, img_num; - i_color val; + i_sample_t *val; float dlt, accerr; hashbox *hb; + i_mempool mp; + int maxwidth = 0; + i_sample_t *line; + const int *sample_indices; - clr = (cvec *)mymalloc(sizeof(cvec) * quant->mc_size); - hb = mymalloc(sizeof(hashbox) * 512); + i_mempool_init(&mp); + + clr = i_mempool_alloc(&mp, sizeof(cvec) * quant->mc_size); + hb = i_mempool_alloc(&mp, sizeof(hashbox) * 512); for (i=0; i < quant->mc_count; ++i) { clr[i].r = quant->mc_colors[i].rgb.r; clr[i].g = quant->mc_colors[i].rgb.g; @@ -401,7 +422,13 @@ makemap_addi(i_quantize *quant, i_img **imgs, int count) { cnum = quant->mc_size; dlt = 1; - prescan(imgs, count, cnum, clr); + for (img_num = 0; img_num < count; ++img_num) { + if (imgs[img_num]->xsize > maxwidth) + maxwidth = imgs[img_num]->xsize; + } + line = i_mempool_alloc(&mp, 3 * maxwidth * sizeof(*line)); + + prescan(imgs, count, cnum, clr, line); cr_hashindex(clr, cnum, hb); for(iter=0;iter<3;iter++) { @@ -409,51 +436,64 @@ makemap_addi(i_quantize *quant, i_img **imgs, int count) { for (img_num = 0; img_num < count; ++img_num) { i_img *im = imgs[img_num]; - for(y=0;yysize;y++) for(x=0;xxsize;x++) { - ld=196608; - i_gpix(im,x,y,&val); - currhb=pixbox(&val); - /* printf("box = %d \n",currhb); */ - for(i=0;ichannels >= 3 ? NULL : gray_samples; + for(y=0;yysize;y++) { + i_gsamp(im, 0, im->xsize, y, line, sample_indices, 3); + val = line; + for(x=0;xxsize;x++) { + ld=196608; + /*i_gpix(im,x,y,&val);*/ + currhb=pixbox_ch(val); + /* printf("box = %d \n",currhb); */ + for(i=0;imc_count = cnum; #endif - /* don't want to keep this */ - myfree(hb); - myfree(clr); + i_mempool_destroy(&mp); } typedef struct { @@ -513,6 +551,9 @@ typedef struct { #define MED_CUT_INDEX(c) ((((c).rgb.r & 0xF8) << 7) | \ (((c).rgb.g & 0xF8) << 2) | (((c).rgb.b & 0xF8) >> 3)) +#define MED_CUT_GRAY_INDEX(c) ((((c).rgb.r & 0xF8) << 7) | \ + (((c).rgb.r & 0xF8) << 2) | (((c).rgb.r & 0xF8) >> 3)) + /* scale these to cover the whole range */ #define MED_CUT_RED(index) ((((index) & 0x7C00) >> 10) * 255 / 31) #define MED_CUT_GREEN(index) ((((index) & 0x3E0) >> 5) * 255 / 31) @@ -597,6 +638,9 @@ makemap_mediancut(i_quantize *quant, i_img **imgs, int count) { medcut_partition *parts; int part_num; int in, out; + /* number of channels we search for the best channel to partition + this isn't terribly efficient, but it should work */ + int chan_count; /*printf("images %d pal size %d\n", count, quant->mc_size);*/ @@ -619,12 +663,22 @@ makemap_mediancut(i_quantize *quant, i_img **imgs, int count) { /* build the stats */ total_pixels = 0; + chan_count = 1; /* assume we just have grayscale */ for (imgn = 0; imgn < count; ++imgn) { total_pixels += imgs[imgn]->xsize * imgs[imgn]->ysize; for (y = 0; y < imgs[imgn]->ysize; ++y) { i_glin(imgs[imgn], 0, imgs[imgn]->xsize, y, line); - for (x = 0; x < imgs[imgn]->xsize; ++x) { - ++colors[MED_CUT_INDEX(line[x])].count; + if (imgs[imgn]->channels > 2) { + chan_count = 3; + for (x = 0; x < imgs[imgn]->xsize; ++x) { + ++colors[MED_CUT_INDEX(line[x])].count; + } + } + else { + /* a gray-scale image, just use the first channel */ + for (x = 0; x < imgs[imgn]->xsize; ++x) { + ++colors[MED_CUT_GRAY_INDEX(line[x])].count; + } } } } @@ -674,7 +728,7 @@ makemap_mediancut(i_quantize *quant, i_img **imgs, int count) { one color */ max_size = -1; for (i = 0; i < color_count; ++i) { - for (ch = 0; ch < 3; ++ch) { + for (ch = 0; ch < chan_count; ++ch) { if (parts[i].width[ch] > max_size && parts[i].size > 1) { max_index = i; @@ -1142,22 +1196,44 @@ static void translate_addi(i_quantize *quant, i_img *img, i_palidx *out) { CF_SETUP; - if (pixdev) { - k=0; - for(y=0;yysize;y++) for(x=0;xxsize;x++) { - i_gpix(img,x,y,&val); - val.channel[0]=g_sat(val.channel[0]+(int)(pixdev*frandn())); - val.channel[1]=g_sat(val.channel[1]+(int)(pixdev*frandn())); - val.channel[2]=g_sat(val.channel[2]+(int)(pixdev*frandn())); - CF_FIND; - out[k++]=bst_idx; + if (img->channels >= 3) { + if (pixdev) { + k=0; + for(y=0;yysize;y++) for(x=0;xxsize;x++) { + i_gpix(img,x,y,&val); + val.channel[0]=g_sat(val.channel[0]+(int)(pixdev*frandn())); + val.channel[1]=g_sat(val.channel[1]+(int)(pixdev*frandn())); + val.channel[2]=g_sat(val.channel[2]+(int)(pixdev*frandn())); + CF_FIND; + out[k++]=bst_idx; + } + } else { + k=0; + for(y=0;yysize;y++) for(x=0;xxsize;x++) { + i_gpix(img,x,y,&val); + CF_FIND; + out[k++]=bst_idx; + } } - } else { - k=0; - for(y=0;yysize;y++) for(x=0;xxsize;x++) { - i_gpix(img,x,y,&val); - CF_FIND; - out[k++]=bst_idx; + } + else { + if (pixdev) { + k=0; + for(y=0;yysize;y++) for(x=0;xxsize;x++) { + i_gpix(img,x,y,&val); + val.channel[1] = val.channel[2] = + val.channel[0]=g_sat(val.channel[0]+(int)(pixdev*frandn())); + CF_FIND; + out[k++]=bst_idx; + } + } else { + k=0; + for(y=0;yysize;y++) for(x=0;xxsize;x++) { + i_gpix(img,x,y,&val); + val.channel[1] = val.channel[2] = val.channel[0]; + CF_FIND; + out[k++]=bst_idx; + } } } CF_CLEANUP; @@ -1254,6 +1330,9 @@ translate_errdiff(i_quantize *quant, i_img *img, i_palidx *out) { long ld, cd; errdiff_t perr; i_gpix(img, x, y, &val); + if (img->channels < 3) { + val.channel[1] = val.channel[2] = val.channel[0]; + } perr = err[x+mapo]; perr.r = perr.r < 0 ? -((-perr.r)/difftotal) : perr.r/difftotal; perr.g = perr.g < 0 ? -((-perr.g)/difftotal) : perr.g/difftotal; @@ -1290,9 +1369,10 @@ translate_errdiff(i_quantize *quant, i_img *img, i_palidx *out) { and that result is used as the initial value for the vectores */ -static void prescan(i_img **imgs,int count, int cnum, cvec *clr) { +static void prescan(i_img **imgs,int count, int cnum, cvec *clr, i_sample_t *line) { int i,k,j,x,y; - i_color val; + i_sample_t *val; + const int *chans; pbox prebox[512]; for(i=0;i<512;i++) { @@ -1304,9 +1384,13 @@ static void prescan(i_img **imgs,int count, int cnum, cvec *clr) { /* process each image */ for (i = 0; i < count; ++i) { i_img *im = imgs[i]; - for(y=0;yysize;y++) for(x=0;xxsize;x++) { - i_gpix(im,x,y,&val); - prebox[pixbox(&val)].pixcnt++; + chans = im->channels >= 3 ? NULL : gray_samples; + for(y=0;yysize;y++) { + i_gsamp(im, 0, im->xsize, y, line, chans, 3); + val = line; + for(x=0;xxsize;x++) { + prebox[pixbox_ch(val)].pixcnt++; + } } } @@ -1515,15 +1599,17 @@ transparent_threshold(i_quantize *quant, i_palidx *data, i_img *img, i_palidx trans_index) { int x, y; + i_sample_t *line = mymalloc(img->xsize * sizeof(i_sample_t)); + int trans_chan = img->channels > 2 ? 3 : 1; for (y = 0; y < img->ysize; ++y) { + i_gsamp(img, 0, img->xsize, y, line, &trans_chan, 1); for (x = 0; x < img->xsize; ++x) { - i_color val; - i_gpix(img, x, y, &val); - if (val.rgba.a < quant->tr_threshold) + if (line[x] < quant->tr_threshold) data[y*img->xsize+x] = trans_index; } } + myfree(line); } static void @@ -1536,6 +1622,8 @@ transparent_errdiff(i_quantize *quant, i_palidx *data, i_img *img, int errw, *err, *errp; int difftotal, out, error; int x, y, dx, dy, i; + i_sample_t *line; + int trans_chan = img->channels > 2 ? 3 : 1; /* no custom map for transparency (yet) */ index = quant->tr_errdiff & ed_mask; @@ -1550,22 +1638,22 @@ transparent_errdiff(i_quantize *quant, i_palidx *data, i_img *img, errp = err+mapo; memset(err, 0, sizeof(*err) * maph * errw); + line = mymalloc(img->xsize * sizeof(i_sample_t)); difftotal = 0; for (i = 0; i < maph * mapw; ++i) difftotal += map[i]; for (y = 0; y < img->ysize; ++y) { + i_gsamp(img, 0, img->xsize, y, line, &trans_chan, 1); for (x = 0; x < img->xsize; ++x) { - i_color val; - i_gpix(img, x, y, &val); - val.rgba.a = g_sat(val.rgba.a-errp[x]/difftotal); - if (val.rgba.a < 128) { + line[x] = g_sat(line[x]-errp[x]/difftotal); + if (line[x] < 128) { out = 0; data[y*img->xsize+x] = trans_index; } else { out = 255; } - error = out - val.rgba.a; + error = out - line[x]; for (dx = 0; dx < mapw; ++dx) { for (dy = 0; dy < maph; ++dy) { errp[x+dx-mapo+dy*errw] += error * map[dx+mapw*dy]; @@ -1577,6 +1665,8 @@ transparent_errdiff(i_quantize *quant, i_palidx *data, i_img *img, memcpy(err+dy*errw, err+(dy+1)*errw, sizeof(*err)*errw); memset(err+(maph-1)*errw, 0, sizeof(*err)*errw); } + myfree(err); + myfree(line); } /* builtin ordered dither maps */ @@ -1690,16 +1780,21 @@ transparent_ordered(i_quantize *quant, i_palidx *data, i_img *img, { unsigned char *spot; int x, y; + i_sample_t *line; + int trans_chan = img->channels > 2 ? 3 : 1; if (quant->tr_orddith == od_custom) spot = quant->tr_custom; else spot = orddith_maps[quant->tr_orddith]; + + line = mymalloc(img->xsize * sizeof(i_sample_t)); for (y = 0; y < img->ysize; ++y) { + i_gsamp(img, 0, img->xsize, y, line, &trans_chan, 1); for (x = 0; x < img->xsize; ++x) { - i_color val; - i_gpix(img, x, y, &val); - if (val.rgba.a < spot[(x&7)+(y&7)*8]) + if (line[x] < spot[(x&7)+(y&7)*8]) data[x+y*img->xsize] = trans_index; } } + myfree(line); } + diff --git a/t/t105gif.t b/t/t105gif.t index 94ede0ee..adf9c5b2 100644 --- a/t/t105gif.t +++ b/t/t105gif.t @@ -1,7 +1,7 @@ #!perl -w use strict; $|=1; -print "1..45\n"; +print "1..60\n"; use Imager qw(:all); sub ok ($$$); @@ -468,6 +468,61 @@ EOS ok(45, !grep(/Obsolete .* interlace .* gif_interlace/, @warns), "check for warning"); } + + # test that we get greyscale from 1 channel images + # we check for each makemap, and for each translate + print "# test writes of grayscale images - ticket #365\n"; + my $num = 46; + my $ooim = Imager->new(xsize=>50, ysize=>50, channels=>1); + for (my $y = 0; $y < 50; $y += 10) { + $ooim->box(box=>[ 0, $y, 49, $y+9], color=>NC($y*5,0,0), filled=>1); + } + my $ooim3 = $ooim->convert(preset=>'rgb'); + #$ooim3->write(file=>'testout/t105gray.ppm'); + my %maxerror = ( mediancut => 51000, + addi => 0, + closest => 0, + perturb => 0, + errdiff => 0 ); + for my $makemap (qw(mediancut addi)) { + print "# make_colors => $makemap\n"; + ok($num++, $ooim->write(file=>"testout/t105gray-$makemap.gif", + make_colors=>$makemap, + gifquant=>'gen'), + "writing gif with makemap $makemap"); + my $im2 = Imager->new; + if (ok($num++, $im2->read(file=>"testout/t105gray-$makemap.gif"), + "reading written grayscale gif")) { + my $diff = i_img_diff($ooim3->{IMG}, $im2->{IMG}); + ok($num++, $diff <= $maxerror{$makemap}, "comparing images $diff"); + #$im2->write(file=>"testout/t105gray-$makemap.ppm"); + } + else { + print "ok $num # skip\n"; + ++$num; + } + } + for my $translate (qw(closest perturb errdiff)) { + print "# translate => $translate\n"; + my @colors = map NC($_*50, $_*50, $_*50), 0..4; + ok($num++, $ooim->write(file=>"testout/t105gray-$translate.gif", + translate=>$translate, + make_colors=>'none', + colors=>\@colors, + gifquant=>'gen'), + "writing gif with translate $translate"); + my $im2 = Imager->new; + if (ok($num++, $im2->read(file=>"testout/t105gray-$translate.gif"), + "reading written grayscale gif")) { + my $diff = i_img_diff($ooim3->{IMG}, $im2->{IMG}); + ok($num++, $diff <= $maxerror{$translate}, "comparing images $diff"); + #$im2->write(file=>"testout/t105gray-$translate.ppm"); + } + else { + print "ok $num # skip\n"; + ++$num; + } + } } sub ok ($$$) { -- 2.39.5