diag methods missing from the method index or are undocumented
[imager.git] / quant.c
CommitLineData
02d1d628
AMH
1/* quant.c - provides general image quantization
2 currently only used by gif.c, but maybe we'll support producing
3 8-bit (or bigger indexed) png files at some point
4*/
92bda632 5#include "imager.h"
50c75381 6#include "imageri.h"
02d1d628 7
59c150a4 8static void makemap_webmap(i_quantize *);
02d1d628 9static void makemap_addi(i_quantize *, i_img **imgs, int count);
97c4effc 10static void makemap_mediancut(i_quantize *, i_img **imgs, int count);
9c106321 11static void makemap_mono(i_quantize *);
02d1d628 12
59c150a4
TC
13static int makemap_palette(i_quantize *, i_img **imgs, int count);
14
02d1d628
AMH
15static
16void
17setcol(i_color *cl,unsigned char r,unsigned char g,unsigned char b,unsigned char a) {
18 cl->rgba.r=r;
19 cl->rgba.g=g;
20 cl->rgba.b=b;
21 cl->rgba.a=a;
22}
23
24
25
26/* make a colour map overwrites mc_existing/mc_count in quant Note
27 that i_makemap will be called once for each image if mc_perimage is
28 set and the format support multiple colour maps per image.
29
30 This means we don't need any special processing at this level to
31 handle multiple colour maps.
32*/
33
92bda632 34/*
5715f7c3 35=item i_quant_makemap(C<quant>, C<imgs>, C<count>)
92bda632
TC
36
37=category Image quantization
38
5715f7c3
TC
39Analyzes the C<count> images in C<imgs> according to the rules in
40C<quant> to build a color map (optimal or not depending on
41C<< quant->make_colors >>).
92bda632
TC
42
43=cut
44*/
45
02d1d628 46void
92bda632 47i_quant_makemap(i_quantize *quant, i_img **imgs, int count) {
97c4effc
TC
48
49 if (quant->translate == pt_giflib) {
50 /* giflib does it's own color table generation */
51 /* previously we used giflib's quantizer, but it didn't handle multiple
52 images, which made it hard to build a global color map
53 We've implemented our own median cut code so we can ignore
54 the giflib version */
55 makemap_mediancut(quant, imgs, count);
02d1d628 56 return;
97c4effc
TC
57 }
58
02d1d628
AMH
59 switch (quant->make_colors & mc_mask) {
60 case mc_none:
61 /* use user's specified map */
62 break;
63 case mc_web_map:
59c150a4 64 makemap_webmap(quant);
02d1d628
AMH
65 break;
66
97c4effc
TC
67 case mc_median_cut:
68 makemap_mediancut(quant, imgs, count);
69 break;
70
9c106321
TC
71 case mc_mono:
72 makemap_mono(quant);
73 break;
74
02d1d628
AMH
75 case mc_addi:
76 default:
77 makemap_addi(quant, imgs, count);
78 break;
79 }
80}
81
02d1d628
AMH
82static void translate_closest(i_quantize *, i_img *, i_palidx *);
83static void translate_errdiff(i_quantize *, i_img *, i_palidx *);
84static void translate_addi(i_quantize *, i_img *, i_palidx *);
85
92bda632 86/*
5715f7c3 87=item i_quant_translate(C<quant>, C<img>)
92bda632
TC
88
89=category Image quantization
90
5715f7c3 91Quantize the image given the palette in C<quant>.
92bda632 92
5715f7c3
TC
93On success returns a pointer to a memory block of C<< img->xsize *
94img->ysize >> C<i_palidx> entries.
92bda632
TC
95
96On failure returns NULL.
02d1d628 97
92bda632
TC
98You should call myfree() on the returned block when you're done with
99it.
100
101This function will fail if the supplied palette contains no colors.
102
103=cut
02d1d628 104*/
92bda632
TC
105i_palidx *
106i_quant_translate(i_quantize *quant, i_img *img) {
2ff8ed30 107 i_palidx *result;
8d14daab 108 size_t bytes;
f771d0ec 109
a73aeb5f 110 mm_log((1, "quant_translate(quant %p, img %p)\n", quant, img));
2ff8ed30 111
1501d9b3
TC
112 /* there must be at least one color in the paletted (though even that
113 isn't very useful */
114 if (quant->mc_count == 0) {
115 i_push_error(0, "no colors available for translation");
116 return NULL;
117 }
118
f771d0ec
TC
119 bytes = img->xsize * img->ysize;
120 if (bytes / img->ysize != img->xsize) {
121 i_push_error(0, "integer overflow calculating memory allocation");
122 return NULL;
123 }
124 result = mymalloc(bytes);
2ff8ed30 125
02d1d628 126 switch (quant->translate) {
02d1d628 127 case pt_closest:
97c4effc 128 case pt_giflib:
02d1d628
AMH
129 translate_closest(quant, img, result);
130 break;
a73aeb5f 131
02d1d628
AMH
132 case pt_errdiff:
133 translate_errdiff(quant, img, result);
134 break;
a73aeb5f 135
02d1d628
AMH
136 case pt_perturb:
137 default:
138 translate_addi(quant, img, result);
139 break;
140 }
a73aeb5f 141
02d1d628
AMH
142 return result;
143}
144
02d1d628
AMH
145static void translate_closest(i_quantize *quant, i_img *img, i_palidx *out) {
146 quant->perturb = 0;
147 translate_addi(quant, img, out);
148}
149
150#define PWR2(x) ((x)*(x))
151
152typedef int (*cmpfunc)(const void*, const void*);
153
154typedef struct {
155 unsigned char r,g,b;
36e67d0b
TC
156 char fixed;
157 char used;
02d1d628
AMH
158 int dr,dg,db;
159 int cdist;
160 int mcount;
161} cvec;
162
163typedef struct {
164 int cnt;
165 int vec[256];
166} hashbox;
167
168typedef struct {
169 int boxnum;
170 int pixcnt;
171 int cand;
172 int pdc;
173} pbox;
174
18accb2a 175static void prescan(i_img **im,int count, int cnum, cvec *clr, i_sample_t *line);
02d1d628
AMH
176static void reorder(pbox prescan[512]);
177static int pboxcmp(const pbox *a,const pbox *b);
178static void boxcenter(int box,cvec *cv);
179static float frandn(void);
180static void boxrand(int box,cvec *cv);
181static void bbox(int box,int *r0,int *r1,int *g0,int *g1,int *b0,int *b1);
182static void cr_hashindex(cvec clr[256],int cnum,hashbox hb[512]);
183static int mindist(int boxnum,cvec *cv);
184static int maxdist(int boxnum,cvec *cv);
185
186/* Some of the simpler functions are kept here to aid the compiler -
187 maybe some of them will be inlined. */
188
189static int
190pixbox(i_color *ic) { return ((ic->channel[0] & 224)<<1)+ ((ic->channel[1]&224)>>2) + ((ic->channel[2] &224) >> 5); }
191
18accb2a
TC
192static int
193pixbox_ch(i_sample_t *chans) { return ((chans[0] & 224)<<1)+ ((chans[1]&224)>>2) + ((chans[2] &224) >> 5); }
194
02d1d628
AMH
195static unsigned char
196g_sat(int in) {
197 if (in>255) { return 255; }
198 else if (in>0) return in;
199 return 0;
200}
201
202static
203float
204frand(void) {
205 return rand()/(RAND_MAX+1.0);
206}
207
a659442a 208#ifdef NOTEF
02d1d628
AMH
209static
210int
211eucl_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]); }
a659442a 212#endif
02d1d628 213
18accb2a
TC
214static
215int
216eucl_d_ch(cvec* cv,i_sample_t *chans) {
217 return PWR2(cv->r - chans[0]) + PWR2(cv->g - chans[1])
218 + PWR2(cv->b - chans[2]);
219}
220
6d068d36
TC
221static int
222ceucl_d(i_color *c1, i_color *c2) {
223return PWR2(c1->channel[0]-c2->channel[0])
224 +PWR2(c1->channel[1]-c2->channel[1])
225 +PWR2(c1->channel[2]-c2->channel[2]);
226}
02d1d628 227
18accb2a
TC
228static const int
229gray_samples[] = { 0, 0, 0 };
230
02d1d628
AMH
231/*
232
233This quantization algorithm and implementation routines are by Arnar
234M. Hrafnkelson. In case any new ideas are here they are mine since
235this was written from scratch.
236
237The algorithm uses local means in the following way:
238
239 For each point in the colormap we find which image points
240 have that point as it's closest point. We calculate the mean
241 of those points and in the next iteration it will be the new
242 entry in the colormap.
243
244In order to speed this process up (i.e. nearest neighbor problem) We
245divied the r,g,b space up in equally large 512 boxes. The boxes are
246numbered from 0 to 511. Their numbering is so that for a given vector
247it is known that it belongs to the box who is formed by concatenating the
2483 most significant bits from each component of the RGB triplet.
249
250For each box we find the list of points from the colormap who might be
251closest to any given point within the box. The exact solution
252involves finding the Voronoi map (or the dual the Delauny
253triangulation) and has many issues including numerical stability.
254
255So we use this approximation:
256
2571. Find which point has the shortest maximum distance to the box.
2582. Find all points that have a shorter minimum distance than that to the box
259
260This is a very simple task and is not computationally heavy if one
261takes into account that the minimum distances from a pixel to a box is
262always found by checking if it's inside the box or is closest to some
263side or a corner. Finding the maximum distance is also either a side
264or a corner.
265
266This approach results 2-3 times more than the actual points needed but
267is still a good gain over the complete space. Usually when one has a
268256 Colorcolor map a search over 30 is often obtained.
269
270A bit of an enhancement to this approach is to keep a seperate list
271for each side of the cube, but this will require even more memory.
272
273 Arnar M. Hrafnkelsson (addi@umich.edu);
274
275*/
276/*
277 Extracted from gifquant.c, removed dependencies on gif_lib,
278 and added support for multiple images.
279 starting from 1nov2000 by TonyC <tony@develop-help.com>.
280
281*/
282
283static void
284makemap_addi(i_quantize *quant, i_img **imgs, int count) {
285 cvec *clr;
8d14daab
TC
286 int cnum, i, bst_idx=0, ld, cd, iter, currhb, img_num;
287 i_img_dim x, y;
18accb2a 288 i_sample_t *val;
02d1d628 289 float dlt, accerr;
9cfd5724 290 hashbox *hb;
18accb2a 291 i_mempool mp;
8d14daab 292 i_img_dim maxwidth = 0;
18accb2a
TC
293 i_sample_t *line;
294 const int *sample_indices;
02d1d628 295
7ac6a2e9
TC
296 mm_log((1, "makemap_addi(quant %p { mc_count=%d, mc_colors=%p }, imgs %p, count %d)\n",
297 quant, quant->mc_count, quant->mc_colors, imgs, count));
59c150a4
TC
298
299 if (makemap_palette(quant, imgs, count))
300 return;
7ac6a2e9 301
18accb2a
TC
302 i_mempool_init(&mp);
303
304 clr = i_mempool_alloc(&mp, sizeof(cvec) * quant->mc_size);
305 hb = i_mempool_alloc(&mp, sizeof(hashbox) * 512);
02d1d628
AMH
306 for (i=0; i < quant->mc_count; ++i) {
307 clr[i].r = quant->mc_colors[i].rgb.r;
308 clr[i].g = quant->mc_colors[i].rgb.g;
309 clr[i].b = quant->mc_colors[i].rgb.b;
36e67d0b
TC
310 clr[i].fixed = 1;
311 clr[i].mcount = 0;
02d1d628
AMH
312 }
313 /* mymalloc doesn't clear memory, so I think we need this */
314 for (; i < quant->mc_size; ++i) {
7ac6a2e9
TC
315 /*clr[i].r = clr[i].g = clr[i].b = 0;*/
316 clr[i].dr = 0;
317 clr[i].dg = 0;
318 clr[i].db = 0;
36e67d0b
TC
319 clr[i].fixed = 0;
320 clr[i].mcount = 0;
02d1d628
AMH
321 }
322 cnum = quant->mc_size;
323 dlt = 1;
324
18accb2a
TC
325 for (img_num = 0; img_num < count; ++img_num) {
326 if (imgs[img_num]->xsize > maxwidth)
327 maxwidth = imgs[img_num]->xsize;
328 }
329 line = i_mempool_alloc(&mp, 3 * maxwidth * sizeof(*line));
330
331 prescan(imgs, count, cnum, clr, line);
02d1d628
AMH
332 cr_hashindex(clr, cnum, hb);
333
334 for(iter=0;iter<3;iter++) {
335 accerr=0.0;
336
36e67d0b
TC
337 for (img_num = 0; img_num < count; ++img_num) {
338 i_img *im = imgs[img_num];
18accb2a
TC
339 sample_indices = im->channels >= 3 ? NULL : gray_samples;
340 for(y=0;y<im->ysize;y++) {
341 i_gsamp(im, 0, im->xsize, y, line, sample_indices, 3);
342 val = line;
343 for(x=0;x<im->xsize;x++) {
344 ld=196608;
345 /*i_gpix(im,x,y,&val);*/
346 currhb=pixbox_ch(val);
347 /* printf("box = %d \n",currhb); */
348 for(i=0;i<hb[currhb].cnt;i++) {
349 /* 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); */
350
351 cd=eucl_d_ch(&clr[hb[currhb].vec[i]],val);
352 if (cd<ld) {
353 ld=cd; /* shortest distance yet */
354 bst_idx=hb[currhb].vec[i]; /* index of closest vector yet */
355 }
356 }
357
358 clr[bst_idx].mcount++;
359 accerr+=(ld);
360 clr[bst_idx].dr+=val[0];
361 clr[bst_idx].dg+=val[1];
362 clr[bst_idx].db+=val[2];
363
364 val += 3; /* next 3 samples (next pixel) */
365 }
02d1d628
AMH
366 }
367 }
18accb2a
TC
368
369 for(i=0;i<cnum;i++)
370 if (clr[i].mcount) {
371 clr[i].dr/=clr[i].mcount;
372 clr[i].dg/=clr[i].mcount;
373 clr[i].db/=clr[i].mcount;
374 }
375
02d1d628 376 /* for(i=0;i<cnum;i++) printf("vec(%d)=(%d,%d,%d) dest=(%d,%d,%d) matchcount=%d\n",
18accb2a
TC
377 i,clr[i].r,clr[i].g,clr[i].b,clr[i].dr,clr[i].dg,clr[i].db,clr[i].mcount); */
378
02d1d628 379 /* printf("total error: %.2f\n",sqrt(accerr)); */
18accb2a 380
02d1d628 381 for(i=0;i<cnum;i++) {
36e67d0b 382 if (clr[i].fixed) continue; /* skip reserved colors */
18accb2a 383
02d1d628 384 if (clr[i].mcount) {
18accb2a
TC
385 clr[i].used = 1;
386 clr[i].r=clr[i].r*(1-dlt)+dlt*clr[i].dr;
387 clr[i].g=clr[i].g*(1-dlt)+dlt*clr[i].dg;
388 clr[i].b=clr[i].b*(1-dlt)+dlt*clr[i].db;
02d1d628 389 } else {
18accb2a
TC
390 /* let's try something else */
391 clr[i].used = 0;
392 clr[i].r=rand();
393 clr[i].g=rand();
394 clr[i].b=rand();
02d1d628 395 }
18accb2a 396
02d1d628
AMH
397 clr[i].dr=0;
398 clr[i].dg=0;
399 clr[i].db=0;
400 clr[i].mcount=0;
401 }
402 cr_hashindex(clr,cnum,hb);
403 }
404
405
406#ifdef NOTEF
407 for(i=0;i<cnum;i++) {
408 cd=eucl_d(&clr[i],&val);
409 if (cd<ld) {
410 ld=cd;
411 bst_idx=i;
412 }
413 }
414#endif
415
36e67d0b
TC
416 /* if defined, we only include colours with an mcount or that were
417 supplied in the fixed palette, giving us a smaller output palette */
418#define ONLY_USE_USED
419#ifdef ONLY_USE_USED
420 /* transfer the colors back */
421 quant->mc_count = 0;
422 for (i = 0; i < cnum; ++i) {
423 if (clr[i].fixed || clr[i].used) {
424 /*printf("Adding %d (%d,%d,%d)\n", i, clr[i].r, clr[i].g, clr[i].b);*/
425 quant->mc_colors[quant->mc_count].rgb.r = clr[i].r;
426 quant->mc_colors[quant->mc_count].rgb.g = clr[i].g;
427 quant->mc_colors[quant->mc_count].rgb.b = clr[i].b;
428 ++quant->mc_count;
429 }
430 }
431#else
02d1d628
AMH
432 /* transfer the colors back */
433 for (i = 0; i < cnum; ++i) {
434 quant->mc_colors[i].rgb.r = clr[i].r;
435 quant->mc_colors[i].rgb.g = clr[i].g;
436 quant->mc_colors[i].rgb.b = clr[i].b;
437 }
438 quant->mc_count = cnum;
36e67d0b 439#endif
02d1d628 440
7ac6a2e9
TC
441#if 0
442 mm_log((1, "makemap_addi returns - quant.mc_count = %d\n", quant->mc_count));
443 for (i = 0; i < quant->mc_count; ++i)
444 mm_log((5, " map entry %d: (%d, %d, %d)\n", i, clr[i].r, clr[i].g, clr[i].b));
445#endif
446
18accb2a 447 i_mempool_destroy(&mp);
59c150a4
TC
448
449 mm_log((1, "makemap_addi() - %d colors\n", quant->mc_count));
02d1d628
AMH
450}
451
97c4effc
TC
452typedef struct {
453 i_sample_t rgb[3];
454 int count;
455} quant_color_entry;
456
457#define MEDIAN_CUT_COLORS 32768
458
459#define MED_CUT_INDEX(c) ((((c).rgb.r & 0xF8) << 7) | \
460 (((c).rgb.g & 0xF8) << 2) | (((c).rgb.b & 0xF8) >> 3))
461
18accb2a
TC
462#define MED_CUT_GRAY_INDEX(c) ((((c).rgb.r & 0xF8) << 7) | \
463 (((c).rgb.r & 0xF8) << 2) | (((c).rgb.r & 0xF8) >> 3))
464
97c4effc
TC
465/* scale these to cover the whole range */
466#define MED_CUT_RED(index) ((((index) & 0x7C00) >> 10) * 255 / 31)
467#define MED_CUT_GREEN(index) ((((index) & 0x3E0) >> 5) * 255 / 31)
468#define MED_CUT_BLUE(index) (((index) & 0x1F) * 255 / 31)
469
470typedef struct {
471 i_sample_t min[3]; /* minimum for each channel */
472 i_sample_t max[3]; /* maximum for each channel */
473 i_sample_t width[3]; /* width for each channel */
474 int start, size; /* beginning and size of the partition */
8d14daab 475 i_img_dim pixels; /* number of pixels represented by this partition */
97c4effc
TC
476} medcut_partition;
477
478/*
479=item calc_part(part, colors)
480
481Calculates the new color limits for the given partition.
482
483Giflib assumes that the limits for the non-split channels stay the
484same, but this strikes me as incorrect, especially if the colors tend
485to be color ramps.
486
487Of course this could be optimized by not recalculating the channel we
488just sorted on, but it's not worth the effort right now.
489
490=cut
491*/
492static void calc_part(medcut_partition *part, quant_color_entry *colors) {
493 int i, ch;
494
495 for (ch = 0; ch < 3; ++ch) {
496 part->min[ch] = 255;
497 part->max[ch] = 0;
498 }
499 for (i = part->start; i < part->start + part->size; ++i) {
500 for (ch = 0; ch < 3; ++ch) {
501 if (part->min[ch] > colors[i].rgb[ch])
502 part->min[ch] = colors[i].rgb[ch];
503 if (part->max[ch] < colors[i].rgb[ch])
504 part->max[ch] = colors[i].rgb[ch];
505 }
506 }
507 for (ch = 0; ch < 3; ++ch) {
508 part->width[ch] = part->max[ch] - part->min[ch];
509 }
510}
511
512/* simple functions to sort by each channel - we could use a global, but
513 that would be bad */
514
515static int
516color_sort_red(void const *left, void const *right) {
517 return ((quant_color_entry *)left)->rgb[0] - ((quant_color_entry *)right)->rgb[0];
518}
519
520static int
521color_sort_green(void const *left, void const *right) {
522 return ((quant_color_entry *)left)->rgb[1] - ((quant_color_entry *)right)->rgb[1];
523}
524
525static int
526color_sort_blue(void const *left, void const *right) {
527 return ((quant_color_entry *)left)->rgb[2] - ((quant_color_entry *)right)->rgb[2];
528}
529
530static int (*sorters[])(void const *, void const *) =
531{
532 color_sort_red,
533 color_sort_green,
534 color_sort_blue,
535};
536
537static void
538makemap_mediancut(i_quantize *quant, i_img **imgs, int count) {
539 quant_color_entry *colors;
540 i_mempool mp;
8d14daab
TC
541 int imgn, i, ch;
542 i_img_dim x, y, max_width;
97c4effc
TC
543 i_color *line;
544 int color_count;
8d14daab 545 i_img_dim total_pixels;
97c4effc
TC
546 medcut_partition *parts;
547 int part_num;
548 int in, out;
18accb2a
TC
549 /* number of channels we search for the best channel to partition
550 this isn't terribly efficient, but it should work */
551 int chan_count;
97c4effc 552
59c150a4
TC
553 mm_log((1, "makemap_mediancut(quant %p { mc_count=%d, mc_colors=%p }, imgs %p, count %d)\n",
554 quant, quant->mc_count, quant->mc_colors, imgs, count));
555
556 if (makemap_palette(quant, imgs, count))
557 return;
97c4effc
TC
558
559 i_mempool_init(&mp);
560
561 colors = i_mempool_alloc(&mp, sizeof(*colors) * MEDIAN_CUT_COLORS);
562 for (i = 0; i < MEDIAN_CUT_COLORS; ++i) {
563 colors[i].rgb[0] = MED_CUT_RED(i);
564 colors[i].rgb[1] = MED_CUT_GREEN(i);
565 colors[i].rgb[2] = MED_CUT_BLUE(i);
566 colors[i].count = 0;
567 }
568
569 max_width = -1;
570 for (imgn = 0; imgn < count; ++imgn) {
571 if (imgs[imgn]->xsize > max_width)
572 max_width = imgs[imgn]->xsize;
573 }
574 line = i_mempool_alloc(&mp, sizeof(i_color) * max_width);
575
576 /* build the stats */
577 total_pixels = 0;
18accb2a 578 chan_count = 1; /* assume we just have grayscale */
97c4effc
TC
579 for (imgn = 0; imgn < count; ++imgn) {
580 total_pixels += imgs[imgn]->xsize * imgs[imgn]->ysize;
581 for (y = 0; y < imgs[imgn]->ysize; ++y) {
582 i_glin(imgs[imgn], 0, imgs[imgn]->xsize, y, line);
18accb2a
TC
583 if (imgs[imgn]->channels > 2) {
584 chan_count = 3;
585 for (x = 0; x < imgs[imgn]->xsize; ++x) {
586 ++colors[MED_CUT_INDEX(line[x])].count;
587 }
588 }
589 else {
590 /* a gray-scale image, just use the first channel */
591 for (x = 0; x < imgs[imgn]->xsize; ++x) {
592 ++colors[MED_CUT_GRAY_INDEX(line[x])].count;
593 }
97c4effc
TC
594 }
595 }
596 }
597
598 /* eliminate the empty colors */
599 out = 0;
600 for (in = 0; in < MEDIAN_CUT_COLORS; ++in) {
601 if (colors[in].count) {
602 colors[out++] = colors[in];
603 }
604 }
605 /*printf("out %d\n", out);
606
607 for (i = 0; i < out; ++i) {
608 if (colors[i].count) {
609 printf("%d: (%d,%d,%d) -> %d\n", i, colors[i].rgb[0], colors[i].rgb[1],
610 colors[i].rgb[2], colors[i].count);
611 }
612 }*/
613
614 if (out < quant->mc_size) {
615 /* just copy them into the color table */
616 for (i = 0; i < out; ++i) {
617 for (ch = 0; ch < 3; ++ch) {
618 quant->mc_colors[i].channel[ch] = colors[i].rgb[ch];
619 }
620 }
621 quant->mc_count = out;
622 }
623 else {
624 /* build the starting partition */
625 parts = i_mempool_alloc(&mp, sizeof(*parts) * quant->mc_size);
626 parts[0].start = 0;
627 parts[0].size = out;
628 parts[0].pixels = total_pixels;
629 calc_part(parts, colors);
630 color_count = 1;
631
632 while (color_count < quant->mc_size) {
b07bc64b
TC
633 /* initialized to avoid compiler warnings */
634 int max_index = 0, max_ch = 0; /* index/channel with biggest spread */
97c4effc
TC
635 int max_size;
636 medcut_partition *workpart;
637 int cum_total;
638 int half;
639
640 /* find the partition with the most biggest span with more than
641 one color */
642 max_size = -1;
643 for (i = 0; i < color_count; ++i) {
18accb2a 644 for (ch = 0; ch < chan_count; ++ch) {
97c4effc
TC
645 if (parts[i].width[ch] > max_size
646 && parts[i].size > 1) {
647 max_index = i;
648 max_ch = ch;
649 max_size = parts[i].width[ch];
650 }
651 }
652 }
653
654 /* nothing else we can split */
655 if (max_size == -1)
656 break;
657
658 workpart = parts+max_index;
659 /*printf("splitting partition %d (pixels %ld, start %d, size %d)\n", max_index, workpart->pixels, workpart->start, workpart->size);*/
660 qsort(colors + workpart->start, workpart->size, sizeof(*colors),
661 sorters[max_ch]);
662
663 /* find the median or something like it we need to make sure both
664 sides of the split have at least one color in them, so we don't
665 test at the first or last entry */
666 i = workpart->start;
667 cum_total = colors[i].count;
668 ++i;
669 half = workpart->pixels / 2;
670 while (i < workpart->start + workpart->size - 1
671 && cum_total < half) {
672 cum_total += colors[i++].count;
673 }
674 /*printf("Split at %d to make %d (half %ld, cumtotal %ld)\n", i, color_count, half, cum_total);*/
675
676 /* found the spot to split */
677 parts[color_count].start = i;
678 parts[color_count].size = workpart->start + workpart->size - i;
679 workpart->size = i - workpart->start;
680 parts[color_count].pixels = workpart->pixels - cum_total;
681 workpart->pixels = cum_total;
682
683 /* recalculate the limits */
684 calc_part(workpart, colors);
685 calc_part(parts+color_count, colors);
686 ++color_count;
687 }
688
689 /* fill in the color table - since we could still have partitions
690 that have more than one color, we need to average the colors */
691 for (part_num = 0; part_num < color_count; ++part_num) {
692 long sums[3];
693 medcut_partition *workpart;
694
695 workpart = parts+part_num;
696 for (ch = 0; ch < 3; ++ch)
697 sums[ch] = 0;
698
699 for (i = workpart->start; i < workpart->start + workpart->size; ++i) {
700 for (ch = 0; ch < 3; ++ch) {
701 sums[ch] += colors[i].rgb[ch] * colors[i].count;
702 }
703 }
704 for (ch = 0; ch < 3; ++ch) {
705 quant->mc_colors[part_num].channel[ch] = sums[ch] / workpart->pixels;
706 }
707 }
708 quant->mc_count = color_count;
709 }
710 /*printf("out %d colors\n", quant->mc_count);*/
711 i_mempool_destroy(&mp);
59c150a4
TC
712
713 mm_log((1, "makemap_mediancut() - %d colors\n", quant->mc_count));
97c4effc
TC
714}
715
9c106321
TC
716static void
717makemap_mono(i_quantize *quant) {
718 quant->mc_colors[0].rgba.r = 0;
719 quant->mc_colors[0].rgba.g = 0;
720 quant->mc_colors[0].rgba.b = 0;
721 quant->mc_colors[0].rgba.a = 255;
722 quant->mc_colors[1].rgba.r = 255;
723 quant->mc_colors[1].rgba.g = 255;
724 quant->mc_colors[1].rgba.b = 255;
725 quant->mc_colors[1].rgba.a = 255;
726 quant->mc_count = 2;
727}
728
59c150a4
TC
729static void
730makemap_webmap(i_quantize *quant) {
731 int r, g, b;
732
733 int i = 0;
734 for (r = 0; r < 256; r+=0x33)
735 for (g = 0; g < 256; g+=0x33)
736 for (b = 0; b < 256; b += 0x33)
737 setcol(quant->mc_colors+i++, r, g, b, 255);
738 quant->mc_count = i;
739}
740
741static int
742in_palette(i_color *c, i_quantize *quant, int size) {
743 int i;
744
745 for (i = 0; i < size; ++i) {
746 if (c->channel[0] == quant->mc_colors[i].channel[0]
747 && c->channel[1] == quant->mc_colors[i].channel[1]
748 && c->channel[2] == quant->mc_colors[i].channel[2]) {
749 return i;
750 }
751 }
752
753 return -1;
754}
755
756/*
757=item makemap_palette(quant, imgs, count)
758
759Tests if all the given images are paletted and have a common palette,
760if they do it builds that palette.
761
762A possible improvement might be to eliminate unused colors in the
763images palettes.
764
765=cut
766*/
767
768static int
769makemap_palette(i_quantize *quant, i_img **imgs, int count) {
770 int size = quant->mc_count;
771 int i;
772 int imgn;
773 char used[256];
774 int col_count;
775
776 mm_log((1, "makemap_palette(quant %p { mc_count=%d, mc_colors=%p }, imgs %p, count %d)\n",
777 quant, quant->mc_count, quant->mc_colors, imgs, count));
778 /* we try to build a common palette here, if we can manage that, then
779 that's the palette we use */
780 for (imgn = 0; imgn < count; ++imgn) {
781 int eliminate_unused;
782 if (imgs[imgn]->type != i_palette_type) {
783 mm_log((1, "makemap_palette() -> 0 (non-palette image)\n"));
784 return 0;
785 }
786
787 if (!i_tags_get_int(&imgs[imgn]->tags, "gif_eliminate_unused", 0,
788 &eliminate_unused)) {
789 eliminate_unused = 1;
790 }
791
792 if (eliminate_unused) {
793 i_palidx *line = mymalloc(sizeof(i_palidx) * imgs[imgn]->xsize);
8d14daab 794 i_img_dim x, y;
59c150a4
TC
795 memset(used, 0, sizeof(used));
796
797 for (y = 0; y < imgs[imgn]->ysize; ++y) {
798 i_gpal(imgs[imgn], 0, imgs[imgn]->xsize, y, line);
799 for (x = 0; x < imgs[imgn]->xsize; ++x)
800 used[line[x]] = 1;
801 }
802
803 myfree(line);
804 }
805 else {
806 /* assume all are in use */
807 memset(used, 1, sizeof(used));
808 }
809
810 col_count = i_colorcount(imgs[imgn]);
811 for (i = 0; i < col_count; ++i) {
812 i_color c;
813
814 i_getcolors(imgs[imgn], i, &c, 1);
815 if (used[i]) {
816 if (in_palette(&c, quant, size) < 0) {
817 if (size < quant->mc_size) {
818 quant->mc_colors[size++] = c;
819 }
820 else {
821 mm_log((1, "makemap_palette() -> 0 (too many colors)\n"));
822 return 0;
823 }
824 }
825 }
826 }
827 }
828
829 mm_log((1, "makemap_palette() -> 1 (%d total colors)\n", size));
830 quant->mc_count = size;
831
832 return 1;
833}
834
02d1d628
AMH
835#define pboxjump 32
836
837/* Define one of the following 4 symbols to choose a colour search method
838 The idea is to try these out, including benchmarking, to see which
839 is fastest in a good spread of circumstances.
840 I'd expect IM_CFLINSEARCH to be fastest for very small palettes, and
841 IM_CFHASHBOX for large images with large palettes.
842
843 Some other possibilities include:
844 - search over entries sorted by luminance
845
846 Initially I was planning on testing using the macros and then
847 integrating the code directly into each function, but this means if
848 we find a bug at a late stage we will need to update N copies of
849 the same code. Also, keeping the code in the macros means that the
850 code in the translation functions is much more to the point,
851 there's no distracting colour search code to remove attention from
852 what makes _this_ translation function different. It may be
853 advisable to move the setup code into functions at some point, but
854 it should be possible to do this fairly transparently.
855
856 If IM_CF_COPTS is defined then CFLAGS must have an appropriate
857 definition.
858
859 Each option needs to define 4 macros:
860 CF_VARS - variables to define in the function
861 CF_SETUP - code to setup for the colour search, eg. allocating and
862 initializing lookup tables
863 CF_FIND - code that looks for the color in val and puts the best
864 matching index in bst_idx
865 CF_CLEANUP - code to clean up, eg. releasing memory
866*/
867#ifndef IM_CF_COPTS
868/*#define IM_CFLINSEARCH*/
869#define IM_CFHASHBOX
870/*#define IM_CFSORTCHAN*/
871/*#define IM_CFRAND2DIST*/
872#endif
873
6d068d36
TC
874/* return true if the color map contains only grays */
875static int
876is_gray_map(const i_quantize *quant) {
877 int i;
878
879 for (i = 0; i < quant->mc_count; ++i) {
880 if (quant->mc_colors[i].rgb.r != quant->mc_colors[i].rgb.g
881 || quant->mc_colors[i].rgb.r != quant->mc_colors[i].rgb.b) {
882 mm_log((1, " not a gray map\n"));
883 return 0;
884 }
885 }
886
887 mm_log((1, " is a gray map\n"));
888 return 1;
889}
890
02d1d628
AMH
891#ifdef IM_CFHASHBOX
892
893/* The original version I wrote for this used the sort.
894 If this is defined then we use a sort to extract the indices for
895 the hashbox */
896#define HB_SORT
897
898/* assume i is available */
9cfd5724 899#define CF_VARS hashbox *hb = mymalloc(sizeof(hashbox) * 512); \
02d1d628
AMH
900 int currhb; \
901 long ld, cd
902
903#ifdef HB_SORT
904
905static long *gdists; /* qsort is annoying */
906/* int might be smaller than long, so we need to do a real compare
907 rather than a subtraction*/
908static int distcomp(void const *a, void const *b) {
909 long ra = gdists[*(int const *)a];
910 long rb = gdists[*(int const *)b];
911 if (ra < rb)
912 return -1;
913 else if (ra > rb)
914 return 1;
915 else
916 return 0;
917}
918
919#endif
920
921/* for each hashbox build a list of colours that are in the hb or is closer
922 than other colours
923 This is pretty involved. The original gifquant generated the hashbox
924 as part of it's normal processing, but since the map generation is now
925 separated from the translation we need to do this on the spot.
926 Any optimizations, even if they don't produce perfect results would be
927 welcome.
928 */
929static void hbsetup(i_quantize *quant, hashbox *hb) {
a659442a 930 long *dists, mind, maxd;
02d1d628
AMH
931 int cr, cb, cg, hbnum, i;
932 i_color cenc;
933#ifdef HB_SORT
934 int *indices = mymalloc(quant->mc_count * sizeof(int));
935#endif
936
937 dists = mymalloc(quant->mc_count * sizeof(long));
938 for (cr = 0; cr < 8; ++cr) {
939 for (cg = 0; cg < 8; ++cg) {
940 for (cb = 0; cb < 8; ++cb) {
941 /* centre of the hashbox */
942 cenc.channel[0] = cr*pboxjump+pboxjump/2;
943 cenc.channel[1] = cg*pboxjump+pboxjump/2;
944 cenc.channel[2] = cb*pboxjump+pboxjump/2;
945 hbnum = pixbox(&cenc);
946 hb[hbnum].cnt = 0;
947 /* order indices in the order of distance from the hashbox */
948 for (i = 0; i < quant->mc_count; ++i) {
949#ifdef HB_SORT
950 indices[i] = i;
951#endif
952 dists[i] = ceucl_d(&cenc, quant->mc_colors+i);
953 }
954#ifdef HB_SORT
955 /* it should be possible to do this without a sort
956 but so far I'm too lazy */
957 gdists = dists;
958 qsort(indices, quant->mc_count, sizeof(int), distcomp);
959 /* any colors that can match are within mind+diagonal size of
960 a hashbox */
961 mind = dists[indices[0]];
962 i = 0;
963 maxd = (sqrt(mind)+pboxjump)*(sqrt(mind)+pboxjump);
964 while (i < quant->mc_count && dists[indices[i]] < maxd) {
965 hb[hbnum].vec[hb[hbnum].cnt++] = indices[i++];
966 }
967#else
968 /* work out the minimum */
969 mind = 256*256*3;
970 for (i = 0; i < quant->mc_count; ++i) {
971 if (dists[i] < mind) mind = dists[i];
972 }
973 /* transfer any colours that might be closest to a colour in
974 this hashbox */
975 maxd = (sqrt(mind)+pboxjump)*(sqrt(mind)+pboxjump);
976 for (i = 0; i < quant->mc_count; ++i) {
977 if (dists[i] < maxd)
978 hb[hbnum].vec[hb[hbnum].cnt++] = i;
979 }
980#endif
981 }
982 }
862b614c 983 }
02d1d628
AMH
984#ifdef HB_SORT
985 myfree(indices);
986#endif
987 myfree(dists) ;
988}
989#define CF_SETUP hbsetup(quant, hb)
990
991#define CF_FIND \
992 currhb = pixbox(&val); \
993 ld = 196608; \
994 for (i = 0; i < hb[currhb].cnt; ++i) { \
995 cd = ceucl_d(quant->mc_colors+hb[currhb].vec[i], &val); \
996 if (cd < ld) { ld = cd; bst_idx = hb[currhb].vec[i]; } \
997 }
998
9cfd5724 999#define CF_CLEANUP myfree(hb)
02d1d628
AMH
1000
1001#endif
1002
1003#ifdef IM_CFLINSEARCH
1004/* as simple as it gets */
1005#define CF_VARS long ld, cd
1006#define CF_SETUP /* none needed */
1007#define CF_FIND \
1008 ld = 196608; \
1009 for (i = 0; i < quant->mc_count; ++i) { \
1010 cd = ceucl_d(quant->mc_colors+i, &val); \
1011 if (cd < ld) { ld = cd; bst_idx = i; } \
1012 }
1013#define CF_CLEANUP
1014#endif
1015
1016#ifdef IM_CFSORTCHAN
1017static int gsortchan;
1018static i_quantize *gquant;
1019static int chansort(void const *a, void const *b) {
1020 return gquant->mc_colors[*(int const *)a].channel[gsortchan] -
1021 gquant->mc_colors[*(int const *)b].channel[gsortchan];
1022}
1023#define CF_VARS int *indices, sortchan, diff; \
1024 long ld, cd; \
1025 int vindex[256] /* where to find value i of chan */
1026
1027static void chansetup(i_img *img, i_quantize *quant, int *csortchan,
1028 int *vindex, int **cindices) {
1029 int *indices, sortchan, chan, i, chval;
1030 int chanmins[MAXCHANNELS], chanmaxs[MAXCHANNELS], maxrange;
1031
1032 /* find the channel with the maximum range */
1033 /* the maximum stddev would probably be better */
1034 for (chan = 0; chan < img->channels; ++chan) {
1035 chanmins[chan] = 256; chanmaxs[chan] = 0;
1036 for (i = 0; i < quant->mc_count; ++i) {
1037 if (quant->mc_colors[i].channel[chan] < chanmins[chan])
1038 chanmins[chan] = quant->mc_colors[i].channel[chan];
1039 if (quant->mc_colors[i].channel[chan] > chanmaxs[chan])
1040 chanmaxs[chan] = quant->mc_colors[i].channel[chan];
1041 }
1042 }
1043 maxrange = -1;
1044 for (chan = 0; chan < img->channels; ++chan) {
1045 if (chanmaxs[chan]-chanmins[chan] > maxrange) {
1046 maxrange = chanmaxs[chan]-chanmins[chan];
1047 sortchan = chan;
1048 }
1049 }
1050 indices = mymalloc(quant->mc_count * sizeof(int)) ;
1051 for (i = 0; i < quant->mc_count; ++i) {
1052 indices[i] = i;
1053 }
1054 gsortchan = sortchan;
1055 gquant = quant;
1056 qsort(indices, quant->mc_count, sizeof(int), chansort) ;
1057 /* now a lookup table to find entries faster */
1058 for (chval=0, i=0; i < quant->mc_count; ++i) {
1059 while (chval < 256 &&
1060 chval < quant->mc_colors[indices[i]].channel[sortchan]) {
1061 vindex[chval++] = i;
1062 }
1063 }
1064 while (chval < 256) {
1065 vindex[chval++] = quant->mc_count-1;
1066 }
1067 *csortchan = sortchan;
1068 *cindices = indices;
1069}
1070
1071#define CF_SETUP \
1072 chansetup(img, quant, &sortchan, vindex, &indices)
1073
1074int chanfind(i_color val, i_quantize *quant, int *indices, int *vindex,
1075 int sortchan) {
1076 int i, bst_idx, diff, maxdiff;
1077 long ld, cd;
1078
1079 i = vindex[val.channel[sortchan]];
1080 bst_idx = indices[i];
1081 ld = 196608;
1082 diff = 0;
1083 maxdiff = quant->mc_count;
1084 while (diff < maxdiff) {
1085 if (i+diff < quant->mc_count) {
1086 cd = ceucl_d(&val, quant->mc_colors+indices[i+diff]);
1087 if (cd < ld) {
1088 bst_idx = indices[i+diff];
1089 ld = cd;
1090 maxdiff = sqrt(ld);
1091 }
1092 }
1093 if (i-diff >= 0) {
1094 cd = ceucl_d(&val, quant->mc_colors+indices[i-diff]);
1095 if (cd < ld) {
1096 bst_idx = indices[i-diff];
1097 ld = cd;
1098 maxdiff = sqrt(ld);
1099 }
1100 }
1101 ++diff;
1102 }
1103
1104 return bst_idx;
1105}
1106
1107#define CF_FIND \
1108 bst_idx = chanfind(val, quant, indices, vindex, sortchan)
1109
1110
1111#define CF_CLEANUP myfree(indices)
1112
1113#endif
1114
1115#ifdef IM_CFRAND2DIST
1116
1117/* This is based on a method described by Addi in the #imager channel
1118 on the 28/2/2001. I was about 1am Sydney time at the time, so I
1119 wasn't at my most cogent. Well, that's my excuse :)
1120
1121<TonyC> what I have at the moment is: hashboxes, with optimum hash box
1122filling; simple linear search; and a lookup in the widest channel
1123(currently the channel with the maximum range)
1124<Addi> There is one more way that might be simple to implement.
1125<Addi> You want to hear?
1126<TonyC> what's that?
1127<purl> somebody said that was not true
1128<Addi> For each of the colors in the palette start by creating a
1129sorted list of the form:
1130<Addi> [distance, color]
1131<Addi> Where they are sorted by distance.
1132<TonyC> distance to where?
1133<Addi> Where the elements in the lists are the distances and colors of
1134the other colors in the palette
1135<TonyC> ok
1136<Addi> So if you are at color 0
1137<Addi> ok - now to search for the closest color when you are creating
1138the final image is done like this:
1139<Addi> a) pick a random color from the palette
1140<Addi> b) calculate the distance to it
1141<Addi> c) only check the vectors that are within double the distance
1142in the list of the color you picked from the palette.
1143<Addi> Does that seem logical?
1144<Addi> Lets imagine that we only have grayscale to make an example:
1145<Addi> Our palette has 1 4 10 20 as colors.
1146<Addi> And we want to quantize the color 11
1147<Addi> lets say we picked 10 randomly
1148<Addi> the double distance is 2
1149<Addi> since abs(10-11)*2 is 2
1150<Addi> And the list at vector 10 is this:
1151<Addi> [0, 10], [6 4], [9, 1], [10, 20]
1152<Addi> so we look at the first one (but not the second one since 6 is
1153at a greater distance than 2.
1154<Addi> Any of that make sense?
1155<TonyC> yes, though are you suggesting another random jump to one of
1156the colours with the possible choices? or an exhaustive search?
1157<Addi> TonyC: It's possible to come up with a recursive/iterative
1158enhancement but this is the 'basic' version.
1159<Addi> Which would do an iterative search.
1160<Addi> You can come up with conditions where it pays to switch to a new one.
1161<Addi> And the 'random' start can be switched over to a small tree.
1162<Addi> So you would have a little index at the start.
1163<Addi> to get you into the general direction
1164<Addi> Perhaps just an 8 split.
1165<Addi> that is - split each dimension in half.
1166<TonyC> yep
1167<TonyC> I get the idea
1168<Addi> But this would seem to be a good approach in our case since we
1169usually have few codevectors.
1170<Addi> So we only need 256*256 entries in a table.
1171<Addi> We could even only index some of them that were deemed as good
1172candidates.
1173<TonyC> I was considering adding paletted output support for PNG and
1174TIFF at some point, which support 16-bit palettes
1175<Addi> ohh.
1176<Addi> 'darn' ;)
1177
1178
1179*/
1180
1181
1182typedef struct i_dists {
1183 int index;
1184 long dist;
1185} i_dists;
1186
1187#define CF_VARS \
1188 i_dists *dists;
1189
1190static int dists_sort(void const *a, void const *b) {
1191 return ((i_dists *)a)->dist - ((i_dists *)b)->dist;
1192}
1193
1194static void rand2dist_setup(i_quantize *quant, i_dists **cdists) {
1195 i_dists *dists =
1196 mymalloc(sizeof(i_dists)*quant->mc_count*quant->mc_count);
1197 int i, j;
1198 long cd;
1199 for (i = 0; i < quant->mc_count; ++i) {
1200 i_dists *ldists = dists + quant->mc_count * i;
1201 i_color val = quant->mc_colors[i];
1202 for (j = 0; j < quant->mc_count; ++j) {
1203 ldists[j].index = j;
1204 ldists[j].dist = ceucl_d(&val, quant->mc_colors+j);
1205 }
1206 qsort(ldists, quant->mc_count, sizeof(i_dists), dists_sort);
1207 }
1208 *cdists = dists;
1209}
1210
1211#define CF_SETUP \
1212 bst_idx = rand() % quant->mc_count; \
1213 rand2dist_setup(quant, &dists)
1214
1215static int rand2dist_find(i_color val, i_quantize *quant, i_dists *dists, int index) {
1216 i_dists *cdists;
1217 long cd, ld;
1218 long maxld;
1219 int i;
1220 int bst_idx;
1221
1222 cdists = dists + index * quant->mc_count;
1223 ld = 3 * 256 * 256;
1224 maxld = 8 * ceucl_d(&val, quant->mc_colors+index);
1225 for (i = 0; i < quant->mc_count && cdists[i].dist <= maxld; ++i) {
1226 cd = ceucl_d(&val, quant->mc_colors+cdists[i].index);
1227 if (cd < ld) {
1228 bst_idx = cdists[i].index;
1229 ld = cd;
1230 }
1231 }
1232 return bst_idx;
1233}
1234
1235#define CF_FIND bst_idx = rand2dist_find(val, quant, dists, bst_idx)
1236
1237#define CF_CLEANUP myfree(dists)
1238
1239
1240#endif
1241
1242static void translate_addi(i_quantize *quant, i_img *img, i_palidx *out) {
8d14daab
TC
1243 i_img_dim x, y, k;
1244 int i, bst_idx = 0;
02d1d628
AMH
1245 i_color val;
1246 int pixdev = quant->perturb;
1247 CF_VARS;
1248
1249 CF_SETUP;
1250
18accb2a
TC
1251 if (img->channels >= 3) {
1252 if (pixdev) {
1253 k=0;
1254 for(y=0;y<img->ysize;y++) for(x=0;x<img->xsize;x++) {
1255 i_gpix(img,x,y,&val);
1256 val.channel[0]=g_sat(val.channel[0]+(int)(pixdev*frandn()));
1257 val.channel[1]=g_sat(val.channel[1]+(int)(pixdev*frandn()));
1258 val.channel[2]=g_sat(val.channel[2]+(int)(pixdev*frandn()));
1259 CF_FIND;
1260 out[k++]=bst_idx;
1261 }
1262 } else {
1263 k=0;
1264 for(y=0;y<img->ysize;y++) for(x=0;x<img->xsize;x++) {
1265 i_gpix(img,x,y,&val);
1266 CF_FIND;
1267 out[k++]=bst_idx;
1268 }
02d1d628 1269 }
18accb2a
TC
1270 }
1271 else {
1272 if (pixdev) {
1273 k=0;
1274 for(y=0;y<img->ysize;y++) for(x=0;x<img->xsize;x++) {
1275 i_gpix(img,x,y,&val);
1276 val.channel[1] = val.channel[2] =
1277 val.channel[0]=g_sat(val.channel[0]+(int)(pixdev*frandn()));
1278 CF_FIND;
1279 out[k++]=bst_idx;
1280 }
1281 } else {
1282 k=0;
1283 for(y=0;y<img->ysize;y++) for(x=0;x<img->xsize;x++) {
1284 i_gpix(img,x,y,&val);
1285 val.channel[1] = val.channel[2] = val.channel[0];
1286 CF_FIND;
1287 out[k++]=bst_idx;
1288 }
02d1d628
AMH
1289 }
1290 }
1291 CF_CLEANUP;
1292}
1293
1294static int floyd_map[] =
1295{
1296 0, 0, 7,
1297 3, 5, 1
1298};
1299
1300static int jarvis_map[] =
1301{
1302 0, 0, 0, 7, 5,
1303 3, 5, 7, 5, 3,
1304 1, 3, 5, 3, 1
1305};
1306
1307static int stucki_map[] =
1308{
1309 0, 0, 0, 8, 4,
1310 2, 4, 8, 4, 2,
1311 1, 2, 4, 2, 1
1312};
1313
1314struct errdiff_map {
1315 int *map;
1316 int width, height, orig;
1317};
1318
1319static struct errdiff_map maps[] =
1320{
1321 { floyd_map, 3, 2, 1 },
1322 { jarvis_map, 5, 3, 2 },
1323 { stucki_map, 5, 3, 2 },
1324};
1325
1326typedef struct errdiff_tag {
1327 int r, g, b;
1328} errdiff_t;
1329
1330/* perform an error diffusion dither */
1331static
1332void
1333translate_errdiff(i_quantize *quant, i_img *img, i_palidx *out) {
1334 int *map;
1335 int mapw, maph, mapo;
1336 int i;
1337 errdiff_t *err;
8d14daab 1338 i_img_dim errw;
02d1d628 1339 int difftotal;
8d14daab 1340 i_img_dim x, y, dx, dy;
b07bc64b 1341 int bst_idx = 0;
6d068d36 1342 int is_gray = is_gray_map(quant);
02d1d628
AMH
1343 CF_VARS;
1344
1345 if ((quant->errdiff & ed_mask) == ed_custom) {
1346 map = quant->ed_map;
1347 mapw = quant->ed_width;
1348 maph = quant->ed_height;
1349 mapo = quant->ed_orig;
1350 }
1351 else {
1352 int index = quant->errdiff & ed_mask;
1353 if (index >= ed_custom) index = ed_floyd;
1354 map = maps[index].map;
1355 mapw = maps[index].width;
1356 maph = maps[index].height;
1357 mapo = maps[index].orig;
1358 }
1359
1360 errw = img->xsize+mapw;
1361 err = mymalloc(sizeof(*err) * maph * errw);
1362 /*errp = err+mapo;*/
1363 memset(err, 0, sizeof(*err) * maph * errw);
1364
1365 difftotal = 0;
1366 for (i = 0; i < maph * mapw; ++i)
1367 difftotal += map[i];
1368 /*printf("map:\n");
1369 for (dy = 0; dy < maph; ++dy) {
1370 for (dx = 0; dx < mapw; ++dx) {
1371 printf("%2d", map[dx+dy*mapw]);
1372 }
1373 putchar('\n');
1374 }*/
1375
1376 CF_SETUP;
1377
1378 for (y = 0; y < img->ysize; ++y) {
1379 for (x = 0; x < img->xsize; ++x) {
1380 i_color val;
02d1d628
AMH
1381 errdiff_t perr;
1382 i_gpix(img, x, y, &val);
18accb2a
TC
1383 if (img->channels < 3) {
1384 val.channel[1] = val.channel[2] = val.channel[0];
1385 }
6d068d36
TC
1386 else if (is_gray) {
1387 int gray = 0.5 + color_to_grey(&val);
1388 val.channel[0] = val.channel[1] = val.channel[2] = gray;
1389 }
02d1d628
AMH
1390 perr = err[x+mapo];
1391 perr.r = perr.r < 0 ? -((-perr.r)/difftotal) : perr.r/difftotal;
1392 perr.g = perr.g < 0 ? -((-perr.g)/difftotal) : perr.g/difftotal;
1393 perr.b = perr.b < 0 ? -((-perr.b)/difftotal) : perr.b/difftotal;
1394 /*printf("x %3d y %3d in(%3d, %3d, %3d) di(%4d,%4d,%4d)\n", x, y, val.channel[0], val.channel[1], val.channel[2], perr.r, perr.g, perr.b);*/
1395 val.channel[0] = g_sat(val.channel[0]-perr.r);
1396 val.channel[1] = g_sat(val.channel[1]-perr.g);
1397 val.channel[2] = g_sat(val.channel[2]-perr.b);
1398 CF_FIND;
1399 /* save error */
1400 perr.r = quant->mc_colors[bst_idx].channel[0] - val.channel[0];
1401 perr.g = quant->mc_colors[bst_idx].channel[1] - val.channel[1];
1402 perr.b = quant->mc_colors[bst_idx].channel[2] - val.channel[2];
1403 /*printf(" out(%3d, %3d, %3d) er(%4d, %4d, %4d)\n", quant->mc_colors[bst_idx].channel[0], quant->mc_colors[bst_idx].channel[1], quant->mc_colors[bst_idx].channel[2], perr.r, perr.g, perr.b);*/
1404 for (dx = 0; dx < mapw; ++dx) {
1405 for (dy = 0; dy < maph; ++dy) {
1406 err[x+dx+dy*errw].r += perr.r * map[dx+mapw*dy];
1407 err[x+dx+dy*errw].g += perr.g * map[dx+mapw*dy];
1408 err[x+dx+dy*errw].b += perr.b * map[dx+mapw*dy];
1409 }
1410 }
1411 *out++ = bst_idx;
1412 }
1413 /* shift up the error matrix */
1414 for (dy = 0; dy < maph-1; ++dy) {
1415 memcpy(err+dy*errw, err+(dy+1)*errw, sizeof(*err)*errw);
1416 }
1417 memset(err+(maph-1)*errw, 0, sizeof(*err)*errw);
1418 }
1419 CF_CLEANUP;
7fd765fe 1420 myfree(err);
02d1d628
AMH
1421}
1422/* Prescan finds the boxes in the image that have the highest number of colors
1423 and that result is used as the initial value for the vectores */
1424
1425
18accb2a 1426static void prescan(i_img **imgs,int count, int cnum, cvec *clr, i_sample_t *line) {
8d14daab
TC
1427 int i,k,j;
1428 i_img_dim x,y;
18accb2a
TC
1429 i_sample_t *val;
1430 const int *chans;
02d1d628
AMH
1431
1432 pbox prebox[512];
1433 for(i=0;i<512;i++) {
1434 prebox[i].boxnum=i;
1435 prebox[i].pixcnt=0;
1436 prebox[i].cand=1;
1437 }
1438
1439 /* process each image */
1440 for (i = 0; i < count; ++i) {
1441 i_img *im = imgs[i];
18accb2a
TC
1442 chans = im->channels >= 3 ? NULL : gray_samples;
1443 for(y=0;y<im->ysize;y++) {
1444 i_gsamp(im, 0, im->xsize, y, line, chans, 3);
1445 val = line;
1446 for(x=0;x<im->xsize;x++) {
1447 prebox[pixbox_ch(val)].pixcnt++;
1448 }
02d1d628
AMH
1449 }
1450 }
1451
1452 for(i=0;i<512;i++) prebox[i].pdc=prebox[i].pixcnt;
1453 qsort(prebox,512,sizeof(pbox),(cmpfunc)pboxcmp);
1454
1455 for(i=0;i<cnum;i++) {
1456 /* printf("Color %d\n",i);
1457 for(k=0;k<10;k++) { printf("box=%03d %04d %d %04d \n",prebox[k].boxnum,prebox[k].pixcnt,prebox[k].cand,prebox[k].pdc); }
1458 printf("\n\n"); */
1459 reorder(prebox);
1460 }
1461
1462 /* for(k=0;k<cnum;k++) { printf("box=%03d %04d %d %04d \n",prebox[k].boxnum,prebox[k].pixcnt,prebox[k].cand,prebox[k].pdc); } */
1463
1464 k=0;
1465 j=1;
1466 i=0;
1467 while(i<cnum) {
1468 /* printf("prebox[%d].cand=%d\n",k,prebox[k].cand); */
36e67d0b 1469 if (clr[i].fixed) { i++; continue; } /* reserved go to next */
02d1d628
AMH
1470 if (j>=prebox[k].cand) { k++; j=1; } else {
1471 if (prebox[k].cand == 2) boxcenter(prebox[k].boxnum,&(clr[i]));
1472 else boxrand(prebox[k].boxnum,&(clr[i]));
1473 /* printf("(%d,%d) %d %d -> (%d,%d,%d)\n",k,j,prebox[k].boxnum,prebox[k].pixcnt,clr[i].r,clr[i].g,clr[i].b); */
1474 j++;
1475 i++;
1476 }
1477 }
1478}
1479
1480
1481static void reorder(pbox prescan[512]) {
1482 int nidx;
1483 pbox c;
1484
1485 nidx=0;
1486 c=prescan[0];
1487
1488 c.cand++;
1489 c.pdc=c.pixcnt/(c.cand*c.cand);
1490 /* c.pdc=c.pixcnt/c.cand; */
1491 while(c.pdc < prescan[nidx+1].pdc && nidx < 511) {
1492 prescan[nidx]=prescan[nidx+1];
1493 nidx++;
1494 }
1495 prescan[nidx]=c;
1496}
1497
1498static int
1499pboxcmp(const pbox *a,const pbox *b) {
1500 if (a->pixcnt > b->pixcnt) return -1;
1501 if (a->pixcnt < b->pixcnt) return 1;
1502 return 0;
1503}
1504
1505static void
1506boxcenter(int box,cvec *cv) {
1507 cv->r=15+((box&448)>>1);
1508 cv->g=15+((box&56)<<2);
1509 cv->b=15+((box&7)<<5);
1510}
1511
1512static void
1513bbox(int box,int *r0,int *r1,int *g0,int *g1,int *b0,int *b1) {
1514 *r0=(box&448)>>1;
1515 *r1=(*r0)|31;
1516 *g0=(box&56)<<2;
1517 *g1=(*g0)|31;
1518 *b0=(box&7)<<5;
1519 *b1=(*b0)|31;
1520}
1521
1522static void
1523boxrand(int box,cvec *cv) {
1524 cv->r=6+(rand()%25)+((box&448)>>1);
1525 cv->g=6+(rand()%25)+((box&56)<<2);
1526 cv->b=6+(rand()%25)+((box&7)<<5);
1527}
1528
1529static float
1530frandn(void) {
1531
1532 float u1,u2,w;
1533
1534 w=1;
1535
1536 while (w >= 1 || w == 0) {
1537 u1 = 2 * frand() - 1;
1538 u2 = 2 * frand() - 1;
1539 w = u1*u1 + u2*u2;
1540 }
1541
1542 w = sqrt((-2*log(w))/w);
1543 return u1*w;
1544}
1545
1546/* Create hash index */
1547static
1548void
1549cr_hashindex(cvec clr[256],int cnum,hashbox hb[512]) {
1550
1551 int bx,mind,cd,cumcnt,bst_idx,i;
1552/* printf("indexing... \n");*/
1553
1554 cumcnt=0;
1555 for(bx=0; bx<512; bx++) {
1556 mind=196608;
1557 for(i=0; i<cnum; i++) {
1558 cd = maxdist(bx,&clr[i]);
1559 if (cd < mind) { mind=cd; bst_idx=i; }
1560 }
1561
1562 hb[bx].cnt=0;
1563 for(i=0;i<cnum;i++) if (mindist(bx,&clr[i])<mind) hb[bx].vec[hb[bx].cnt++]=i;
1564 /*printf("box %d -> approx -> %d\n",bx,hb[bx].cnt); */
1565 /* statbox(bx,cnum,clr); */
1566 cumcnt+=hb[bx].cnt;
1567 }
1568
1569/* printf("Average search space: %d\n",cumcnt/512); */
1570}
1571
1572static int
1573maxdist(int boxnum,cvec *cv) {
1574 int r0,r1,g0,g1,b0,b1;
1575 int r,g,b,mr,mg,mb;
1576
1577 r=cv->r;
1578 g=cv->g;
1579 b=cv->b;
1580
1581 bbox(boxnum,&r0,&r1,&g0,&g1,&b0,&b1);
1582
b33c08f8
TC
1583 mr=i_max(abs(b-b0),abs(b-b1));
1584 mg=i_max(abs(g-g0),abs(g-g1));
1585 mb=i_max(abs(r-r0),abs(r-r1));
02d1d628
AMH
1586
1587 return PWR2(mr)+PWR2(mg)+PWR2(mb);
1588}
1589
1590static int
1591mindist(int boxnum,cvec *cv) {
1592 int r0,r1,g0,g1,b0,b1;
1593 int r,g,b,mr,mg,mb;
1594
1595 r=cv->r;
1596 g=cv->g;
1597 b=cv->b;
1598
1599 bbox(boxnum,&r0,&r1,&g0,&g1,&b0,&b1);
1600
1601 /* printf("box %d, (%d,%d,%d)-(%d,%d,%d) vec (%d,%d,%d) ",boxnum,r0,g0,b0,r1,g1,b1,r,g,b); */
1602
1603 if (r0<=r && r<=r1 && g0<=g && g<=g1 && b0<=b && b<=b1) return 0;
1604
b33c08f8
TC
1605 mr=i_min(abs(b-b0),abs(b-b1));
1606 mg=i_min(abs(g-g0),abs(g-g1));
1607 mb=i_min(abs(r-r0),abs(r-r1));
02d1d628
AMH
1608
1609 mr=PWR2(mr);
1610 mg=PWR2(mg);
1611 mb=PWR2(mb);
1612
1613 if (r0<=r && r<=r1 && g0<=g && g<=g1) return mb;
1614 if (r0<=r && r<=r1 && b0<=b && b<=b1) return mg;
1615 if (b0<=b && b<=b1 && g0<=g && g<=g1) return mr;
1616
1617 if (r0<=r && r<=r1) return mg+mb;
1618 if (g0<=g && g<=g1) return mr+mb;
1619 if (b0<=b && b<=b1) return mg+mr;
1620
1621 return mr+mg+mb;
1622}
1623
1624static void transparent_threshold(i_quantize *, i_palidx *, i_img *, i_palidx);
1625static void transparent_errdiff(i_quantize *, i_palidx *, i_img *, i_palidx);
1626static void transparent_ordered(i_quantize *, i_palidx *, i_img *, i_palidx);
1627
92bda632 1628/*
5715f7c3 1629=item i_quant_transparent(C<quant>, C<data>, C<img>, C<trans_index>)
92bda632
TC
1630
1631=category Image quantization
1632
5715f7c3
TC
1633Dither the alpha channel on C<img> into the palette indexes in
1634C<data>. Pixels to be transparent are replaced with C<trans_pixel>.
92bda632 1635
5715f7c3 1636The method used depends on the tr_* members of C<quant>.
92bda632
TC
1637
1638=cut
1639*/
1640
1641void
1642i_quant_transparent(i_quantize *quant, i_palidx *data, i_img *img,
02d1d628
AMH
1643 i_palidx trans_index)
1644{
1645 switch (quant->transp) {
1646 case tr_none:
1647 break;
1648
1649 default:
1650 quant->tr_threshold = 128;
1651 /* fall through */
1652 case tr_threshold:
1653 transparent_threshold(quant, data, img, trans_index);
1654 break;
1655
1656 case tr_errdiff:
1657 transparent_errdiff(quant, data, img, trans_index);
1658 break;
1659
1660 case tr_ordered:
1661 transparent_ordered(quant, data, img, trans_index);
1662 break;
1663 }
1664}
1665
1666static void
1667transparent_threshold(i_quantize *quant, i_palidx *data, i_img *img,
1668 i_palidx trans_index)
1669{
8d14daab 1670 i_img_dim x, y;
18accb2a
TC
1671 i_sample_t *line = mymalloc(img->xsize * sizeof(i_sample_t));
1672 int trans_chan = img->channels > 2 ? 3 : 1;
02d1d628
AMH
1673
1674 for (y = 0; y < img->ysize; ++y) {
18accb2a 1675 i_gsamp(img, 0, img->xsize, y, line, &trans_chan, 1);
02d1d628 1676 for (x = 0; x < img->xsize; ++x) {
18accb2a 1677 if (line[x] < quant->tr_threshold)
02d1d628
AMH
1678 data[y*img->xsize+x] = trans_index;
1679 }
1680 }
18accb2a 1681 myfree(line);
02d1d628
AMH
1682}
1683
1684static void
1685transparent_errdiff(i_quantize *quant, i_palidx *data, i_img *img,
1686 i_palidx trans_index)
1687{
1688 int *map;
1689 int index;
1690 int mapw, maph, mapo;
1691 int errw, *err, *errp;
1692 int difftotal, out, error;
8d14daab
TC
1693 i_img_dim x, y, dx, dy;
1694 int i;
18accb2a
TC
1695 i_sample_t *line;
1696 int trans_chan = img->channels > 2 ? 3 : 1;
02d1d628
AMH
1697
1698 /* no custom map for transparency (yet) */
1699 index = quant->tr_errdiff & ed_mask;
1700 if (index >= ed_custom) index = ed_floyd;
1701 map = maps[index].map;
1702 mapw = maps[index].width;
1703 maph = maps[index].height;
1704 mapo = maps[index].orig;
1705
1706 errw = img->xsize+mapw-1;
1707 err = mymalloc(sizeof(*err) * maph * errw);
1708 errp = err+mapo;
1709 memset(err, 0, sizeof(*err) * maph * errw);
1710
18accb2a 1711 line = mymalloc(img->xsize * sizeof(i_sample_t));
02d1d628
AMH
1712 difftotal = 0;
1713 for (i = 0; i < maph * mapw; ++i)
1714 difftotal += map[i];
1715 for (y = 0; y < img->ysize; ++y) {
18accb2a 1716 i_gsamp(img, 0, img->xsize, y, line, &trans_chan, 1);
02d1d628 1717 for (x = 0; x < img->xsize; ++x) {
18accb2a
TC
1718 line[x] = g_sat(line[x]-errp[x]/difftotal);
1719 if (line[x] < 128) {
02d1d628
AMH
1720 out = 0;
1721 data[y*img->xsize+x] = trans_index;
1722 }
1723 else {
1724 out = 255;
1725 }
18accb2a 1726 error = out - line[x];
02d1d628
AMH
1727 for (dx = 0; dx < mapw; ++dx) {
1728 for (dy = 0; dy < maph; ++dy) {
1729 errp[x+dx-mapo+dy*errw] += error * map[dx+mapw*dy];
1730 }
1731 }
1732 }
1733 /* shift up the error matrix */
1734 for (dy = 0; dy < maph-1; ++dy)
1735 memcpy(err+dy*errw, err+(dy+1)*errw, sizeof(*err)*errw);
1736 memset(err+(maph-1)*errw, 0, sizeof(*err)*errw);
1737 }
18accb2a
TC
1738 myfree(err);
1739 myfree(line);
02d1d628
AMH
1740}
1741
1742/* builtin ordered dither maps */
b33c08f8
TC
1743static unsigned char
1744orddith_maps[][64] =
02d1d628
AMH
1745{
1746 { /* random
1747 this is purely random - it's pretty awful
1748 */
1749 48, 72, 196, 252, 180, 92, 108, 52,
1750 228, 176, 64, 8, 236, 40, 20, 164,
1751 120, 128, 84, 116, 24, 28, 172, 220,
1752 68, 0, 188, 124, 184, 224, 192, 104,
1753 132, 100, 240, 200, 152, 160, 244, 44,
1754 96, 204, 144, 16, 140, 56, 232, 216,
1755 208, 4, 76, 212, 136, 248, 80, 168,
1756 156, 88, 32, 112, 148, 12, 36, 60,
1757 },
1758 {
1759 /* dot8
1760 perl spot.perl '($x-3.5)*($x-3.5)+($y-3.5)*($y-3.5)'
1761 */
1762 240, 232, 200, 136, 140, 192, 228, 248,
1763 220, 148, 100, 76, 80, 104, 152, 212,
1764 180, 116, 56, 32, 36, 60, 120, 176,
1765 156, 64, 28, 0, 8, 44, 88, 160,
1766 128, 92, 24, 12, 4, 40, 68, 132,
1767 184, 96, 48, 20, 16, 52, 108, 188,
1768 216, 144, 112, 72, 84, 124, 164, 224,
1769 244, 236, 196, 168, 172, 204, 208, 252,
1770 },
1771 { /* dot4
1772 perl spot.perl \
1773 'min(dist(1.5, 1.5),dist(5.5,1.5),dist(1.5,5.5),dist(5.5,5.5))'
1774 */
1775 196, 72, 104, 220, 200, 80, 112, 224,
1776 76, 4, 24, 136, 84, 8, 32, 144,
1777 108, 28, 52, 168, 116, 36, 56, 176,
1778 216, 140, 172, 244, 228, 148, 180, 248,
1779 204, 92, 124, 236, 192, 68, 96, 208,
1780 88, 12, 44, 156, 64, 0, 16, 128,
1781 120, 40, 60, 188, 100, 20, 48, 160,
1782 232, 152, 184, 252, 212, 132, 164, 240,
1783 },
1784 { /* hline
1785 perl spot.perl '$y-3'
1786 */
1787 160, 164, 168, 172, 176, 180, 184, 188,
1788 128, 132, 136, 140, 144, 148, 152, 156,
1789 32, 36, 40, 44, 48, 52, 56, 60,
1790 0, 4, 8, 12, 16, 20, 24, 28,
1791 64, 68, 72, 76, 80, 84, 88, 92,
1792 96, 100, 104, 108, 112, 116, 120, 124,
1793 192, 196, 200, 204, 208, 212, 216, 220,
1794 224, 228, 232, 236, 240, 244, 248, 252,
1795 },
1796 { /* vline
1797 perl spot.perl '$x-3'
1798 */
1799 180, 100, 40, 12, 44, 104, 184, 232,
1800 204, 148, 60, 16, 64, 128, 208, 224,
1801 212, 144, 76, 8, 80, 132, 216, 244,
1802 160, 112, 68, 20, 84, 108, 172, 236,
1803 176, 96, 72, 28, 88, 152, 188, 228,
1804 200, 124, 92, 0, 32, 116, 164, 240,
1805 168, 120, 36, 24, 48, 136, 192, 248,
1806 196, 140, 52, 4, 56, 156, 220, 252,
1807 },
1808 { /* slashline
1809 perl spot.perl '$y+$x-7'
1810 */
1811 248, 232, 224, 192, 140, 92, 52, 28,
1812 240, 220, 196, 144, 108, 60, 12, 64,
1813 216, 180, 148, 116, 76, 20, 80, 128,
1814 204, 152, 104, 44, 16, 72, 100, 160,
1815 164, 96, 68, 24, 56, 112, 168, 176,
1816 124, 40, 8, 36, 88, 136, 184, 212,
1817 84, 4, 32, 120, 156, 188, 228, 236,
1818 0, 48, 132, 172, 200, 208, 244, 252,
1819 },
1820 { /* backline
1821 perl spot.perl '$y-$x'
1822 */
1823 0, 32, 116, 172, 184, 216, 236, 252,
1824 56, 8, 72, 132, 136, 200, 228, 240,
1825 100, 36, 12, 40, 92, 144, 204, 220,
1826 168, 120, 60, 16, 44, 96, 156, 176,
1827 180, 164, 112, 48, 28, 52, 128, 148,
1828 208, 192, 152, 88, 84, 20, 64, 104,
1829 232, 224, 196, 140, 108, 68, 24, 76,
1830 248, 244, 212, 188, 160, 124, 80, 4,
1831 },
11e7329d
TC
1832 {
1833 /* tiny
1834 good for display, bad for print
1835 hand generated
1836 */
1837 0, 128, 32, 192, 8, 136, 40, 200,
1838 224, 64, 160, 112, 232, 72, 168, 120,
1839 48, 144, 16, 208, 56, 152, 24, 216,
1840 176, 96, 240, 80, 184, 104, 248, 88,
1841 12, 140, 44, 204, 4, 132, 36, 196,
1842 236, 76, 172, 124, 228, 68, 164, 116,
1843 60, 156, 28, 220, 52, 148, 20, 212,
1844 188, 108, 252, 92, 180, 100, 244, 84,
1845 },
02d1d628
AMH
1846};
1847
1848static void
1849transparent_ordered(i_quantize *quant, i_palidx *data, i_img *img,
1850 i_palidx trans_index)
1851{
1852 unsigned char *spot;
8d14daab 1853 i_img_dim x, y;
18accb2a
TC
1854 i_sample_t *line;
1855 int trans_chan = img->channels > 2 ? 3 : 1;
02d1d628
AMH
1856 if (quant->tr_orddith == od_custom)
1857 spot = quant->tr_custom;
1858 else
1859 spot = orddith_maps[quant->tr_orddith];
18accb2a
TC
1860
1861 line = mymalloc(img->xsize * sizeof(i_sample_t));
02d1d628 1862 for (y = 0; y < img->ysize; ++y) {
18accb2a 1863 i_gsamp(img, 0, img->xsize, y, line, &trans_chan, 1);
02d1d628 1864 for (x = 0; x < img->xsize; ++x) {
18accb2a 1865 if (line[x] < spot[(x&7)+(y&7)*8])
02d1d628
AMH
1866 data[x+y*img->xsize] = trans_index;
1867 }
1868 }
18accb2a 1869 myfree(line);
02d1d628 1870}
18accb2a 1871