- 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
=================================================================
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);
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)
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;
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) {
=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) {
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
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
}
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;
}
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;
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
}
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;
}
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;
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);
}
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)
}
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)
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);
=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;
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) \
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;
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);
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; }
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
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;
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++) {
for (img_num = 0; img_num < count; ++img_num) {
i_img *im = imgs[img_num];
- for(y=0;y<im->ysize;y++) for(x=0;x<im->xsize;x++) {
- ld=196608;
- i_gpix(im,x,y,&val);
- currhb=pixbox(&val);
- /* printf("box = %d \n",currhb); */
- for(i=0;i<hb[currhb].cnt;i++) {
- /* printf("comparing: pix (%d,%d,%d) vec (%d,%d,%d)\n",val.channel[0],val.channel[1],val.channel[2],clr[hb[currhb].vec[i]].r,clr[hb[currhb].vec[i]].g,clr[hb[currhb].vec[i]].b); */
-
- cd=eucl_d(&clr[hb[currhb].vec[i]],&val);
- if (cd<ld) {
- ld=cd; /* shortest distance yet */
- bst_idx=hb[currhb].vec[i]; /* index of closest vector yet */
- }
- }
-
- clr[bst_idx].mcount++;
- accerr+=(ld);
- clr[bst_idx].dr+=val.channel[0];
- clr[bst_idx].dg+=val.channel[1];
- clr[bst_idx].db+=val.channel[2];
+ sample_indices = im->channels >= 3 ? NULL : gray_samples;
+ for(y=0;y<im->ysize;y++) {
+ i_gsamp(im, 0, im->xsize, y, line, sample_indices, 3);
+ val = line;
+ for(x=0;x<im->xsize;x++) {
+ ld=196608;
+ /*i_gpix(im,x,y,&val);*/
+ currhb=pixbox_ch(val);
+ /* printf("box = %d \n",currhb); */
+ for(i=0;i<hb[currhb].cnt;i++) {
+ /* printf("comparing: pix (%d,%d,%d) vec (%d,%d,%d)\n",val.channel[0],val.channel[1],val.channel[2],clr[hb[currhb].vec[i]].r,clr[hb[currhb].vec[i]].g,clr[hb[currhb].vec[i]].b); */
+
+ cd=eucl_d_ch(&clr[hb[currhb].vec[i]],val);
+ if (cd<ld) {
+ ld=cd; /* shortest distance yet */
+ bst_idx=hb[currhb].vec[i]; /* index of closest vector yet */
+ }
+ }
+
+ clr[bst_idx].mcount++;
+ accerr+=(ld);
+ clr[bst_idx].dr+=val[0];
+ clr[bst_idx].dg+=val[1];
+ clr[bst_idx].db+=val[2];
+
+ val += 3; /* next 3 samples (next pixel) */
+ }
}
}
- for(i=0;i<cnum;i++) if (clr[i].mcount) { clr[i].dr/=clr[i].mcount; clr[i].dg/=clr[i].mcount; clr[i].db/=clr[i].mcount; }
-
+
+ for(i=0;i<cnum;i++)
+ if (clr[i].mcount) {
+ clr[i].dr/=clr[i].mcount;
+ clr[i].dg/=clr[i].mcount;
+ clr[i].db/=clr[i].mcount;
+ }
+
/* for(i=0;i<cnum;i++) printf("vec(%d)=(%d,%d,%d) dest=(%d,%d,%d) matchcount=%d\n",
- i,clr[i].r,clr[i].g,clr[i].b,clr[i].dr,clr[i].dg,clr[i].db,clr[i].mcount); */
-
+ i,clr[i].r,clr[i].g,clr[i].b,clr[i].dr,clr[i].dg,clr[i].db,clr[i].mcount); */
+
/* printf("total error: %.2f\n",sqrt(accerr)); */
-
+
for(i=0;i<cnum;i++) {
if (clr[i].fixed) continue; /* skip reserved colors */
-
+
if (clr[i].mcount) {
- clr[i].used = 1;
- clr[i].r=clr[i].r*(1-dlt)+dlt*clr[i].dr;
- clr[i].g=clr[i].g*(1-dlt)+dlt*clr[i].dg;
- clr[i].b=clr[i].b*(1-dlt)+dlt*clr[i].db;
+ clr[i].used = 1;
+ clr[i].r=clr[i].r*(1-dlt)+dlt*clr[i].dr;
+ clr[i].g=clr[i].g*(1-dlt)+dlt*clr[i].dg;
+ clr[i].b=clr[i].b*(1-dlt)+dlt*clr[i].db;
} else {
- /* let's try something else */
- clr[i].used = 0;
- clr[i].r=rand();
- clr[i].g=rand();
- clr[i].b=rand();
+ /* let's try something else */
+ clr[i].used = 0;
+ clr[i].r=rand();
+ clr[i].g=rand();
+ clr[i].b=rand();
}
-
+
clr[i].dr=0;
clr[i].dg=0;
clr[i].db=0;
quant->mc_count = cnum;
#endif
- /* don't want to keep this */
- myfree(hb);
- myfree(clr);
+ i_mempool_destroy(&mp);
}
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)
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);*/
/* 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;
+ }
}
}
}
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;
CF_SETUP;
- if (pixdev) {
- k=0;
- for(y=0;y<img->ysize;y++) for(x=0;x<img->xsize;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;y<img->ysize;y++) for(x=0;x<img->xsize;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;y<img->ysize;y++) for(x=0;x<img->xsize;x++) {
+ i_gpix(img,x,y,&val);
+ CF_FIND;
+ out[k++]=bst_idx;
+ }
}
- } else {
- k=0;
- for(y=0;y<img->ysize;y++) for(x=0;x<img->xsize;x++) {
- i_gpix(img,x,y,&val);
- CF_FIND;
- out[k++]=bst_idx;
+ }
+ else {
+ if (pixdev) {
+ k=0;
+ for(y=0;y<img->ysize;y++) for(x=0;x<img->xsize;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;y<img->ysize;y++) for(x=0;x<img->xsize;x++) {
+ i_gpix(img,x,y,&val);
+ val.channel[1] = val.channel[2] = val.channel[0];
+ CF_FIND;
+ out[k++]=bst_idx;
+ }
}
}
CF_CLEANUP;
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;
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++) {
/* process each image */
for (i = 0; i < count; ++i) {
i_img *im = imgs[i];
- for(y=0;y<im->ysize;y++) for(x=0;x<im->xsize;x++) {
- i_gpix(im,x,y,&val);
- prebox[pixbox(&val)].pixcnt++;
+ chans = im->channels >= 3 ? NULL : gray_samples;
+ for(y=0;y<im->ysize;y++) {
+ i_gsamp(im, 0, im->xsize, y, line, chans, 3);
+ val = line;
+ for(x=0;x<im->xsize;x++) {
+ prebox[pixbox_ch(val)].pixcnt++;
+ }
}
}
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
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;
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];
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 */
{
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);
}
+
#!perl -w
use strict;
$|=1;
-print "1..45\n";
+print "1..60\n";
use Imager qw(:all);
sub ok ($$$);
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 ($$$) {