gbdk-2020 | GameBoy Development Kit |
| download: https://git.y1.nz/archives/gbdk.tar.gz | |
| README | Files | Log | Refs | LICENSE |
gbdk-support/png2hicolorgb/src/hicolor/median.c
1
2 #include <stdio.h>
3 #include <string.h>
4 #include <stdbool.h>
5 #include <stdint.h>
6
7 #include "defines.h"
8 #include "fsdither.h" // tables:
9 #include "median.h"
10
11 Color cmap[256]; // colormap created by quantization
12 int actual_number_of_colors; // Number of colors actually needed
13 Histogram histogram; // holds the histogram
14 ColorFreq AHistorgram[32768];
15 s32 Ared_n_row[60];
16 s32 Ared_p_row[60];
17 s32 Agrn_n_row[60];
18 s32 Agrn_p_row[60];
19 s32 Ablu_n_row[60];
20 s32 Ablu_p_row[60];
21 mbox Abox[4];
22 s32 Atable[514];
23 u8 Picture256[160*BUF_HEIGHT*3];
24 u8 QuantizedPalette[256][3];
25
26
27
28
29 void zero_histogram_rgb(void)
30 {
31 s32 r, g, b;
32
33 for (r = 0; r < HIST_R_ELEMS; r++)
34 for (g = 0; g < HIST_G_ELEMS; g++)
35 for (b = 0; b < HIST_B_ELEMS; b++)
36 histogram[r * MR + g * MG + b] = 0;
37 }
38
39
40
41 // Find the splittable box with the largest color population
42 // Returns 0 if no splittable boxes remain
43
44 boxptr find_biggest_color_pop(boxptr boxlist,s32 numboxes)
45 {
46 boxptr boxp;
47 s32 i;
48 s32 maxc = 0;
49 boxptr which = 0;
50
51 for (i = 0, boxp = boxlist; i < numboxes; i++, boxp++)
52 {
53 if (boxp->colorcount > maxc && boxp->volume > 0)
54 {
55 which = boxp;
56 maxc = boxp->colorcount;
57 }
58 }
59
60 return which;
61 }
62
63
64
65 // Find the splittable box with the largest (scaled) volume
66 // Returns 0 if no splittable boxes remain
67
68 boxptr find_biggest_volume(boxptr boxlist,s32 numboxes)
69 {
70 boxptr boxp;
71 s32 i;
72 s32 maxv = 0;
73 boxptr which = 0;
74
75 for (i = 0, boxp = boxlist; i < numboxes; i++, boxp++)
76 {
77 if (boxp->volume > maxv)
78 {
79 which = boxp;
80 maxv = boxp->volume;
81 }
82 }
83
84 return which;
85 }
86
87
88 // Shrink the min/max bounds of a box to enclose only nonzero elements,
89 // and recompute its volume and population
90
91 void update_box_rgb(boxptr boxp)
92 {
93 ColorFreq *histp;
94 s32 R, G, B;
95 s32 Rmin, Rmax, Gmin, Gmax, Bmin, Bmax;
96 s32 dist0, dist1, dist2;
97 s32 ccount;
98
99 Rmin = boxp->Rmin;
100 Rmax = boxp->Rmax;
101 Gmin = boxp->Gmin;
102 Gmax = boxp->Gmax;
103 Bmin = boxp->Bmin;
104 Bmax = boxp->Bmax;
105
106 if (Rmax > Rmin)
107 for (R = Rmin; R <= Rmax; R++)
108 for (G = Gmin; G <= Gmax; G++)
109 {
110 histp = histogram + R * MR + G * MG + Bmin;
111 for (B = Bmin; B <= Bmax; B++)
112 if (*histp++ != 0)
113 {
114 boxp->Rmin = Rmin = R;
115 goto have_Rmin;
116 }
117 }
118
119 have_Rmin:
120
121 if (Rmax > Rmin)
122 for (R = Rmax; R >= Rmin; R--)
123 for (G = Gmin; G <= Gmax; G++)
124 {
125 histp = histogram + R * MR + G * MG + Bmin;
126 for (B = Bmin; B <= Bmax; B++)
127 if (*histp++ != 0)
128 {
129 boxp->Rmax = Rmax = R;
130 goto have_Rmax;
131 }
132 }
133
134 have_Rmax:
135
136 if (Gmax > Gmin)
137 for (G = Gmin; G <= Gmax; G++)
138 for (R = Rmin; R <= Rmax; R++)
139 {
140 histp = histogram + R * MR + G * MG + Bmin;
141 for (B = Bmin; B <= Bmax; B++)
142 if (*histp++ != 0)
143 {
144 boxp->Gmin = Gmin = G;
145 goto have_Gmin;
146 }
147 }
148
149 have_Gmin:
150
151 if (Gmax > Gmin)
152 for (G = Gmax; G >= Gmin; G--)
153 for (R = Rmin; R <= Rmax; R++)
154 {
155 histp = histogram + R * MR + G * MG + Bmin;
156 for (B = Bmin; B <= Bmax; B++)
157 if (*histp++ != 0)
158 {
159 boxp->Gmax = Gmax = G;
160 goto have_Gmax;
161 }
162 }
163
164 have_Gmax:
165
166 if (Bmax > Bmin)
167 for (B = Bmin; B <= Bmax; B++)
168 for (R = Rmin; R <= Rmax; R++)
169 {
170 histp = histogram + R * MR + Gmin * MG + B;
171 for (G = Gmin; G <= Gmax; G++, histp += MG)
172 if (*histp != 0)
173 {
174 boxp->Bmin = Bmin = B;
175 goto have_Bmin;
176 }
177 }
178
179 have_Bmin:
180
181 if (Bmax > Bmin)
182 for (B = Bmax; B >= Bmin; B--)
183 for (R = Rmin; R <= Rmax; R++)
184 {
185 histp = histogram + R * MR + Gmin * MG + B;
186 for (G = Gmin; G <= Gmax; G++, histp += MG)
187 if (*histp != 0)
188 {
189 boxp->Bmax = Bmax = B;
190 goto have_Bmax;
191 }
192 }
193
194 have_Bmax:
195
196 // Update box volume.
197 // We use 2-norm rather than real volume here; this biases the method
198 // against making long narrow boxes, and it has the side benefit that
199 // a box is splittable iff norm > 0.
200 // Since the differences are expressed in histogram-cell units,
201 // we have to shift back to JSAMPLE units to get consistent distances;
202 // after which, we scale according to the selected distance scale factors.
203
204 dist0 = ((Rmax - Rmin) << R_SHIFT) R_SCALE;
205 dist1 = ((Gmax - Gmin) << G_SHIFT) G_SCALE;
206 dist2 = ((Bmax - Bmin) << B_SHIFT) B_SCALE;
207 boxp->volume = dist0 * dist0 + dist1 * dist1 + dist2 * dist2;
208
209 // Now scan remaining volume of box and compute population
210 ccount = 0;
211 for (R = Rmin; R <= Rmax; R++)
212 {
213 for (G = Gmin; G <= Gmax; G++)
214 {
215 histp = histogram + R * MR + G * MG + Bmin;
216 for (B = Bmin; B <= Bmax; B++, histp++)
217 if (*histp != 0)
218 {
219 ccount++;
220 }
221 }
222 }
223
224 boxp->colorcount = ccount;
225 }
226
227
228 // Repeatedly select and split the largest box until we have enough boxes
229
230 s32 median_cut_rgb(boxptr boxlist,s32 numboxes)
231 {
232 s32 n, lb;
233 s32 R, G, B, cmax;
234 boxptr b1, b2;
235
236 while (numboxes < 4)
237 {
238 // Select box to split. Current algorithm: by population for first half, then by volume.
239 if (numboxes * 2 <= 4)
240 b1 = find_biggest_color_pop(boxlist, numboxes);
241 else
242 b1 = find_biggest_volume(boxlist, numboxes);
243
244 if (b1 == 0) /* no splittable boxes left! */
245 break;
246
247 b2 = boxlist + numboxes; // where new box will go
248 b2->Rmax = b1->Rmax; // Copy the color bounds to the new box.
249 b2->Gmax = b1->Gmax;
250 b2->Bmax = b1->Bmax;
251 b2->Rmin = b1->Rmin;
252 b2->Gmin = b1->Gmin;
253 b2->Bmin = b1->Bmin;
254
255 // Choose which axis to split the box on Current algorithm: longest scaled axis.
256 // See notes in update_box about scaling distances.
257
258 R = ((b1->Rmax - b1->Rmin) << R_SHIFT) R_SCALE;
259 G = ((b1->Gmax - b1->Gmin) << G_SHIFT) G_SCALE;
260 B = ((b1->Bmax - b1->Bmin) << B_SHIFT) B_SCALE;
261
262 // We want to break any ties in favor of green, then red, blue last.
263
264 cmax = G;
265 n = 1;
266
267 if (R > cmax)
268 {
269 cmax = R;
270 n = 0;
271 }
272
273 if (B > cmax)
274 n = 2;
275
276 // Choose split point along selected axis, and update box bounds.
277 // Current algorithm: split at halfway point.
278 // (Since the box has been shrunk to minimum volume,
279 // any split will produce two nonempty subboxes.)
280 // Note that lb value is max for lower box, so must be < old max.
281
282 switch (n)
283 {
284 case 0:
285
286 lb = (b1->Rmax + b1->Rmin) / 2;
287 b1->Rmax = lb;
288 b2->Rmin = lb + 1;
289 break;
290
291 case 1:
292
293 lb = (b1->Gmax + b1->Gmin) / 2;
294 b1->Gmax = lb;
295 b2->Gmin = lb + 1;
296 break;
297
298 case 2:
299
300 lb = (b1->Bmax + b1->Bmin) / 2;
301 b1->Bmax = lb;
302 b2->Bmin = lb + 1;
303 break;
304 }
305
306 // Update stats for boxes
307 update_box_rgb(b1);
308 update_box_rgb(b2);
309 numboxes++;
310 }
311
312 return numboxes;
313 }
314
315 // Compute representative color for a box, put it in colormap[icolor]
316
317 void compute_color_rgb(boxptr boxp,s32 icolor)
318 {
319 // Current algorithm: mean weighted by pixels (not colors)
320 // Note it is important to get the rounding correct!
321 ColorFreq *histp;
322 s32 R, G, B;
323 s32 Rmin, Rmax;
324 s32 Gmin, Gmax;
325 s32 Bmin, Bmax;
326 s32 count;
327 s32 total = 0;
328 s32 Rtotal = 0;
329 s32 Gtotal = 0;
330 s32 Btotal = 0;
331
332 Rmin = boxp->Rmin;
333 Rmax = boxp->Rmax;
334 Gmin = boxp->Gmin;
335 Gmax = boxp->Gmax;
336 Bmin = boxp->Bmin;
337 Bmax = boxp->Bmax;
338
339 for (R = Rmin; R <= Rmax; R++)
340 {
341 for (G = Gmin; G <= Gmax; G++)
342 {
343 histp = histogram + R * MR + G * MG + Bmin;
344 for (B = Bmin; B <= Bmax; B++)
345 {
346 if ((count = *histp++) != 0)
347 {
348 total += count;
349 Rtotal += ((R << R_SHIFT) + ((1 << R_SHIFT) >> 1)) * count;
350 Gtotal += ((G << G_SHIFT) + ((1 << G_SHIFT) >> 1)) * count;
351 Btotal += ((B << B_SHIFT) + ((1 << B_SHIFT) >> 1)) * count;
352 }
353 }
354 }
355 }
356
357 cmap[icolor].red = (Rtotal + (total >> 1)) / total;
358 cmap[icolor].green = (Gtotal + (total >> 1)) / total;
359 cmap[icolor].blue = (Btotal + (total >> 1)) / total;
360 }
361
362
363 #define BOX_R_LOG (PRECISION_R-3)
364 #define BOX_G_LOG (PRECISION_G-3)
365 #define BOX_B_LOG (PRECISION_B-3)
366
367 #define BOX_R_ELEMS (1<<BOX_R_LOG)
368 #define BOX_G_ELEMS (1<<BOX_G_LOG)
369 #define BOX_B_ELEMS (1<<BOX_B_LOG)
370
371 #define BOX_R_SHIFT (R_SHIFT + BOX_R_LOG)
372 #define BOX_G_SHIFT (G_SHIFT + BOX_G_LOG)
373 #define BOX_B_SHIFT (B_SHIFT + BOX_B_LOG)
374
375 /*
376 * The next three routines implement inverse colormap filling. They could
377 * all be folded into one big routine, but splitting them up this way saves
378 * some stack space (the mindist[] and bestdist[] arrays need not coexist)
379 * and may allow some compilers to produce better code by registerizing more
380 * inner-loop variables.
381 */
382
383 s32 find_nearby_colors(s32 minR,s32 minG,s32 minB,s32 colorlist[])
384 /* Locate the colormap entries close enough to an update box to be candidates
385 * for the nearest entry to some cell(s) in the update box. The update box
386 * is specified by the center coordinates of its first cell. The number of
387 * candidate colormap entries is returned, and their colormap indexes are
388 * placed in colorlist[].
389 * This routine uses Heckbert's "locally sorted search" criterion to select
390 * the colors that need further consideration.
391 */
392 {
393 s32 maxR, maxG, maxB;
394 s32 centerR, centerG, centerB;
395 s32 i, x, ncolors;
396 s32 minmaxdist, min_dist, max_dist, tdist;
397 s32 mindist[MAXNUMCOLORS]; /* min distance to colormap entry i */
398
399 /* Compute true coordinates of update box's upper corner and center.
400 * Actually we compute the coordinates of the center of the upper-corner
401 * histogram cell, which are the upper bounds of the volume we care about.
402 * Note that since ">>" rounds down, the "center" values may be closer to
403 * min than to max; hence comparisons to them must be "<=", not "<".
404 */
405
406 maxR = minR + ((1 << BOX_R_SHIFT) - (1 << R_SHIFT));
407 centerR = (minR + maxR) >> 1;
408 maxG = minG + ((1 << BOX_G_SHIFT) - (1 << G_SHIFT));
409 centerG = (minG + maxG) >> 1;
410 maxB = minB + ((1 << BOX_B_SHIFT) - (1 << B_SHIFT));
411 centerB = (minB + maxB) >> 1;
412
413 /* For each color in colormap, find:
414 * 1. its minimum squared-distance to any point in the update box
415 * (zero if color is within update box);
416 * 2. its maximum squared-distance to any point in the update box.
417 * Both of these can be found by considering only the corners of the box.
418 * We save the minimum distance for each color in mindist[];
419 * only the smallest maximum distance is of interest.
420 */
421
422 minmaxdist = 0x7FFFFFFFL;
423
424 for (i = 0; i < actual_number_of_colors; i++)
425 {
426 // We compute the squared-R-distance term, then add in the other two.
427 x = cmap[i].red;
428
429 if (x < minR)
430 {
431 tdist = (x - minR) R_SCALE;
432 min_dist = tdist * tdist;
433 tdist = (x - maxR) R_SCALE;
434 max_dist = tdist * tdist;
435 }
436 else if (x > maxR)
437 {
438 tdist = (x - maxR) R_SCALE;
439 min_dist = tdist * tdist;
440 tdist = (x - minR) R_SCALE;
441 max_dist = tdist * tdist;
442 }
443 else
444 {
445 /* within cell range so no contribution to min_dist */
446 min_dist = 0;
447 if (x <= centerR)
448 {
449 tdist = (x - maxR) R_SCALE;
450 max_dist = tdist * tdist;
451 }
452 else
453 {
454 tdist = (x - minR) R_SCALE;
455 max_dist = tdist * tdist;
456 }
457 }
458
459 x = cmap[i].green;
460
461 if (x < minG)
462 {
463 tdist = (x - minG) G_SCALE;
464 min_dist += tdist * tdist;
465 tdist = (x - maxG) G_SCALE;
466 max_dist += tdist * tdist;
467 }
468 else if (x > maxG)
469 {
470 tdist = (x - maxG) G_SCALE;
471 min_dist += tdist * tdist;
472 tdist = (x - minG) G_SCALE;
473 max_dist += tdist * tdist;
474 }
475 else
476 {
477 // within cell range so no contribution to min_dist
478 if (x <= centerG)
479 {
480 tdist = (x - maxG) G_SCALE;
481 max_dist += tdist * tdist;
482 }
483 else
484 {
485 tdist = (x - minG) G_SCALE;
486 max_dist += tdist * tdist;
487 }
488 }
489
490 x = cmap[i].blue;
491
492 if (x < minB)
493 {
494 tdist = (x - minB) B_SCALE;
495 min_dist += tdist * tdist;
496 tdist = (x - maxB) B_SCALE;
497 max_dist += tdist * tdist;
498 }
499 else if (x > maxB)
500 {
501 tdist = (x - maxB) B_SCALE;
502 min_dist += tdist * tdist;
503 tdist = (x - minB) B_SCALE;
504 max_dist += tdist * tdist;
505 }
506 else
507 {
508 // within cell range so no contribution to min_dist
509 if (x <= centerB)
510 {
511 tdist = (x - maxB) B_SCALE;
512 max_dist += tdist * tdist;
513 }
514 else
515 {
516 tdist = (x - minB) B_SCALE;
517 max_dist += tdist * tdist;
518 }
519 }
520
521 mindist[i] = min_dist; // save away the results
522 if (max_dist < minmaxdist)
523 minmaxdist = max_dist;
524 }
525
526 // Now we know that no cell in the update box is more than minmaxdist
527 // away from some colormap entry. Therefore, only colors that are
528 // within minmaxdist of some part of the box need be considered.
529
530 ncolors = 0;
531
532 for (i = 0; i < actual_number_of_colors; i++)
533 {
534 if (mindist[i] <= minmaxdist)
535 colorlist[ncolors++] = i;
536 }
537
538 return ncolors;
539 }
540
541
542 /* Find the closest colormap entry for each cell in the update box,
543 given the list of candidate colors prepared by find_nearby_colors.
544 Return the indexes of the closest entries in the bestcolor[] array.
545 This routine uses Thomas' incremental distance calculation method to
546 find the distance from a colormap entry to successive cells in the box.
547 */
548 void find_best_colors(s32 minR, s32 minG, s32 minB,s32 numcolors,s32 colorlist[],s32 bestcolor[])
549 {
550 s32 iR, iG, iB;
551 s32 i, icolor;
552 s32 *bptr; /* pointer into bestdist[] array */
553 s32 *cptr; /* pointer into bestcolor[] array */
554 s32 dist0, dist1; /* initial distance values */
555 s32 dist2; /* current distance in inner loop */
556 s32 xx0, xx1; /* distance increments */
557 s32 xx2;
558 s32 inR, inG, inB; /* initial values for increments */
559
560 // This array holds the distance to the nearest-so-far color for each cell */
561 int bestdist[BOX_R_ELEMS * BOX_G_ELEMS * BOX_B_ELEMS];
562
563 // Initialize best-distance for each cell of the update box */
564 bptr = bestdist;
565
566 for (i = BOX_R_ELEMS * BOX_G_ELEMS * BOX_B_ELEMS - 1; i >= 0; i--)
567 *bptr++ = 0x7FFFFFFFL;
568
569 // For each color selected by find_nearby_colors,
570 // compute its distance to the center of each cell in the box.
571 // If that's less than best-so-far, update best distance and color number.
572
573
574 // Nominal steps between cell centers ("x" in Thomas article) */
575
576 #define STEP_R ((1 << R_SHIFT) R_SCALE)
577 #define STEP_G ((1 << G_SHIFT) G_SCALE)
578 #define STEP_B ((1 << B_SHIFT) B_SCALE)
579
580 for (i = 0; i < numcolors; i++)
581 {
582 icolor = colorlist[i];
583 // Compute (square of) distance from minR/G/B to this color
584 inR = (minR - cmap[icolor].red) R_SCALE;
585 dist0 = inR * inR;
586 inG = (minG - cmap[icolor].green) G_SCALE;
587 dist0 += inG * inG;
588 inB = (minB - cmap[icolor].blue) B_SCALE;
589 dist0 += inB * inB;
590
591 // Form the initial difference increments
592 inR = inR * (2 * STEP_R) + STEP_R * STEP_R;
593 inG = inG * (2 * STEP_G) + STEP_G * STEP_G;
594 inB = inB * (2 * STEP_B) + STEP_B * STEP_B;
595
596 // Now loop over all cells in box, updating distance per Thomas method
597 bptr = bestdist;
598 cptr = bestcolor;
599 xx0 = inR;
600 for (iR = BOX_R_ELEMS - 1; iR >= 0; iR--)
601 {
602 dist1 = dist0;
603 xx1 = inG;
604 for (iG = BOX_G_ELEMS - 1; iG >= 0; iG--)
605 {
606 dist2 = dist1;
607 xx2 = inB;
608 for (iB = BOX_B_ELEMS - 1; iB >= 0; iB--)
609 {
610 if (dist2 < *bptr)
611 {
612 *bptr = dist2;
613 *cptr = icolor;
614 }
615
616 dist2 += xx2;
617 xx2 += 2 * STEP_B * STEP_B;
618 bptr++;
619 cptr++;
620 }
621
622 dist1 += xx1;
623 xx1 += 2 * STEP_G * STEP_G;
624 }
625 dist0 += xx0;
626 xx0 += 2 * STEP_R * STEP_R;
627 }
628 }
629 }
630
631
632 // Fill the inverse-colormap entries in the update box that contains
633 // histogram cell R/G/B. (Only that one cell MUST be filled, but
634 // we can fill as many others as we wish.)
635
636 void fill_inverse_cmap_rgb(s32 R, s32 G, s32 B)
637 {
638 s32 minR, minG, minB; /* lower left corner of update box */
639 s32 iR, iG, iB;
640 s32 *cptr; /* pointer into bestcolor[] array */
641 ColorFreq *cachep; /* pointer into main cache array */
642 /* This array lists the candidate colormap indexes. */
643 s32 colorlist[MAXNUMCOLORS];
644 s32 numcolors; /* number of candidate colors */
645 /* This array holds the actually closest colormap index for each cell. */
646 s32 bestcolor[BOX_R_ELEMS * BOX_G_ELEMS * BOX_B_ELEMS];
647
648 /* Convert cell coordinates to update box ID */
649 R >>= BOX_R_LOG;
650 G >>= BOX_G_LOG;
651 B >>= BOX_B_LOG;
652
653 /* Compute true coordinates of update box's origin corner.
654 * Actually we compute the coordinates of the center of the corner
655 * histogram cell, which are the lower bounds of the volume we care about.
656 */
657
658 minR = (R << BOX_R_SHIFT) + ((1 << R_SHIFT) >> 1);
659 minG = (G << BOX_G_SHIFT) + ((1 << G_SHIFT) >> 1);
660 minB = (B << BOX_B_SHIFT) + ((1 << B_SHIFT) >> 1);
661
662 /* Determine which colormap entries are close enough to be candidates
663 * for the nearest entry to some cell in the update box.
664 */
665
666 numcolors = find_nearby_colors(minR, minG, minB, colorlist);
667
668 /* Determine the actually nearest colors. */
669 find_best_colors(minR, minG, minB, numcolors, colorlist,bestcolor);
670
671 /* Save the best color numbers (plus 1) in the main cache array */
672 R <<= BOX_R_LOG; /* convert ID back to base cell indexes */
673 G <<= BOX_G_LOG;
674 B <<= BOX_B_LOG;
675
676 cptr = bestcolor;
677
678 for (iR = 0; iR < BOX_R_ELEMS; iR++)
679 {
680 for (iG = 0; iG < BOX_G_ELEMS; iG++)
681 {
682 cachep = &histogram[(R + iR) * MR + (G + iG) * MG + B];
683
684 for (iB = 0; iB < BOX_B_ELEMS; iB++)
685 {
686 *cachep++ = (*cptr++) + 1;
687 }
688 }
689 }
690 }
691
692
693
694
695 /* This is pass 1 */
696 void median_cut_pass1_rgb(u8 *src,s32 width,s32 height)
697 {
698 s32 num_elems;
699 ColorFreq *col;
700 boxptr boxlist;
701 s32 numboxes;
702 s32 i;
703
704 num_elems = width * height;
705 zero_histogram_rgb();
706
707 while (num_elems--)
708 {
709 col = &histogram[(src[0] >> R_SHIFT) * MR + (src[1] >> G_SHIFT) * MG + (src[2] >> B_SHIFT)];
710 (*col)++;
711 src += 3;
712 }
713
714 boxlist = (boxptr) Abox;
715
716 // Initialize one box containing whole space
717 numboxes = 1;
718 boxlist[0].Rmin = 0;
719 boxlist[0].Rmax = (1 << PRECISION_R) - 1;
720 boxlist[0].Gmin = 0;
721 boxlist[0].Gmax = (1 << PRECISION_G) - 1;
722 boxlist[0].Bmin = 0;
723 boxlist[0].Bmax = (1 << PRECISION_B) - 1;
724
725 // Shrink it to actually-used volume and set its statistics
726 update_box_rgb(boxlist);
727
728 // Perform median-cut to produce final box list
729 numboxes = median_cut_rgb(boxlist, numboxes);
730
731 actual_number_of_colors = numboxes;
732
733 // Compute the representative color for each box, fill colormap
734 for (i = 0; i < numboxes; i++)
735 compute_color_rgb(boxlist + i, i);
736 }
737
738
739 /* Map some rows of pixels to the output colormapped representation. */
740
741
742
743
744
745 /*
746 Initialize the error-limiting transfer function (lookup table).
747 The raw F-S error computation can potentially compute error values of up to
748 +- MAXJSAMPLE. But we want the maximum correction applied to a pixel to be
749 much less, otherwise obviously wrong pixels will be created. (Typical
750 effects include weird fringes at color-area boundaries, isolated bright
751 pixels in a dark area, etc.) The standard advice for avoiding this problem
752 is to ensure that the "corners" of the color cube are allocated as output
753 colors; then repeated errors in the same direction cannot cause cascading
754 error buildup. However, that only prevents the error from getting
755 completely out of hand; Aaron Giles reports that error limiting improves
756 the results even with corner colors allocated.
757
758 A simple clamping of the error values to about +- MAXJSAMPLE/8 works pretty
759 well, but the smoother transfer function used below is even better. Thanks
760 to Aaron Giles for this idea.
761 */
762
763 // Allocate and fill in the error_limiter table
764 s32 *init_error_limit(void)
765 {
766 s32 *table;
767 s32 in, out;
768
769 table = Atable;
770 table += 255; // so we can index -255 ... +255
771
772 // Map errors 1:1 up to +- 16
773 out = 0;
774 for (in = 0; in < 16; in++, out++)
775 {
776 table[in] = out;
777 table[-in] = -out;
778 }
779
780 // Map errors 1:2 up to +- 3*16
781 for (; in < 16 * 3; in++, out += (in & 1) ? 0 : 1)
782 {
783 table[in] = out;
784 table[-in] = -out;
785 }
786
787 // Clamp the rest to final out value (which is 32)
788 for (; in <= 255; in++)
789 {
790 table[in] = out;
791 table[-in] = -out;
792 }
793
794 return table;
795 }
796
797
798
799 void to_indexed(u8 *input,s32 dither,s32 width,s32 height)
800 {
801 s32 i, j;
802 u8 *src;
803 u8 *dest;
804 s32 r, g, b;
805 ColorFreq *cachep;
806 s32 row, col;
807
808 Color *color;
809 u8 *src_row;
810 u8 *dest_row;
811 s32 *error_limiter;
812 s16 *fs_err1, *fs_err2;
813 s16 *fs_err3, *fs_err4;
814 s32 *red_n_row, *red_p_row;
815 s32 *grn_n_row, *grn_p_row;
816 s32 *blu_n_row, *blu_p_row;
817 s32 *rnr, *rpr;
818 s32 *gnr, *gpr;
819 s32 *bnr, *bpr;
820 s32 *tmp;
821 s32 re, ge, be;
822 s32 index;
823 s32 rowstride;
824 s32 step_dest, step_src;
825 s32 odd_row;
826 u8 *range_limiter;
827
828 histogram = AHistorgram;
829
830 median_cut_pass1_rgb(input, width, height);
831
832 src=input;
833 dest=Picture256;
834 zero_histogram_rgb();
835
836 if(dither)
837 {
838 error_limiter = init_error_limit();
839 range_limiter = range_array + 256;
840
841 red_n_row = Ared_n_row;
842 red_p_row = Ared_p_row;
843 grn_n_row = Agrn_n_row;
844 grn_p_row = Agrn_p_row;
845 blu_n_row = Ablu_n_row;
846 blu_p_row = Ablu_p_row;
847
848 memset(red_p_row, 0, sizeof(int) * (width + 2));
849 memset(grn_p_row, 0, sizeof(int) * (width + 2));
850 memset(blu_p_row, 0, sizeof(int) * (width + 2));
851
852 fs_err1 = floyd_steinberg_error1 + 511;
853 fs_err2 = floyd_steinberg_error2 + 511;
854 fs_err3 = floyd_steinberg_error3 + 511;
855 fs_err4 = floyd_steinberg_error4 + 511;
856
857 src_row = src;
858 dest_row = dest;
859 rowstride = width * 3;
860 odd_row = 0;
861
862 for (row = 0; row < height; row++)
863 {
864 src = src_row;
865 dest = dest_row;
866
867 src_row += rowstride;
868 dest_row += width;
869
870 rnr = red_n_row;
871 gnr = grn_n_row;
872 bnr = blu_n_row;
873 rpr = red_p_row + 1;
874 gpr = grn_p_row + 1;
875 bpr = blu_p_row + 1;
876
877 if (odd_row)
878 {
879 step_dest = -1;
880 step_src = -3;
881
882 src += rowstride - 3;
883 dest += width - 1;
884
885 rnr += width + 1;
886 gnr += width + 1;
887 bnr += width + 1;
888 rpr += width;
889 gpr += width;
890 bpr += width;
891
892 *(rnr - 1) = *(gnr - 1) = *(bnr - 1) = 0;
893 }
894 else
895 {
896 step_dest = 1;
897 step_src = 3;
898
899 *(rnr + 1) = *(gnr + 1) = *(bnr + 1) = 0;
900 }
901
902 *rnr = *gnr = *bnr = 0;
903
904 for (col = 0; col < width; col++)
905 {
906 r = range_limiter[src[0] + error_limiter[*rpr]];
907 g = range_limiter[src[1] + error_limiter[*gpr]];
908 b = range_limiter[src[2] + error_limiter[*bpr]];
909
910 re = r >> R_SHIFT;
911 ge = g >> G_SHIFT;
912 be = b >> B_SHIFT;
913
914 cachep = &histogram[re * MR + ge * MG + be];
915
916 // If we have not seen this color before, find nearest colormap entry and update the cache
917 if (*cachep == 0)
918 fill_inverse_cmap_rgb(re, ge, be);
919
920 index = *cachep - 1;
921 *dest = index;
922
923 color = &cmap[index];
924 re = r - color->red;
925 ge = g - color->green;
926 be = b - color->blue;
927
928 if (odd_row)
929 {
930 *(--rpr) += fs_err1[re];
931 *(--gpr) += fs_err1[ge];
932 *(--bpr) += fs_err1[be];
933
934 *rnr-- += fs_err2[re];
935 *gnr-- += fs_err2[ge];
936 *bnr-- += fs_err2[be];
937
938 *rnr += fs_err3[re];
939 *gnr += fs_err3[ge];
940 *bnr += fs_err3[be];
941
942 *(rnr - 1) = fs_err4[re];
943 *(gnr - 1) = fs_err4[ge];
944 *(bnr - 1) = fs_err4[be];
945 }
946 else
947 {
948 *(++rpr) += fs_err1[re];
949 *(++gpr) += fs_err1[ge];
950 *(++bpr) += fs_err1[be];
951
952 *rnr++ += fs_err2[re];
953 *gnr++ += fs_err2[ge];
954 *bnr++ += fs_err2[be];
955
956 *rnr += fs_err3[re];
957 *gnr += fs_err3[ge];
958 *bnr += fs_err3[be];
959
960 *(rnr + 1) = fs_err4[re];
961 *(gnr + 1) = fs_err4[ge];
962 *(bnr + 1) = fs_err4[be];
963 }
964
965 dest += step_dest;
966 src += step_src;
967 }
968
969 tmp = red_n_row;
970 red_n_row = red_p_row;
971 red_p_row = tmp;
972
973 tmp = grn_n_row;
974 grn_n_row = grn_p_row;
975 grn_p_row = tmp;
976
977 tmp = blu_n_row;
978 blu_n_row = blu_p_row;
979 blu_p_row = tmp;
980
981 odd_row = !odd_row;
982 }
983
984 }
985 else
986 {
987 for (row = 0; row < height; row++)
988 {
989 for (col = 0; col < width; col++)
990 {
991 // get pixel value and index into the cache */
992 r = (*src++) >> R_SHIFT;
993 g = (*src++) >> G_SHIFT;
994 b = (*src++) >> B_SHIFT;
995
996 cachep = &histogram[r * MR + g * MG + b];
997
998 // If we have not seen this color before, find nearest colormap entry and update the cache
999 if (*cachep == 0)
1000 fill_inverse_cmap_rgb(r, g, b);
1001
1002 // Now emit the colormap index for this cell */
1003 *dest++ = (unsigned char)(*cachep - 1);
1004 }
1005
1006 }
1007 }
1008
1009 for (i = 0, j = 0; i < actual_number_of_colors; i++)
1010 {
1011 QuantizedPalette[j][0] = cmap[i].blue;
1012 QuantizedPalette[j][1] = cmap[i].green;
1013 QuantizedPalette[j++][2] = cmap[i].red;
1014 }
1015 }
1016
This webpage is intended to be an accessible preview of this repository. To get a fuller picture, clone it and use the git CLI.