/** \file * \brief RGB2Map Conversion * * See Copyright Notice in cd.h */ #include #include #include "cd.h" #define PARM(a) a typedef unsigned char byte; /* RANGE forces a to be in the range b..c (inclusive) */ #define RANGE(a,b,c) { if (a < b) a = b; if (a > c) a = c; } typedef unsigned long uu_long; typedef unsigned short uu_short; #define INT32 int #define TRUE 1 #define FALSE 0 static void xvbzero(char *s, size_t len) { for ( ; len>0; len--) *s++ = 0; } static void xvbcopy(char *src, char *dst, size_t len) { /* determine if the regions overlap * * 3 cases: src=dst, srcdst * * if src=dst, they overlap completely, but nothing needs to be moved * if srcdst then they overlap * if src>dst and srcdst) { /* do a backward copy */ src = src + len - 1; dst = dst + len - 1; for ( ; len>0; len--, src--, dst--) *dst = *src; } else { /* they either overlap (src>dst) or they don't overlap */ /* do a forward copy */ for ( ; len>0; len--, src++, dst++) *dst = *src; } } /****************************/ static int quick_map(const byte *red, const byte *green, const byte *blue, int w, int h, byte *map, byte *rmap, byte *gmap, byte *bmap, int *maxcol) { /* scans picture until it finds more than 'maxcol' different colors. If it finds more than 'maxcol' colors, it returns '0'. If it DOESN'T, it does the 24-to-8 conversion by simply sticking the colors it found into a colormap, and changing instances of a color in pic24 into colormap indicies (in pic8) */ unsigned long colors[256],col; int i, nc, low, high, mid; const byte *pred, *pgreen, *pblue; byte *pix; /* put the first color in the table by hand */ nc = 0; mid = 0; for (i=w*h,pred=red,pgreen=green,pblue=blue; i; i--) { col = (((uu_long) *pred++) << 16); col += (((uu_long) *pgreen++) << 8); col += *pblue++; /* binary search the 'colors' array to see if it's in there */ low = 0; high = nc-1; while (low <= high) { mid = (low+high)/2; if (col < colors[mid]) high = mid - 1; else if (col > colors[mid]) low = mid + 1; else break; } if (high < low) { /* didn't find color in list, add it. */ if (nc>=*maxcol) return 0; xvbcopy((char *) &colors[low], (char *) &colors[low+1], (nc - low) * sizeof(uu_long)); colors[low] = col; nc++; } } /* run through the data a second time, this time mapping pixel values in pic24 into colormap offsets into 'colors' */ for (i=w*h,pred=red,pgreen=green,pblue=blue, pix=map; i; i--,pix++) { col = (((uu_long) *pred++) << 16); col += (((uu_long) *pgreen++) << 8); col += *pblue++; /* binary search the 'colors' array. It *IS* in there */ low = 0; high = nc-1; while (low <= high) { mid = (low+high)/2; if (col < colors[mid]) high = mid - 1; else if (col > colors[mid]) low = mid + 1; else break; } if (high < low) return 0; *pix = (unsigned char)mid; } /* and load up the 'desired colormap' */ for (i=0; i>16); gmap[i] = (unsigned char)((colors[i]>>8) & 0xff); bmap[i] = (unsigned char)( colors[i] & 0xff); } *maxcol = nc; return 1; } /***************************************************************/ /* The following is based on jquant2.c from version 5 */ /* of the IJG JPEG software, which is */ /* Copyright (C) 1991-1994, Thomas G. Lane. */ /***************************************************************/ #define MAXNUMCOLORS 256 /* maximum size of colormap */ #define C0_SCALE 2 /* scale R distances by this much */ #define C1_SCALE 3 /* scale G distances by this much */ #define C2_SCALE 1 /* and B by this much */ #define HIST_C0_BITS 5 /* bits of precision in R histogram */ #define HIST_C1_BITS 6 /* bits of precision in G histogram */ #define HIST_C2_BITS 5 /* bits of precision in B histogram */ /* Number of elements along histogram axes. */ #define HIST_C0_ELEMS (1< 0) { /* get pixel value and index into the histogram */ histp = & histogram[*red >> C0_SHIFT] [*green >> C1_SHIFT] [*blue >> C2_SHIFT]; /* increment, check for overflow and undo increment if so. */ if (++(*histp) <= 0) (*histp)--; red++; green++; blue++; } } static boxptr find_biggest_color_pop (boxptr boxlist, int numboxes) { register boxptr boxp; register int i; register long maxc = 0; boxptr which = NULL; for (i = 0, boxp = boxlist; i < numboxes; i++, boxp++) { if (boxp->colorcount > maxc && boxp->volume > 0) { which = boxp; maxc = boxp->colorcount; } } return which; } static boxptr find_biggest_volume (boxptr boxlist, int numboxes) { register boxptr boxp; register int i; register INT32 maxv = 0; boxptr which = NULL; for (i = 0, boxp = boxlist; i < numboxes; i++, boxp++) { if (boxp->volume > maxv) { which = boxp; maxv = boxp->volume; } } return which; } static void update_box (boxptr boxp) { hist2d * histogram = sl_histogram; histptr histp; int c0,c1,c2; int c0min,c0max,c1min,c1max,c2min,c2max; INT32 dist0,dist1,dist2; long ccount; c0min = boxp->c0min; c0max = boxp->c0max; c1min = boxp->c1min; c1max = boxp->c1max; c2min = boxp->c2min; c2max = boxp->c2max; if (c0max > c0min) for (c0 = c0min; c0 <= c0max; c0++) for (c1 = c1min; c1 <= c1max; c1++) { histp = & histogram[c0][c1][c2min]; for (c2 = c2min; c2 <= c2max; c2++) if (*histp++ != 0) { boxp->c0min = c0min = c0; goto have_c0min; } } have_c0min: if (c0max > c0min) for (c0 = c0max; c0 >= c0min; c0--) for (c1 = c1min; c1 <= c1max; c1++) { histp = & histogram[c0][c1][c2min]; for (c2 = c2min; c2 <= c2max; c2++) if (*histp++ != 0) { boxp->c0max = c0max = c0; goto have_c0max; } } have_c0max: if (c1max > c1min) for (c1 = c1min; c1 <= c1max; c1++) for (c0 = c0min; c0 <= c0max; c0++) { histp = & histogram[c0][c1][c2min]; for (c2 = c2min; c2 <= c2max; c2++) if (*histp++ != 0) { boxp->c1min = c1min = c1; goto have_c1min; } } have_c1min: if (c1max > c1min) for (c1 = c1max; c1 >= c1min; c1--) for (c0 = c0min; c0 <= c0max; c0++) { histp = & histogram[c0][c1][c2min]; for (c2 = c2min; c2 <= c2max; c2++) if (*histp++ != 0) { boxp->c1max = c1max = c1; goto have_c1max; } } have_c1max: if (c2max > c2min) for (c2 = c2min; c2 <= c2max; c2++) for (c0 = c0min; c0 <= c0max; c0++) { histp = & histogram[c0][c1min][c2]; for (c1 = c1min; c1 <= c1max; c1++, histp += HIST_C2_ELEMS) if (*histp != 0) { boxp->c2min = c2min = c2; goto have_c2min; } } have_c2min: if (c2max > c2min) for (c2 = c2max; c2 >= c2min; c2--) for (c0 = c0min; c0 <= c0max; c0++) { histp = & histogram[c0][c1min][c2]; for (c1 = c1min; c1 <= c1max; c1++, histp += HIST_C2_ELEMS) if (*histp != 0) { boxp->c2max = c2max = c2; goto have_c2max; } } have_c2max: dist0 = ((c0max - c0min) << C0_SHIFT) * C0_SCALE; dist1 = ((c1max - c1min) << C1_SHIFT) * C1_SCALE; dist2 = ((c2max - c2min) << C2_SHIFT) * C2_SCALE; boxp->volume = dist0*dist0 + dist1*dist1 + dist2*dist2; ccount = 0; for (c0 = c0min; c0 <= c0max; c0++) for (c1 = c1min; c1 <= c1max; c1++) { histp = & histogram[c0][c1][c2min]; for (c2 = c2min; c2 <= c2max; c2++, histp++) if (*histp != 0) { ccount++; } } boxp->colorcount = ccount; } static int median_cut (boxptr boxlist, int numboxes, int desired_colors) { int n,lb; int c0,c1,c2,cmax; register boxptr b1,b2; while (numboxes < desired_colors) { /* Select box to split. * Current algorithm: by population for first half, then by volume. */ if (numboxes*2 <= desired_colors) { b1 = find_biggest_color_pop(boxlist, numboxes); } else { b1 = find_biggest_volume(boxlist, numboxes); } if (b1 == NULL) /* no splittable boxes left! */ break; b2 = &boxlist[numboxes]; /* where new box will go */ /* Copy the color bounds to the new box. */ b2->c0max = b1->c0max; b2->c1max = b1->c1max; b2->c2max = b1->c2max; b2->c0min = b1->c0min; b2->c1min = b1->c1min; b2->c2min = b1->c2min; /* Choose which axis to split the box on. */ c0 = ((b1->c0max - b1->c0min) << C0_SHIFT) * C0_SCALE; c1 = ((b1->c1max - b1->c1min) << C1_SHIFT) * C1_SCALE; c2 = ((b1->c2max - b1->c2min) << C2_SHIFT) * C2_SCALE; cmax = c1; n = 1; if (c0 > cmax) { cmax = c0; n = 0; } if (c2 > cmax) { n = 2; } switch (n) { case 0: lb = (b1->c0max + b1->c0min) / 2; b1->c0max = lb; b2->c0min = lb+1; break; case 1: lb = (b1->c1max + b1->c1min) / 2; b1->c1max = lb; b2->c1min = lb+1; break; case 2: lb = (b1->c2max + b1->c2min) / 2; b1->c2max = lb; b2->c2min = lb+1; break; } /* Update stats for boxes */ update_box(b1); update_box(b2); numboxes++; } return numboxes; } static void compute_color (boxptr boxp, int icolor) { /* Current algorithm: mean weighted by pixels (not colors) */ /* Note it is important to get the rounding correct! */ hist2d * histogram = sl_histogram; histptr histp; int c0,c1,c2; int c0min,c0max,c1min,c1max,c2min,c2max; long count; long total = 0; long c0total = 0; long c1total = 0; long c2total = 0; c0min = boxp->c0min; c0max = boxp->c0max; c1min = boxp->c1min; c1max = boxp->c1max; c2min = boxp->c2min; c2max = boxp->c2max; for (c0 = c0min; c0 <= c0max; c0++) for (c1 = c1min; c1 <= c1max; c1++) { histp = & histogram[c0][c1][c2min]; for (c2 = c2min; c2 <= c2max; c2++) { if ((count = *histp++) != 0) { total += count; c0total += ((c0 << C0_SHIFT) + ((1<>1)) * count; c1total += ((c1 << C1_SHIFT) + ((1<>1)) * count; c2total += ((c2 << C2_SHIFT) + ((1<>1)) * count; } } } sl_colormap[0][icolor] = (JSAMPLE) ((c0total + (total>>1)) / total); sl_colormap[1][icolor] = (JSAMPLE) ((c1total + (total>>1)) / total); sl_colormap[2][icolor] = (JSAMPLE) ((c2total + (total>>1)) / total); } static void slow_select_colors (int *descolors) /* Master routine for color selection */ { box boxlist[MAXNUMCOLORS]; int numboxes; int i; /* Initialize one box containing whole space */ numboxes = 1; boxlist[0].c0min = 0; boxlist[0].c0max = 255 >> C0_SHIFT; boxlist[0].c1min = 0; boxlist[0].c1max = 255 >> C1_SHIFT; boxlist[0].c2min = 0; boxlist[0].c2max = 255 >> C2_SHIFT; /* Shrink it to actually-used volume and set its statistics */ update_box(& boxlist[0]); /* Perform median-cut to produce final box list */ numboxes = median_cut(boxlist, numboxes, *descolors); /* Compute the representative color for each box, fill colormap */ for (i = 0; i < numboxes; i++) compute_color(& boxlist[i], i); sl_num_colors = numboxes; *descolors = sl_num_colors; } /* log2(histogram cells in update box) for each axis; this can be adjusted */ #define BOX_C0_LOG (HIST_C0_BITS-3) #define BOX_C1_LOG (HIST_C1_BITS-3) #define BOX_C2_LOG (HIST_C2_BITS-3) #define BOX_C0_ELEMS (1<> 1; maxc1 = minc1 + ((1 << BOX_C1_SHIFT) - (1 << C1_SHIFT)); centerc1 = (minc1 + maxc1) >> 1; maxc2 = minc2 + ((1 << BOX_C2_SHIFT) - (1 << C2_SHIFT)); centerc2 = (minc2 + maxc2) >> 1; minmaxdist = 0x7FFFFFFFL; for (i = 0; i < numcolors; i++) { /* We compute the squared-c0-distance term, then add in the other two. */ x = sl_colormap[0][i]; if (x < minc0) { tdist = (x - minc0) * C0_SCALE; min_dist = tdist*tdist; tdist = (x - maxc0) * C0_SCALE; max_dist = tdist*tdist; } else if (x > maxc0) { tdist = (x - maxc0) * C0_SCALE; min_dist = tdist*tdist; tdist = (x - minc0) * C0_SCALE; max_dist = tdist*tdist; } else { /* within cell range so no contribution to min_dist */ min_dist = 0; if (x <= centerc0) { tdist = (x - maxc0) * C0_SCALE; max_dist = tdist*tdist; } else { tdist = (x - minc0) * C0_SCALE; max_dist = tdist*tdist; } } x = sl_colormap[1][i]; if (x < minc1) { tdist = (x - minc1) * C1_SCALE; min_dist += tdist*tdist; tdist = (x - maxc1) * C1_SCALE; max_dist += tdist*tdist; } else if (x > maxc1) { tdist = (x - maxc1) * C1_SCALE; min_dist += tdist*tdist; tdist = (x - minc1) * C1_SCALE; max_dist += tdist*tdist; } else { /* within cell range so no contribution to min_dist */ if (x <= centerc1) { tdist = (x - maxc1) * C1_SCALE; max_dist += tdist*tdist; } else { tdist = (x - minc1) * C1_SCALE; max_dist += tdist*tdist; } } x = sl_colormap[2][i]; if (x < minc2) { tdist = (x - minc2) * C2_SCALE; min_dist += tdist*tdist; tdist = (x - maxc2) * C2_SCALE; max_dist += tdist*tdist; } else if (x > maxc2) { tdist = (x - maxc2) * C2_SCALE; min_dist += tdist*tdist; tdist = (x - minc2) * C2_SCALE; max_dist += tdist*tdist; } else { /* within cell range so no contribution to min_dist */ if (x <= centerc2) { tdist = (x - maxc2) * C2_SCALE; max_dist += tdist*tdist; } else { tdist = (x - minc2) * C2_SCALE; max_dist += tdist*tdist; } } mindist[i] = min_dist; /* save away the results */ if (max_dist < minmaxdist) minmaxdist = max_dist; } ncolors = 0; for (i = 0; i < numcolors; i++) { if (mindist[i] <= minmaxdist) colorlist[ncolors++] = (JSAMPLE) i; } return ncolors; } static void find_best_colors (int minc0, int minc1, int minc2, int numcolors, JSAMPLE colorlist[], JSAMPLE bestcolor[]) { int ic0, ic1, ic2; int i, icolor; register INT32 * bptr; /* pointer into bestdist[] array */ JSAMPLE * cptr; /* pointer into bestcolor[] array */ INT32 dist0, dist1; /* initial distance values */ register INT32 dist2; /* current distance in inner loop */ INT32 xx0, xx1; /* distance increments */ register INT32 xx2; INT32 inc0, inc1, inc2; /* initial values for increments */ /* This array holds the distance to the nearest-so-far color for each cell */ INT32 bestdist[BOX_C0_ELEMS * BOX_C1_ELEMS * BOX_C2_ELEMS]; /* Initialize best-distance for each cell of the update box */ bptr = bestdist; for (i = BOX_C0_ELEMS*BOX_C1_ELEMS*BOX_C2_ELEMS-1; i >= 0; i--) *bptr++ = 0x7FFFFFFFL; /* Nominal steps between cell centers ("x" in Thomas article) */ #define STEP_C0 ((1 << C0_SHIFT) * C0_SCALE) #define STEP_C1 ((1 << C1_SHIFT) * C1_SCALE) #define STEP_C2 ((1 << C2_SHIFT) * C2_SCALE) for (i = 0; i < numcolors; i++) { icolor = colorlist[i]; /* Compute (square of) distance from minc0/c1/c2 to this color */ inc0 = (minc0 - (int) sl_colormap[0][icolor]) * C0_SCALE; dist0 = inc0*inc0; inc1 = (minc1 - (int) sl_colormap[1][icolor]) * C1_SCALE; dist0 += inc1*inc1; inc2 = (minc2 - (int) sl_colormap[2][icolor]) * C2_SCALE; dist0 += inc2*inc2; /* Form the initial difference increments */ inc0 = inc0 * (2 * STEP_C0) + STEP_C0 * STEP_C0; inc1 = inc1 * (2 * STEP_C1) + STEP_C1 * STEP_C1; inc2 = inc2 * (2 * STEP_C2) + STEP_C2 * STEP_C2; /* Now loop over all cells in box, updating distance per Thomas method */ bptr = bestdist; cptr = bestcolor; xx0 = inc0; for (ic0 = BOX_C0_ELEMS-1; ic0 >= 0; ic0--) { dist1 = dist0; xx1 = inc1; for (ic1 = BOX_C1_ELEMS-1; ic1 >= 0; ic1--) { dist2 = dist1; xx2 = inc2; for (ic2 = BOX_C2_ELEMS-1; ic2 >= 0; ic2--) { if (dist2 < *bptr) { *bptr = dist2; *cptr = (JSAMPLE) icolor; } dist2 += xx2; xx2 += 2 * STEP_C2 * STEP_C2; bptr++; cptr++; } dist1 += xx1; xx1 += 2 * STEP_C1 * STEP_C1; } dist0 += xx0; xx0 += 2 * STEP_C0 * STEP_C0; } } } static void fill_inverse_cmap (int c0, int c1, int c2) { hist2d * histogram = sl_histogram; int minc0, minc1, minc2; /* lower left corner of update box */ int ic0, ic1, ic2; register JSAMPLE * cptr; /* pointer into bestcolor[] array */ register histptr cachep; /* pointer into main cache array */ /* This array lists the candidate colormap indexes. */ JSAMPLE colorlist[MAXNUMCOLORS]; int numcolors; /* number of candidate colors */ /* This array holds the actually closest colormap index for each cell. */ JSAMPLE bestcolor[BOX_C0_ELEMS * BOX_C1_ELEMS * BOX_C2_ELEMS]; /* Convert cell coordinates to update box ID */ c0 >>= BOX_C0_LOG; c1 >>= BOX_C1_LOG; c2 >>= BOX_C2_LOG; minc0 = (c0 << BOX_C0_SHIFT) + ((1 << C0_SHIFT) >> 1); minc1 = (c1 << BOX_C1_SHIFT) + ((1 << C1_SHIFT) >> 1); minc2 = (c2 << BOX_C2_SHIFT) + ((1 << C2_SHIFT) >> 1); numcolors = find_nearby_colors(minc0, minc1, minc2, colorlist); /* Determine the actually nearest colors. */ find_best_colors(minc0, minc1, minc2, numcolors, colorlist, bestcolor); /* Save the best color numbers (plus 1) in the main cache array */ c0 <<= BOX_C0_LOG; /* convert ID back to base cell indexes */ c1 <<= BOX_C1_LOG; c2 <<= BOX_C2_LOG; cptr = bestcolor; for (ic0 = 0; ic0 < BOX_C0_ELEMS; ic0++) { for (ic1 = 0; ic1 < BOX_C1_ELEMS; ic1++) { cachep = & histogram[c0+ic0][c1+ic1][c2]; for (ic2 = 0; ic2 < BOX_C2_ELEMS; ic2++) { *cachep++ = (histcell) (*cptr++ + 1); } } } } static void slow_map_pixels(const byte *red, const byte *green, const byte *blue, int width, int height, byte *map) { register LOCFSERROR cur0, cur1, cur2; /* current error or pixel value */ LOCFSERROR belowerr0, belowerr1, belowerr2; /* error for pixel below cur */ LOCFSERROR bpreverr0, bpreverr1, bpreverr2; /* error for below/prev col */ register FSERRPTR errorptr; /* => fserrors[] at column before current */ JSAMPROW inRptr, inGptr, inBptr; /* => current input pixel */ JSAMPROW outptr; /* => current output pixel */ histptr cachep; int dir; /* +1 or -1 depending on direction */ int dir3; /* 3*dir, for advancing errorptr */ int row, col, offset; int *error_limit = sl_error_limiter; JSAMPROW colormap0 = sl_colormap[0]; JSAMPROW colormap1 = sl_colormap[1]; JSAMPROW colormap2 = sl_colormap[2]; hist2d * histogram = sl_histogram; for (row = 0; row < height; row++) { offset = row * width; inRptr = (JSAMPROW)&red[offset]; inGptr = (JSAMPROW)&green[offset]; inBptr = (JSAMPROW)&blue[offset]; outptr = &map[offset]; if (sl_on_odd_row) { /* work right to left in this row */ offset = width-1; inRptr += offset; /* so point to rightmost pixel */ inGptr += offset; /* so point to rightmost pixel */ inBptr += offset; /* so point to rightmost pixel */ outptr += offset; dir = -1; dir3 = -3; errorptr = sl_fserrors + (width+1)*3; /* => entry after last column */ sl_on_odd_row = FALSE; /* flip for next time */ } else { /* work left to right in this row */ dir = 1; dir3 = 3; errorptr = sl_fserrors; /* => entry before first real column */ sl_on_odd_row = TRUE; /* flip for next time */ } /* Preset error values: no error propagated to first pixel from left */ cur0 = cur1 = cur2 = 0; /* and no error propagated to row below yet */ belowerr0 = belowerr1 = belowerr2 = 0; bpreverr0 = bpreverr1 = bpreverr2 = 0; for (col = width; col > 0; col--) { cur0 = (cur0 + errorptr[dir3+0] + 8) >> 4; cur1 = (cur1 + errorptr[dir3+1] + 8) >> 4; cur2 = (cur2 + errorptr[dir3+2] + 8) >> 4; cur0 = error_limit[cur0]; cur1 = error_limit[cur1]; cur2 = error_limit[cur2]; cur0 += inRptr[0]; cur1 += inGptr[0]; cur2 += inBptr[0]; RANGE(cur0, 0, 255); RANGE(cur1, 0, 255); RANGE(cur2, 0, 255); /* Index into the cache with adjusted pixel value */ cachep = & histogram[cur0>>C0_SHIFT][cur1>>C1_SHIFT][cur2>>C2_SHIFT]; /* If we have not seen this color before, find nearest colormap */ /* entry and update the cache */ if (*cachep == 0) fill_inverse_cmap(cur0>>C0_SHIFT, cur1>>C1_SHIFT, cur2>>C2_SHIFT); /* Now emit the colormap index for this cell */ { register int pixcode = *cachep - 1; *outptr = (JSAMPLE) pixcode; /* Compute representation error for this pixel */ cur0 -= (int) colormap0[pixcode]; cur1 -= (int) colormap1[pixcode]; cur2 -= (int) colormap2[pixcode]; } /* Compute error fractions to be propagated to adjacent pixels. * Add these into the running sums, and simultaneously shift the * next-line error sums left by 1 column. */ { register LOCFSERROR bnexterr, delta; bnexterr = cur0; /* Process component 0 */ delta = cur0 * 2; cur0 += delta; /* form error * 3 */ errorptr[0] = (FSERROR) (bpreverr0 + cur0); cur0 += delta; /* form error * 5 */ bpreverr0 = belowerr0 + cur0; belowerr0 = bnexterr; cur0 += delta; /* form error * 7 */ bnexterr = cur1; /* Process component 1 */ delta = cur1 * 2; cur1 += delta; /* form error * 3 */ errorptr[1] = (FSERROR) (bpreverr1 + cur1); cur1 += delta; /* form error * 5 */ bpreverr1 = belowerr1 + cur1; belowerr1 = bnexterr; cur1 += delta; /* form error * 7 */ bnexterr = cur2; /* Process component 2 */ delta = cur2 * 2; cur2 += delta; /* form error * 3 */ errorptr[2] = (FSERROR) (bpreverr2 + cur2); cur2 += delta; /* form error * 5 */ bpreverr2 = belowerr2 + cur2; belowerr2 = bnexterr; cur2 += delta; /* form error * 7 */ } /* At this point curN contains the 7/16 error value to be propagated * to the next pixel on the current line, and all the errors for the * next line have been shifted over. We are therefore ready to move on. */ inRptr += dir; /* Advance pixel pointers to next column */ inGptr += dir; /* Advance pixel pointers to next column */ inBptr += dir; /* Advance pixel pointers to next column */ outptr += dir; errorptr += dir3; /* advance errorptr to current column */ } /* Post-loop cleanup: we must unload the final error values into the * final fserrors[] entry. Note we need not unload belowerrN because * it is for the dummy column before or after the actual array. */ errorptr[0] = (FSERROR) bpreverr0; /* unload prev errs into array */ errorptr[1] = (FSERROR) bpreverr1; errorptr[2] = (FSERROR) bpreverr2; } } /* Allocate and fill in the error_limiter table */ static void init_error_limit (void) { int * table; int in, out, STEPSIZE; table = (int *) malloc((size_t) ((255*2+1) * sizeof(int))); if (! table) return; table += 255; /* so can index -255 .. +255 */ sl_error_limiter = table; STEPSIZE = ((255+1)/16); /* Map errors 1:1 up to +- 255/16 */ out = 0; for (in = 0; in < STEPSIZE; in++, out++) { table[in] = out; table[-in] = -out; } /* Map errors 1:2 up to +- 3*255/16 */ for (; in < STEPSIZE*3; in++, out += (in&1) ? 0 : 1) { table[in] = out; table[-in] = -out; } /* Clamp the rest to final out value (which is (255+1)/8) */ for (; in <= 255; in++) { table[in] = out; table[-in] = -out; } } void cdRGB2Map(int width, int height, const unsigned char *red, const unsigned char *green, const unsigned char *blue, unsigned char *map, int pal_size, long *colors) { int i, err; byte rm[256], gm[256], bm[256]; int num_colors; if (pal_size <= 0 || pal_size > 256) pal_size = 256; num_colors = pal_size; if (!quick_map(red, green, blue, width, height, map, rm, gm, bm, &num_colors)) { err = slow_quant(red, green, blue, width, height, map, rm, gm, bm, &num_colors); if (err) return; } for (i=0; i < num_colors; i++) *colors++ = cdEncodeColor(rm[i], gm[i], bm[i]); if (num_colors < pal_size) { for (i=num_colors; i < pal_size; i++) *colors++ = 0; } }