]> git.saurik.com Git - wxWidgets.git/blob - src/tiff/tools/tiffmedian.c
No changes, just fix a harmless warning in FileSystemWatcherTestCase.
[wxWidgets.git] / src / tiff / tools / tiffmedian.c
1 /* $Id$ */
2
3 /*
4 * Apply median cut on an image.
5 *
6 * tiffmedian [-c n] [-f] input output
7 * -C n - set colortable size. Default is 256.
8 * -f - use Floyd-Steinberg dithering.
9 * -c lzw - compress output with LZW
10 * -c none - use no compression on output
11 * -c packbits - use packbits compression on output
12 * -r n - create output with n rows/strip of data
13 * (by default the compression scheme and rows/strip are taken
14 * from the input file)
15 *
16 * Notes:
17 *
18 * [1] Floyd-Steinberg dither:
19 * I should point out that the actual fractions we used were, assuming
20 * you are at X, moving left to right:
21 *
22 * X 7/16
23 * 3/16 5/16 1/16
24 *
25 * Note that the error goes to four neighbors, not three. I think this
26 * will probably do better (at least for black and white) than the
27 * 3/8-3/8-1/4 distribution, at the cost of greater processing. I have
28 * seen the 3/8-3/8-1/4 distribution described as "our" algorithm before,
29 * but I have no idea who the credit really belongs to.
30
31 * Also, I should add that if you do zig-zag scanning (see my immediately
32 * previous message), it is sufficient (but not quite as good) to send
33 * half the error one pixel ahead (e.g. to the right on lines you scan
34 * left to right), and half one pixel straight down. Again, this is for
35 * black and white; I've not tried it with color.
36 * --
37 * Lou Steinberg
38 *
39 * [2] Color Image Quantization for Frame Buffer Display, Paul Heckbert,
40 * Siggraph '82 proceedings, pp. 297-307
41 */
42
43 #include "tif_config.h"
44
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <string.h>
48
49 #ifdef HAVE_UNISTD_H
50 # include <unistd.h>
51 #endif
52
53 #include "tiffio.h"
54
55 #define MAX_CMAP_SIZE 256
56
57 #define streq(a,b) (strcmp(a,b) == 0)
58 #define strneq(a,b,n) (strncmp(a,b,n) == 0)
59
60 #define COLOR_DEPTH 8
61 #define MAX_COLOR 256
62
63 #define B_DEPTH 5 /* # bits/pixel to use */
64 #define B_LEN (1L<<B_DEPTH)
65
66 #define C_DEPTH 2
67 #define C_LEN (1L<<C_DEPTH) /* # cells/color to use */
68
69 #define COLOR_SHIFT (COLOR_DEPTH-B_DEPTH)
70
71 typedef struct colorbox {
72 struct colorbox *next, *prev;
73 int rmin, rmax;
74 int gmin, gmax;
75 int bmin, bmax;
76 uint32 total;
77 } Colorbox;
78
79 typedef struct {
80 int num_ents;
81 int entries[MAX_CMAP_SIZE][2];
82 } C_cell;
83
84 uint16 rm[MAX_CMAP_SIZE], gm[MAX_CMAP_SIZE], bm[MAX_CMAP_SIZE];
85 int num_colors;
86 uint32 histogram[B_LEN][B_LEN][B_LEN];
87 Colorbox *freeboxes;
88 Colorbox *usedboxes;
89 C_cell **ColorCells;
90 TIFF *in, *out;
91 uint32 rowsperstrip = (uint32) -1;
92 uint16 compression = (uint16) -1;
93 uint16 bitspersample = 1;
94 uint16 samplesperpixel;
95 uint32 imagewidth;
96 uint32 imagelength;
97 uint16 predictor = 0;
98
99 static void get_histogram(TIFF*, Colorbox*);
100 static void splitbox(Colorbox*);
101 static void shrinkbox(Colorbox*);
102 static void map_colortable(void);
103 static void quant(TIFF*, TIFF*);
104 static void quant_fsdither(TIFF*, TIFF*);
105 static Colorbox* largest_box(void);
106
107 static void usage(void);
108 static int processCompressOptions(char*);
109
110 #define CopyField(tag, v) \
111 if (TIFFGetField(in, tag, &v)) TIFFSetField(out, tag, v)
112
113 int
114 main(int argc, char* argv[])
115 {
116 int i, dither = 0;
117 uint16 shortv, config, photometric;
118 Colorbox *box_list, *ptr;
119 float floatv;
120 uint32 longv;
121 int c;
122 extern int optind;
123 extern char* optarg;
124
125 num_colors = MAX_CMAP_SIZE;
126 while ((c = getopt(argc, argv, "c:C:r:f")) != -1)
127 switch (c) {
128 case 'c': /* compression scheme */
129 if (!processCompressOptions(optarg))
130 usage();
131 break;
132 case 'C': /* set colormap size */
133 num_colors = atoi(optarg);
134 if (num_colors > MAX_CMAP_SIZE) {
135 fprintf(stderr,
136 "-c: colormap too big, max %d\n",
137 MAX_CMAP_SIZE);
138 usage();
139 }
140 break;
141 case 'f': /* dither */
142 dither = 1;
143 break;
144 case 'r': /* rows/strip */
145 rowsperstrip = atoi(optarg);
146 break;
147 case '?':
148 usage();
149 /*NOTREACHED*/
150 }
151 if (argc - optind != 2)
152 usage();
153 in = TIFFOpen(argv[optind], "r");
154 if (in == NULL)
155 return (-1);
156 TIFFGetField(in, TIFFTAG_IMAGEWIDTH, &imagewidth);
157 TIFFGetField(in, TIFFTAG_IMAGELENGTH, &imagelength);
158 TIFFGetField(in, TIFFTAG_BITSPERSAMPLE, &bitspersample);
159 TIFFGetField(in, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel);
160 if (bitspersample != 8 && bitspersample != 16) {
161 fprintf(stderr, "%s: Image must have at least 8-bits/sample\n",
162 argv[optind]);
163 return (-3);
164 }
165 if (!TIFFGetField(in, TIFFTAG_PHOTOMETRIC, &photometric) ||
166 photometric != PHOTOMETRIC_RGB || samplesperpixel < 3) {
167 fprintf(stderr, "%s: Image must have RGB data\n", argv[optind]);
168 return (-4);
169 }
170 TIFFGetField(in, TIFFTAG_PLANARCONFIG, &config);
171 if (config != PLANARCONFIG_CONTIG) {
172 fprintf(stderr, "%s: Can only handle contiguous data packing\n",
173 argv[optind]);
174 return (-5);
175 }
176
177 /*
178 * STEP 1: create empty boxes
179 */
180 usedboxes = NULL;
181 box_list = freeboxes = (Colorbox *)_TIFFmalloc(num_colors*sizeof (Colorbox));
182 freeboxes[0].next = &freeboxes[1];
183 freeboxes[0].prev = NULL;
184 for (i = 1; i < num_colors-1; ++i) {
185 freeboxes[i].next = &freeboxes[i+1];
186 freeboxes[i].prev = &freeboxes[i-1];
187 }
188 freeboxes[num_colors-1].next = NULL;
189 freeboxes[num_colors-1].prev = &freeboxes[num_colors-2];
190
191 /*
192 * STEP 2: get histogram, initialize first box
193 */
194 ptr = freeboxes;
195 freeboxes = ptr->next;
196 if (freeboxes)
197 freeboxes->prev = NULL;
198 ptr->next = usedboxes;
199 usedboxes = ptr;
200 if (ptr->next)
201 ptr->next->prev = ptr;
202 get_histogram(in, ptr);
203
204 /*
205 * STEP 3: continually subdivide boxes until no more free
206 * boxes remain or until all colors assigned.
207 */
208 while (freeboxes != NULL) {
209 ptr = largest_box();
210 if (ptr != NULL)
211 splitbox(ptr);
212 else
213 freeboxes = NULL;
214 }
215
216 /*
217 * STEP 4: assign colors to all boxes
218 */
219 for (i = 0, ptr = usedboxes; ptr != NULL; ++i, ptr = ptr->next) {
220 rm[i] = ((ptr->rmin + ptr->rmax) << COLOR_SHIFT) / 2;
221 gm[i] = ((ptr->gmin + ptr->gmax) << COLOR_SHIFT) / 2;
222 bm[i] = ((ptr->bmin + ptr->bmax) << COLOR_SHIFT) / 2;
223 }
224
225 /* We're done with the boxes now */
226 _TIFFfree(box_list);
227 freeboxes = usedboxes = NULL;
228
229 /*
230 * STEP 5: scan histogram and map all values to closest color
231 */
232 /* 5a: create cell list as described in Heckbert[2] */
233 ColorCells = (C_cell **)_TIFFmalloc(C_LEN*C_LEN*C_LEN*sizeof (C_cell*));
234 _TIFFmemset(ColorCells, 0, C_LEN*C_LEN*C_LEN*sizeof (C_cell*));
235 /* 5b: create mapping from truncated pixel space to color
236 table entries */
237 map_colortable();
238
239 /*
240 * STEP 6: scan image, match input values to table entries
241 */
242 out = TIFFOpen(argv[optind+1], "w");
243 if (out == NULL)
244 return (-2);
245
246 CopyField(TIFFTAG_SUBFILETYPE, longv);
247 CopyField(TIFFTAG_IMAGEWIDTH, longv);
248 TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, (short)COLOR_DEPTH);
249 if (compression != (uint16)-1) {
250 TIFFSetField(out, TIFFTAG_COMPRESSION, compression);
251 switch (compression) {
252 case COMPRESSION_LZW:
253 case COMPRESSION_DEFLATE:
254 if (predictor != 0)
255 TIFFSetField(out, TIFFTAG_PREDICTOR, predictor);
256 break;
257 }
258 } else
259 CopyField(TIFFTAG_COMPRESSION, compression);
260 TIFFSetField(out, TIFFTAG_PHOTOMETRIC, (short)PHOTOMETRIC_PALETTE);
261 CopyField(TIFFTAG_ORIENTATION, shortv);
262 TIFFSetField(out, TIFFTAG_SAMPLESPERPIXEL, (short)1);
263 CopyField(TIFFTAG_PLANARCONFIG, shortv);
264 TIFFSetField(out, TIFFTAG_ROWSPERSTRIP,
265 TIFFDefaultStripSize(out, rowsperstrip));
266 CopyField(TIFFTAG_MINSAMPLEVALUE, shortv);
267 CopyField(TIFFTAG_MAXSAMPLEVALUE, shortv);
268 CopyField(TIFFTAG_RESOLUTIONUNIT, shortv);
269 CopyField(TIFFTAG_XRESOLUTION, floatv);
270 CopyField(TIFFTAG_YRESOLUTION, floatv);
271 CopyField(TIFFTAG_XPOSITION, floatv);
272 CopyField(TIFFTAG_YPOSITION, floatv);
273
274 if (dither)
275 quant_fsdither(in, out);
276 else
277 quant(in, out);
278 /*
279 * Scale colormap to TIFF-required 16-bit values.
280 */
281 #define SCALE(x) (((x)*((1L<<16)-1))/255)
282 for (i = 0; i < MAX_CMAP_SIZE; ++i) {
283 rm[i] = SCALE(rm[i]);
284 gm[i] = SCALE(gm[i]);
285 bm[i] = SCALE(bm[i]);
286 }
287 TIFFSetField(out, TIFFTAG_COLORMAP, rm, gm, bm);
288 (void) TIFFClose(out);
289 return (0);
290 }
291
292 static int
293 processCompressOptions(char* opt)
294 {
295 if (streq(opt, "none"))
296 compression = COMPRESSION_NONE;
297 else if (streq(opt, "packbits"))
298 compression = COMPRESSION_PACKBITS;
299 else if (strneq(opt, "lzw", 3)) {
300 char* cp = strchr(opt, ':');
301 if (cp)
302 predictor = atoi(cp+1);
303 compression = COMPRESSION_LZW;
304 } else if (strneq(opt, "zip", 3)) {
305 char* cp = strchr(opt, ':');
306 if (cp)
307 predictor = atoi(cp+1);
308 compression = COMPRESSION_DEFLATE;
309 } else
310 return (0);
311 return (1);
312 }
313
314 char* stuff[] = {
315 "usage: tiffmedian [options] input.tif output.tif",
316 "where options are:",
317 " -r # make each strip have no more than # rows",
318 " -C # create a colormap with # entries",
319 " -f use Floyd-Steinberg dithering",
320 " -c lzw[:opts] compress output with Lempel-Ziv & Welch encoding",
321 " -c zip[:opts] compress output with deflate encoding",
322 " -c packbits compress output with packbits encoding",
323 " -c none use no compression algorithm on output",
324 "",
325 "LZW and deflate options:",
326 " # set predictor value",
327 "For example, -c lzw:2 to get LZW-encoded data with horizontal differencing",
328 NULL
329 };
330
331 static void
332 usage(void)
333 {
334 char buf[BUFSIZ];
335 int i;
336
337 setbuf(stderr, buf);
338 fprintf(stderr, "%s\n\n", TIFFGetVersion());
339 for (i = 0; stuff[i] != NULL; i++)
340 fprintf(stderr, "%s\n", stuff[i]);
341 exit(-1);
342 }
343
344 static void
345 get_histogram(TIFF* in, Colorbox* box)
346 {
347 register unsigned char *inptr;
348 register int red, green, blue;
349 register uint32 j, i;
350 unsigned char *inputline;
351
352 inputline = (unsigned char *)_TIFFmalloc(TIFFScanlineSize(in));
353 if (inputline == NULL) {
354 fprintf(stderr, "No space for scanline buffer\n");
355 exit(-1);
356 }
357 box->rmin = box->gmin = box->bmin = 999;
358 box->rmax = box->gmax = box->bmax = -1;
359 box->total = imagewidth * imagelength;
360
361 { register uint32 *ptr = &histogram[0][0][0];
362 for (i = B_LEN*B_LEN*B_LEN; i-- > 0;)
363 *ptr++ = 0;
364 }
365 for (i = 0; i < imagelength; i++) {
366 if (TIFFReadScanline(in, inputline, i, 0) <= 0)
367 break;
368 inptr = inputline;
369 for (j = imagewidth; j-- > 0;) {
370 red = *inptr++ >> COLOR_SHIFT;
371 green = *inptr++ >> COLOR_SHIFT;
372 blue = *inptr++ >> COLOR_SHIFT;
373 if (red < box->rmin)
374 box->rmin = red;
375 if (red > box->rmax)
376 box->rmax = red;
377 if (green < box->gmin)
378 box->gmin = green;
379 if (green > box->gmax)
380 box->gmax = green;
381 if (blue < box->bmin)
382 box->bmin = blue;
383 if (blue > box->bmax)
384 box->bmax = blue;
385 histogram[red][green][blue]++;
386 }
387 }
388 _TIFFfree(inputline);
389 }
390
391 static Colorbox *
392 largest_box(void)
393 {
394 register Colorbox *p, *b;
395 register uint32 size;
396
397 b = NULL;
398 size = 0;
399 for (p = usedboxes; p != NULL; p = p->next)
400 if ((p->rmax > p->rmin || p->gmax > p->gmin ||
401 p->bmax > p->bmin) && p->total > size)
402 size = (b = p)->total;
403 return (b);
404 }
405
406 static void
407 splitbox(Colorbox* ptr)
408 {
409 uint32 hist2[B_LEN];
410 int first=0, last=0;
411 register Colorbox *new;
412 register uint32 *iptr, *histp;
413 register int i, j;
414 register int ir,ig,ib;
415 register uint32 sum, sum1, sum2;
416 enum { RED, GREEN, BLUE } axis;
417
418 /*
419 * See which axis is the largest, do a histogram along that
420 * axis. Split at median point. Contract both new boxes to
421 * fit points and return
422 */
423 i = ptr->rmax - ptr->rmin;
424 if (i >= ptr->gmax - ptr->gmin && i >= ptr->bmax - ptr->bmin)
425 axis = RED;
426 else if (ptr->gmax - ptr->gmin >= ptr->bmax - ptr->bmin)
427 axis = GREEN;
428 else
429 axis = BLUE;
430 /* get histogram along longest axis */
431 switch (axis) {
432 case RED:
433 histp = &hist2[ptr->rmin];
434 for (ir = ptr->rmin; ir <= ptr->rmax; ++ir) {
435 *histp = 0;
436 for (ig = ptr->gmin; ig <= ptr->gmax; ++ig) {
437 iptr = &histogram[ir][ig][ptr->bmin];
438 for (ib = ptr->bmin; ib <= ptr->bmax; ++ib)
439 *histp += *iptr++;
440 }
441 histp++;
442 }
443 first = ptr->rmin;
444 last = ptr->rmax;
445 break;
446 case GREEN:
447 histp = &hist2[ptr->gmin];
448 for (ig = ptr->gmin; ig <= ptr->gmax; ++ig) {
449 *histp = 0;
450 for (ir = ptr->rmin; ir <= ptr->rmax; ++ir) {
451 iptr = &histogram[ir][ig][ptr->bmin];
452 for (ib = ptr->bmin; ib <= ptr->bmax; ++ib)
453 *histp += *iptr++;
454 }
455 histp++;
456 }
457 first = ptr->gmin;
458 last = ptr->gmax;
459 break;
460 case BLUE:
461 histp = &hist2[ptr->bmin];
462 for (ib = ptr->bmin; ib <= ptr->bmax; ++ib) {
463 *histp = 0;
464 for (ir = ptr->rmin; ir <= ptr->rmax; ++ir) {
465 iptr = &histogram[ir][ptr->gmin][ib];
466 for (ig = ptr->gmin; ig <= ptr->gmax; ++ig) {
467 *histp += *iptr;
468 iptr += B_LEN;
469 }
470 }
471 histp++;
472 }
473 first = ptr->bmin;
474 last = ptr->bmax;
475 break;
476 }
477 /* find median point */
478 sum2 = ptr->total / 2;
479 histp = &hist2[first];
480 sum = 0;
481 for (i = first; i <= last && (sum += *histp++) < sum2; ++i)
482 ;
483 if (i == first)
484 i++;
485
486 /* Create new box, re-allocate points */
487 new = freeboxes;
488 freeboxes = new->next;
489 if (freeboxes)
490 freeboxes->prev = NULL;
491 if (usedboxes)
492 usedboxes->prev = new;
493 new->next = usedboxes;
494 usedboxes = new;
495
496 histp = &hist2[first];
497 for (sum1 = 0, j = first; j < i; j++)
498 sum1 += *histp++;
499 for (sum2 = 0, j = i; j <= last; j++)
500 sum2 += *histp++;
501 new->total = sum1;
502 ptr->total = sum2;
503
504 new->rmin = ptr->rmin;
505 new->rmax = ptr->rmax;
506 new->gmin = ptr->gmin;
507 new->gmax = ptr->gmax;
508 new->bmin = ptr->bmin;
509 new->bmax = ptr->bmax;
510 switch (axis) {
511 case RED:
512 new->rmax = i-1;
513 ptr->rmin = i;
514 break;
515 case GREEN:
516 new->gmax = i-1;
517 ptr->gmin = i;
518 break;
519 case BLUE:
520 new->bmax = i-1;
521 ptr->bmin = i;
522 break;
523 }
524 shrinkbox(new);
525 shrinkbox(ptr);
526 }
527
528 static void
529 shrinkbox(Colorbox* box)
530 {
531 register uint32 *histp;
532 register int ir, ig, ib;
533
534 if (box->rmax > box->rmin) {
535 for (ir = box->rmin; ir <= box->rmax; ++ir)
536 for (ig = box->gmin; ig <= box->gmax; ++ig) {
537 histp = &histogram[ir][ig][box->bmin];
538 for (ib = box->bmin; ib <= box->bmax; ++ib)
539 if (*histp++ != 0) {
540 box->rmin = ir;
541 goto have_rmin;
542 }
543 }
544 have_rmin:
545 if (box->rmax > box->rmin)
546 for (ir = box->rmax; ir >= box->rmin; --ir)
547 for (ig = box->gmin; ig <= box->gmax; ++ig) {
548 histp = &histogram[ir][ig][box->bmin];
549 ib = box->bmin;
550 for (; ib <= box->bmax; ++ib)
551 if (*histp++ != 0) {
552 box->rmax = ir;
553 goto have_rmax;
554 }
555 }
556 }
557 have_rmax:
558 if (box->gmax > box->gmin) {
559 for (ig = box->gmin; ig <= box->gmax; ++ig)
560 for (ir = box->rmin; ir <= box->rmax; ++ir) {
561 histp = &histogram[ir][ig][box->bmin];
562 for (ib = box->bmin; ib <= box->bmax; ++ib)
563 if (*histp++ != 0) {
564 box->gmin = ig;
565 goto have_gmin;
566 }
567 }
568 have_gmin:
569 if (box->gmax > box->gmin)
570 for (ig = box->gmax; ig >= box->gmin; --ig)
571 for (ir = box->rmin; ir <= box->rmax; ++ir) {
572 histp = &histogram[ir][ig][box->bmin];
573 ib = box->bmin;
574 for (; ib <= box->bmax; ++ib)
575 if (*histp++ != 0) {
576 box->gmax = ig;
577 goto have_gmax;
578 }
579 }
580 }
581 have_gmax:
582 if (box->bmax > box->bmin) {
583 for (ib = box->bmin; ib <= box->bmax; ++ib)
584 for (ir = box->rmin; ir <= box->rmax; ++ir) {
585 histp = &histogram[ir][box->gmin][ib];
586 for (ig = box->gmin; ig <= box->gmax; ++ig) {
587 if (*histp != 0) {
588 box->bmin = ib;
589 goto have_bmin;
590 }
591 histp += B_LEN;
592 }
593 }
594 have_bmin:
595 if (box->bmax > box->bmin)
596 for (ib = box->bmax; ib >= box->bmin; --ib)
597 for (ir = box->rmin; ir <= box->rmax; ++ir) {
598 histp = &histogram[ir][box->gmin][ib];
599 ig = box->gmin;
600 for (; ig <= box->gmax; ++ig) {
601 if (*histp != 0) {
602 box->bmax = ib;
603 goto have_bmax;
604 }
605 histp += B_LEN;
606 }
607 }
608 }
609 have_bmax:
610 ;
611 }
612
613 static C_cell *
614 create_colorcell(int red, int green, int blue)
615 {
616 register int ir, ig, ib, i;
617 register C_cell *ptr;
618 int mindist, next_n;
619 register int tmp, dist, n;
620
621 ir = red >> (COLOR_DEPTH-C_DEPTH);
622 ig = green >> (COLOR_DEPTH-C_DEPTH);
623 ib = blue >> (COLOR_DEPTH-C_DEPTH);
624 ptr = (C_cell *)_TIFFmalloc(sizeof (C_cell));
625 *(ColorCells + ir*C_LEN*C_LEN + ig*C_LEN + ib) = ptr;
626 ptr->num_ents = 0;
627
628 /*
629 * Step 1: find all colors inside this cell, while we're at
630 * it, find distance of centermost point to furthest corner
631 */
632 mindist = 99999999;
633 for (i = 0; i < num_colors; ++i) {
634 if (rm[i]>>(COLOR_DEPTH-C_DEPTH) != ir ||
635 gm[i]>>(COLOR_DEPTH-C_DEPTH) != ig ||
636 bm[i]>>(COLOR_DEPTH-C_DEPTH) != ib)
637 continue;
638 ptr->entries[ptr->num_ents][0] = i;
639 ptr->entries[ptr->num_ents][1] = 0;
640 ++ptr->num_ents;
641 tmp = rm[i] - red;
642 if (tmp < (MAX_COLOR/C_LEN/2))
643 tmp = MAX_COLOR/C_LEN-1 - tmp;
644 dist = tmp*tmp;
645 tmp = gm[i] - green;
646 if (tmp < (MAX_COLOR/C_LEN/2))
647 tmp = MAX_COLOR/C_LEN-1 - tmp;
648 dist += tmp*tmp;
649 tmp = bm[i] - blue;
650 if (tmp < (MAX_COLOR/C_LEN/2))
651 tmp = MAX_COLOR/C_LEN-1 - tmp;
652 dist += tmp*tmp;
653 if (dist < mindist)
654 mindist = dist;
655 }
656
657 /*
658 * Step 3: find all points within that distance to cell.
659 */
660 for (i = 0; i < num_colors; ++i) {
661 if (rm[i] >> (COLOR_DEPTH-C_DEPTH) == ir &&
662 gm[i] >> (COLOR_DEPTH-C_DEPTH) == ig &&
663 bm[i] >> (COLOR_DEPTH-C_DEPTH) == ib)
664 continue;
665 dist = 0;
666 if ((tmp = red - rm[i]) > 0 ||
667 (tmp = rm[i] - (red + MAX_COLOR/C_LEN-1)) > 0 )
668 dist += tmp*tmp;
669 if ((tmp = green - gm[i]) > 0 ||
670 (tmp = gm[i] - (green + MAX_COLOR/C_LEN-1)) > 0 )
671 dist += tmp*tmp;
672 if ((tmp = blue - bm[i]) > 0 ||
673 (tmp = bm[i] - (blue + MAX_COLOR/C_LEN-1)) > 0 )
674 dist += tmp*tmp;
675 if (dist < mindist) {
676 ptr->entries[ptr->num_ents][0] = i;
677 ptr->entries[ptr->num_ents][1] = dist;
678 ++ptr->num_ents;
679 }
680 }
681
682 /*
683 * Sort color cells by distance, use cheap exchange sort
684 */
685 for (n = ptr->num_ents - 1; n > 0; n = next_n) {
686 next_n = 0;
687 for (i = 0; i < n; ++i)
688 if (ptr->entries[i][1] > ptr->entries[i+1][1]) {
689 tmp = ptr->entries[i][0];
690 ptr->entries[i][0] = ptr->entries[i+1][0];
691 ptr->entries[i+1][0] = tmp;
692 tmp = ptr->entries[i][1];
693 ptr->entries[i][1] = ptr->entries[i+1][1];
694 ptr->entries[i+1][1] = tmp;
695 next_n = i;
696 }
697 }
698 return (ptr);
699 }
700
701 static void
702 map_colortable(void)
703 {
704 register uint32 *histp = &histogram[0][0][0];
705 register C_cell *cell;
706 register int j, tmp, d2, dist;
707 int ir, ig, ib, i;
708
709 for (ir = 0; ir < B_LEN; ++ir)
710 for (ig = 0; ig < B_LEN; ++ig)
711 for (ib = 0; ib < B_LEN; ++ib, histp++) {
712 if (*histp == 0) {
713 *histp = -1;
714 continue;
715 }
716 cell = *(ColorCells +
717 (((ir>>(B_DEPTH-C_DEPTH)) << C_DEPTH*2) +
718 ((ig>>(B_DEPTH-C_DEPTH)) << C_DEPTH) +
719 (ib>>(B_DEPTH-C_DEPTH))));
720 if (cell == NULL )
721 cell = create_colorcell(
722 ir << COLOR_SHIFT,
723 ig << COLOR_SHIFT,
724 ib << COLOR_SHIFT);
725 dist = 9999999;
726 for (i = 0; i < cell->num_ents &&
727 dist > cell->entries[i][1]; ++i) {
728 j = cell->entries[i][0];
729 d2 = rm[j] - (ir << COLOR_SHIFT);
730 d2 *= d2;
731 tmp = gm[j] - (ig << COLOR_SHIFT);
732 d2 += tmp*tmp;
733 tmp = bm[j] - (ib << COLOR_SHIFT);
734 d2 += tmp*tmp;
735 if (d2 < dist) {
736 dist = d2;
737 *histp = j;
738 }
739 }
740 }
741 }
742
743 /*
744 * straight quantization. Each pixel is mapped to the colors
745 * closest to it. Color values are rounded to the nearest color
746 * table entry.
747 */
748 static void
749 quant(TIFF* in, TIFF* out)
750 {
751 unsigned char *outline, *inputline;
752 register unsigned char *outptr, *inptr;
753 register uint32 i, j;
754 register int red, green, blue;
755
756 inputline = (unsigned char *)_TIFFmalloc(TIFFScanlineSize(in));
757 outline = (unsigned char *)_TIFFmalloc(imagewidth);
758 for (i = 0; i < imagelength; i++) {
759 if (TIFFReadScanline(in, inputline, i, 0) <= 0)
760 break;
761 inptr = inputline;
762 outptr = outline;
763 for (j = 0; j < imagewidth; j++) {
764 red = *inptr++ >> COLOR_SHIFT;
765 green = *inptr++ >> COLOR_SHIFT;
766 blue = *inptr++ >> COLOR_SHIFT;
767 *outptr++ = (unsigned char)histogram[red][green][blue];
768 }
769 if (TIFFWriteScanline(out, outline, i, 0) < 0)
770 break;
771 }
772 _TIFFfree(inputline);
773 _TIFFfree(outline);
774 }
775
776 #define SWAP(type,a,b) { type p; p = a; a = b; b = p; }
777
778 #define GetInputLine(tif, row, bad) \
779 if (TIFFReadScanline(tif, inputline, row, 0) <= 0) \
780 bad; \
781 inptr = inputline; \
782 nextptr = nextline; \
783 for (j = 0; j < imagewidth; ++j) { \
784 *nextptr++ = *inptr++; \
785 *nextptr++ = *inptr++; \
786 *nextptr++ = *inptr++; \
787 }
788 #define GetComponent(raw, cshift, c) \
789 cshift = raw; \
790 if (cshift < 0) \
791 cshift = 0; \
792 else if (cshift >= MAX_COLOR) \
793 cshift = MAX_COLOR-1; \
794 c = cshift; \
795 cshift >>= COLOR_SHIFT;
796
797 static void
798 quant_fsdither(TIFF* in, TIFF* out)
799 {
800 unsigned char *outline, *inputline, *inptr;
801 short *thisline, *nextline;
802 register unsigned char *outptr;
803 register short *thisptr, *nextptr;
804 register uint32 i, j;
805 uint32 imax, jmax;
806 int lastline, lastpixel;
807
808 imax = imagelength - 1;
809 jmax = imagewidth - 1;
810 inputline = (unsigned char *)_TIFFmalloc(TIFFScanlineSize(in));
811 thisline = (short *)_TIFFmalloc(imagewidth * 3 * sizeof (short));
812 nextline = (short *)_TIFFmalloc(imagewidth * 3 * sizeof (short));
813 outline = (unsigned char *) _TIFFmalloc(TIFFScanlineSize(out));
814
815 GetInputLine(in, 0, goto bad); /* get first line */
816 for (i = 1; i <= imagelength; ++i) {
817 SWAP(short *, thisline, nextline);
818 lastline = (i >= imax);
819 if (i <= imax)
820 GetInputLine(in, i, break);
821 thisptr = thisline;
822 nextptr = nextline;
823 outptr = outline;
824 for (j = 0; j < imagewidth; ++j) {
825 int red, green, blue;
826 register int oval, r2, g2, b2;
827
828 lastpixel = (j == jmax);
829 GetComponent(*thisptr++, r2, red);
830 GetComponent(*thisptr++, g2, green);
831 GetComponent(*thisptr++, b2, blue);
832 oval = histogram[r2][g2][b2];
833 if (oval == -1) {
834 int ci;
835 register int cj, tmp, d2, dist;
836 register C_cell *cell;
837
838 cell = *(ColorCells +
839 (((r2>>(B_DEPTH-C_DEPTH)) << C_DEPTH*2) +
840 ((g2>>(B_DEPTH-C_DEPTH)) << C_DEPTH ) +
841 (b2>>(B_DEPTH-C_DEPTH))));
842 if (cell == NULL)
843 cell = create_colorcell(red,
844 green, blue);
845 dist = 9999999;
846 for (ci = 0; ci < cell->num_ents && dist > cell->entries[ci][1]; ++ci) {
847 cj = cell->entries[ci][0];
848 d2 = (rm[cj] >> COLOR_SHIFT) - r2;
849 d2 *= d2;
850 tmp = (gm[cj] >> COLOR_SHIFT) - g2;
851 d2 += tmp*tmp;
852 tmp = (bm[cj] >> COLOR_SHIFT) - b2;
853 d2 += tmp*tmp;
854 if (d2 < dist) {
855 dist = d2;
856 oval = cj;
857 }
858 }
859 histogram[r2][g2][b2] = oval;
860 }
861 *outptr++ = oval;
862 red -= rm[oval];
863 green -= gm[oval];
864 blue -= bm[oval];
865 if (!lastpixel) {
866 thisptr[0] += blue * 7 / 16;
867 thisptr[1] += green * 7 / 16;
868 thisptr[2] += red * 7 / 16;
869 }
870 if (!lastline) {
871 if (j != 0) {
872 nextptr[-3] += blue * 3 / 16;
873 nextptr[-2] += green * 3 / 16;
874 nextptr[-1] += red * 3 / 16;
875 }
876 nextptr[0] += blue * 5 / 16;
877 nextptr[1] += green * 5 / 16;
878 nextptr[2] += red * 5 / 16;
879 if (!lastpixel) {
880 nextptr[3] += blue / 16;
881 nextptr[4] += green / 16;
882 nextptr[5] += red / 16;
883 }
884 nextptr += 3;
885 }
886 }
887 if (TIFFWriteScanline(out, outline, i-1, 0) < 0)
888 break;
889 }
890 bad:
891 _TIFFfree(inputline);
892 _TIFFfree(thisline);
893 _TIFFfree(nextline);
894 _TIFFfree(outline);
895 }