1 /* Image processing functions
2 Copyright (C) 1998 Jareth Hein
4 This file is part of SXEmacs
6 SXEmacs is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
11 SXEmacs is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>. */
20 /* Synched up with: Not in FSF. */
22 /* Original author: Jareth Hein */
24 /* Parts of this file are based on code from Sam Leffler's tiff library,
25 with the original copyright displayed here:
27 Copyright (c) 1988-1997 Sam Leffler
28 Copyright (c) 1991-1997 Silicon Graphics, Inc.
30 Permission to use, copy, modify, distribute, and sell this software and
31 its documentation for any purpose is hereby granted without fee, provided
32 that (i) the above copyright notices and this permission notice appear in
33 all copies of the software and related documentation, and (ii) the names of
34 Sam Leffler and Silicon Graphics may not be used in any advertising or
35 publicity relating to the software without the specific, prior written
36 permission of Sam Leffler and Silicon Graphics. */
38 /* Quantizing code based off of the paper
39 Color Image Quantization for Frame Buffer Display, Paul Heckbert,
40 Siggraph '82 proceedings, pp. 297-307 */
47 get_histogram(quant_table * qt, unsigned char *pic,
48 int width, int height, Colorbox * box)
50 register unsigned char *inptr;
51 register int red, green, blue;
54 box->rmin = box->gmin = box->bmin = 999;
55 box->rmax = box->gmax = box->bmax = -1;
56 box->total = width * height;
59 for (i = 0; i < height; i++) {
60 for (j = width; j-- > 0;) {
61 red = (*inptr++ >> COLOR_SHIFT) & COLOR_MASK;
62 green = (*inptr++ >> COLOR_SHIFT) & COLOR_MASK;
63 blue = (*inptr++ >> COLOR_SHIFT) & COLOR_MASK;
68 if (green < box->gmin)
70 if (green > box->gmax)
76 #if defined(DEBUG_SXEMACS) && DEBUG_SXEMACS
77 if( red < 0 || green < 0 || blue < 0 ||
78 ! (red < B_LEN && green < B_LEN && blue < B_LEN) ) {
82 qt->histogram[red][green][blue]++;
87 static Colorbox *largest_box(quant_table * qt)
89 register Colorbox *p, *b;
94 for (p = qt->usedboxes; p != NULL; p = p->next)
95 if ((p->rmax > p->rmin || p->gmax > p->gmin ||
96 p->bmax > p->bmin) && p->total > size)
97 size = (b = p)->total;
101 static void shrinkbox(quant_table * qt, Colorbox * box)
103 register int *histp, ir, ig, ib;
105 if (box->rmax > box->rmin) {
106 for (ir = box->rmin; ir <= box->rmax; ++ir)
107 for (ig = box->gmin; ig <= box->gmax; ++ig) {
108 histp = &(qt->histogram[ir][ig][box->bmin]);
109 for (ib = box->bmin; ib <= box->bmax; ++ib)
116 if (box->rmax > box->rmin)
117 for (ir = box->rmax; ir >= box->rmin; --ir)
118 for (ig = box->gmin; ig <= box->gmax; ++ig) {
120 &(qt->histogram[ir][ig][box->bmin]);
122 for (; ib <= box->bmax; ++ib)
130 if (box->gmax > box->gmin) {
131 for (ig = box->gmin; ig <= box->gmax; ++ig)
132 for (ir = box->rmin; ir <= box->rmax; ++ir) {
133 histp = &(qt->histogram[ir][ig][box->bmin]);
134 for (ib = box->bmin; ib <= box->bmax; ++ib)
141 if (box->gmax > box->gmin)
142 for (ig = box->gmax; ig >= box->gmin; --ig)
143 for (ir = box->rmin; ir <= box->rmax; ++ir) {
145 &(qt->histogram[ir][ig][box->bmin]);
147 for (; ib <= box->bmax; ++ib)
155 if (box->bmax > box->bmin) {
156 for (ib = box->bmin; ib <= box->bmax; ++ib)
157 for (ir = box->rmin; ir <= box->rmax; ++ir) {
158 histp = &(qt->histogram[ir][box->gmin][ib]);
159 for (ig = box->gmin; ig <= box->gmax; ++ig) {
168 if (box->bmax > box->bmin)
169 for (ib = box->bmax; ib >= box->bmin; --ib)
170 for (ir = box->rmin; ir <= box->rmax; ++ir) {
172 &(qt->histogram[ir][box->gmin][ib]);
174 for (; ig <= box->gmax; ++ig) {
187 static void splitbox(quant_table * qt, Colorbox * ptr)
190 int first = 0, last = 0;
191 register Colorbox *new;
192 register int *iptr, *histp;
194 register int ir, ig, ib;
195 register int sum, sum1, sum2;
196 enum { RED, GREEN, BLUE } axis;
199 * See which axis is the largest, do a histogram along that
200 * axis. Split at median point. Contract both new boxes to
201 * fit points and return
203 i = ptr->rmax - ptr->rmin;
204 if (i >= ptr->gmax - ptr->gmin && i >= ptr->bmax - ptr->bmin)
206 else if (ptr->gmax - ptr->gmin >= ptr->bmax - ptr->bmin)
210 /* get histogram along longest axis */
213 histp = &hist2[ptr->rmin];
214 for (ir = ptr->rmin; ir <= ptr->rmax; ++ir) {
216 for (ig = ptr->gmin; ig <= ptr->gmax; ++ig) {
217 iptr = &(qt->histogram[ir][ig][ptr->bmin]);
218 for (ib = ptr->bmin; ib <= ptr->bmax; ++ib)
227 histp = &hist2[ptr->gmin];
228 for (ig = ptr->gmin; ig <= ptr->gmax; ++ig) {
230 for (ir = ptr->rmin; ir <= ptr->rmax; ++ir) {
231 iptr = &(qt->histogram[ir][ig][ptr->bmin]);
232 for (ib = ptr->bmin; ib <= ptr->bmax; ++ib)
241 histp = &hist2[ptr->bmin];
242 for (ib = ptr->bmin; ib <= ptr->bmax; ++ib) {
244 for (ir = ptr->rmin; ir <= ptr->rmax; ++ir) {
245 iptr = &(qt->histogram[ir][ptr->gmin][ib]);
246 for (ig = ptr->gmin; ig <= ptr->gmax; ++ig) {
261 /* find median point */
262 sum2 = ptr->total / 2;
263 histp = &hist2[first];
265 for (i = first; i <= last && (sum += *histp++) < sum2; ++i) ;
269 /* Create new box, re-allocate points */
271 qt->freeboxes = new->next;
273 qt->freeboxes->prev = NULL;
275 qt->usedboxes->prev = new;
276 new->next = qt->usedboxes;
279 histp = &hist2[first];
280 for (sum1 = 0, j = first; j < i; j++)
282 for (sum2 = 0, j = i; j <= last; j++)
287 new->rmin = ptr->rmin;
288 new->rmax = ptr->rmax;
289 new->gmin = ptr->gmin;
290 new->gmax = ptr->gmax;
291 new->bmin = ptr->bmin;
292 new->bmax = ptr->bmax;
315 static C_cell *create_colorcell(quant_table * qt, int num_colors, int red,
318 register int ir, ig, ib, i;
319 register C_cell *ptr;
321 register int tmp, dist, n;
323 ir = red >> (COLOR_DEPTH - C_DEPTH);
324 ig = green >> (COLOR_DEPTH - C_DEPTH);
325 ib = blue >> (COLOR_DEPTH - C_DEPTH);
326 ptr = (C_cell *)xmalloc_atomic(sizeof(C_cell));
327 *(qt->ColorCells + ir * C_LEN * C_LEN + ig * C_LEN + ib) = ptr;
331 * Step 1: find all colors inside this cell, while we're at
332 * it, find distance of centermost point to furthest corner
335 for (i = 0; i < num_colors; ++i) {
336 if (qt->rm[i] >> (COLOR_DEPTH - C_DEPTH) != ir ||
337 qt->gm[i] >> (COLOR_DEPTH - C_DEPTH) != ig ||
338 qt->bm[i] >> (COLOR_DEPTH - C_DEPTH) != ib)
340 ptr->entries[ptr->num_ents][0] = i;
341 ptr->entries[ptr->num_ents][1] = 0;
343 tmp = qt->rm[i] - red;
344 if (tmp < (MAX_COLOR / C_LEN / 2))
345 tmp = MAX_COLOR / C_LEN - 1 - tmp;
347 tmp = qt->gm[i] - green;
348 if (tmp < (MAX_COLOR / C_LEN / 2))
349 tmp = MAX_COLOR / C_LEN - 1 - tmp;
351 tmp = qt->bm[i] - blue;
352 if (tmp < (MAX_COLOR / C_LEN / 2))
353 tmp = MAX_COLOR / C_LEN - 1 - tmp;
360 * Step 3: find all points within that distance to cell.
362 for (i = 0; i < num_colors; ++i) {
363 if (qt->rm[i] >> (COLOR_DEPTH - C_DEPTH) == ir &&
364 qt->gm[i] >> (COLOR_DEPTH - C_DEPTH) == ig &&
365 qt->bm[i] >> (COLOR_DEPTH - C_DEPTH) == ib)
368 if ((tmp = red - qt->rm[i]) > 0 ||
369 (tmp = qt->rm[i] - (red + MAX_COLOR / C_LEN - 1)) > 0)
371 if ((tmp = green - qt->gm[i]) > 0 ||
372 (tmp = qt->gm[i] - (green + MAX_COLOR / C_LEN - 1)) > 0)
374 if ((tmp = blue - qt->bm[i]) > 0 ||
375 (tmp = qt->bm[i] - (blue + MAX_COLOR / C_LEN - 1)) > 0)
377 if (dist < mindist) {
378 ptr->entries[ptr->num_ents][0] = i;
379 ptr->entries[ptr->num_ents][1] = dist;
385 * Sort color cells by distance, use cheap exchange sort
387 for (n = ptr->num_ents - 1; n > 0; n = next_n) {
389 for (i = 0; i < n; ++i)
390 if (ptr->entries[i][1] > ptr->entries[i + 1][1]) {
391 tmp = ptr->entries[i][0];
392 ptr->entries[i][0] = ptr->entries[i + 1][0];
393 ptr->entries[i + 1][0] = tmp;
394 tmp = ptr->entries[i][1];
395 ptr->entries[i][1] = ptr->entries[i + 1][1];
396 ptr->entries[i + 1][1] = tmp;
403 static int map_colortable(quant_table * qt, int num_colors)
405 register int *histp = &(qt->histogram[0][0][0]);
406 register C_cell *cell;
407 register int j, tmp, d2, dist;
410 for (ir = 0; ir < B_LEN; ++ir)
411 for (ig = 0; ig < B_LEN; ++ig)
412 for (ib = 0; ib < B_LEN; ++ib, histp++) {
417 cell = *(qt->ColorCells +
418 (((ir >> (B_DEPTH - C_DEPTH)) <<
420 ((ig >> (B_DEPTH - C_DEPTH)) <<
421 C_DEPTH) + (ib >> (B_DEPTH -
424 cell = create_colorcell(qt, num_colors,
431 if (cell == NULL) /* memory exhausted! punt! */
434 for (i = 0; i < cell->num_ents &&
435 dist > cell->entries[i][1]; ++i) {
436 j = cell->entries[i][0];
437 d2 = qt->rm[j] - (ir << COLOR_SHIFT);
439 tmp = qt->gm[j] - (ig << COLOR_SHIFT);
441 tmp = qt->bm[j] - (ib << COLOR_SHIFT);
452 quant_table *build_EImage_quantable(unsigned char *eimage, int width,
453 int height, int num_colors)
456 Colorbox *box_list, *ptr;
459 qt = (quant_table *)xmalloc_and_zero(sizeof(quant_table));
463 assert(num_colors < 257 && num_colors > 2);
465 * STEP 1: create empty boxes
467 qt->usedboxes = NULL;
468 box_list = qt->freeboxes = xnew_array(Colorbox, num_colors);
469 qt->freeboxes[0].next = &(qt->freeboxes[1]);
470 qt->freeboxes[0].prev = NULL;
471 for (i = 1; i < num_colors - 1; ++i) {
472 qt->freeboxes[i].next = &(qt->freeboxes[i + 1]);
473 qt->freeboxes[i].prev = &(qt->freeboxes[i - 1]);
475 qt->freeboxes[num_colors - 1].next = NULL;
476 qt->freeboxes[num_colors - 1].prev = &(qt->freeboxes[num_colors - 2]);
479 * STEP 2: get histogram, initialize first box
482 qt->freeboxes = ptr->next;
484 qt->freeboxes->prev = NULL;
485 ptr->next = qt->usedboxes;
488 ptr->next->prev = ptr;
489 get_histogram(qt, eimage, width, height, ptr);
492 * STEP 3: continually subdivide boxes until no more free
493 * boxes remain or until all colors assigned.
495 while (qt->freeboxes != NULL) {
496 ptr = largest_box(qt);
500 qt->freeboxes = NULL;
504 * STEP 4: assign colors to all boxes
506 for (i = 0, ptr = qt->usedboxes; ptr != NULL; ++i, ptr = ptr->next) {
507 qt->rm[i] = ((ptr->rmin + ptr->rmax) << COLOR_SHIFT) / 2;
508 qt->gm[i] = ((ptr->gmin + ptr->gmax) << COLOR_SHIFT) / 2;
509 qt->bm[i] = ((ptr->bmin + ptr->bmax) << COLOR_SHIFT) / 2;
510 qt->um[i] = ptr->total;
512 qt->num_active_colors = i;
514 /* We're done with the boxes now */
516 qt->freeboxes = qt->usedboxes = NULL;
519 * STEP 5: scan histogram and map all values to closest color
521 /* 5a: create cell list as described in Heckbert */
522 qt->ColorCells = xnew_array_and_zero(C_cell*, C_LEN * C_LEN * C_LEN);
523 /* 5b: create mapping from truncated pixel space to color
525 res = map_colortable(qt, num_colors);
527 /* 5c: done with ColorCells */
528 for (i = 0; i < C_LEN * C_LEN * C_LEN; i++) {
529 if (qt->ColorCells[i])
530 xfree(qt->ColorCells[i]);
532 xfree(qt->ColorCells);
535 /* we failed in memory allocation, so clean up an leave */