git.y1.nz

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.