|
1 | 1 | /* |
2 | 2 | * The Python Imaging Library |
3 | 3 | * |
4 | | - * See Convert.c for legacy history of this file. |
| 4 | + * See Convert.c and Palette.c for legacy history of this file. |
5 | 5 | * |
6 | 6 | * Copyright (c) 1997-2005 by Secret Labs AB. |
7 | 7 | * Copyright (c) 1995-1997 by Fredrik Lundh. |
|
11 | 11 |
|
12 | 12 | #include "Imaging.h" |
13 | 13 |
|
| 14 | +/* |
| 15 | + * The coarse colour mapping is loosely based on the corresponding code in |
| 16 | + * the IJG JPEG library by Thomas G. Lane. Original algorithms by |
| 17 | + * Paul Heckbert and Spencer W. Thomas. |
| 18 | + */ |
| 19 | + |
| 20 | +#define DIST(a, b, s) (a - b) * (a - b) * s |
| 21 | + |
| 22 | +#define RSCALE 1 |
| 23 | +#define GSCALE 1 |
| 24 | +#define BSCALE 1 |
| 25 | + |
| 26 | +#define RDIST(a, b) DIST(a, b, RSCALE *RSCALE) |
| 27 | +#define GDIST(a, b) DIST(a, b, GSCALE *GSCALE) |
| 28 | +#define BDIST(a, b) DIST(a, b, BSCALE *BSCALE) |
| 29 | + |
| 30 | +#define RSTEP (4 * RSCALE) |
| 31 | +#define GSTEP (4 * GSCALE) |
| 32 | +#define BSTEP (4 * BSCALE) |
| 33 | + |
| 34 | +#define BOX 8 |
| 35 | +#define BOXVOLUME (BOX * BOX * BOX) |
| 36 | + |
| 37 | +inline static INT16 * |
| 38 | +palette_cache(ImagingPalette palette, int r, int g, int b) { |
| 39 | + return &palette->cache[(r >> 2) + (g >> 2) * 64 + (b >> 2) * 64 * 64]; |
| 40 | +} |
| 41 | + |
| 42 | +static void |
| 43 | +palette_cache_update(ImagingPalette palette, int r, int g, int b) { |
| 44 | + int i, j; |
| 45 | + unsigned int dmin[IMAGING_PALETTE_MAX_ENTRIES], dmax; |
| 46 | + int r0, g0, b0; |
| 47 | + int r1, g1, b1; |
| 48 | + int rc, gc, bc; |
| 49 | + unsigned int d[BOXVOLUME]; |
| 50 | + UINT8 c[BOXVOLUME]; |
| 51 | + |
| 52 | + /* Get box boundaries for the given (r,g,b)-triplet. Each box |
| 53 | + covers eight cache slots (32 colour values, that is). */ |
| 54 | + |
| 55 | + r0 = r & 0xe0; |
| 56 | + r1 = r0 + 0x1f; |
| 57 | + rc = (r0 + r1) / 2; |
| 58 | + g0 = g & 0xe0; |
| 59 | + g1 = g0 + 0x1f; |
| 60 | + gc = (g0 + g1) / 2; |
| 61 | + b0 = b & 0xe0; |
| 62 | + b1 = b0 + 0x1f; |
| 63 | + bc = (b0 + b1) / 2; |
| 64 | + |
| 65 | + /* Step 1 -- Select relevant palette entries (after Heckbert) */ |
| 66 | + |
| 67 | + /* For each palette entry, calculate the min and max distances to |
| 68 | + * any position in the box given by the colour we're looking for. */ |
| 69 | + |
| 70 | + dmax = (unsigned int)~0; |
| 71 | + |
| 72 | + for (i = 0; i < palette->size; i++) { |
| 73 | + int r, g, b; |
| 74 | + unsigned int tmin, tmax; |
| 75 | + |
| 76 | + /* Find min and max distances to any point in the box */ |
| 77 | + r = palette->palette[i * 4 + 0]; |
| 78 | + tmin = (r < r0) ? RDIST(r, r0) : (r > r1) ? RDIST(r, r1) : 0; |
| 79 | + tmax = (r <= rc) ? RDIST(r, r1) : RDIST(r, r0); |
| 80 | + |
| 81 | + g = palette->palette[i * 4 + 1]; |
| 82 | + tmin += (g < g0) ? GDIST(g, g0) : (g > g1) ? GDIST(g, g1) : 0; |
| 83 | + tmax += (g <= gc) ? GDIST(g, g1) : GDIST(g, g0); |
| 84 | + |
| 85 | + b = palette->palette[i * 4 + 2]; |
| 86 | + tmin += (b < b0) ? BDIST(b, b0) : (b > b1) ? BDIST(b, b1) : 0; |
| 87 | + tmax += (b <= bc) ? BDIST(b, b1) : BDIST(b, b0); |
| 88 | + |
| 89 | + dmin[i] = tmin; |
| 90 | + if (tmax < dmax) { |
| 91 | + dmax = tmax; /* keep the smallest max distance only */ |
| 92 | + } |
| 93 | + } |
| 94 | + |
| 95 | + /* Step 2 -- Incrementally update cache slot (after Thomas) */ |
| 96 | + |
| 97 | + /* Find the box containing the nearest palette entry, and update |
| 98 | + * all slots in that box. We only check boxes for which the min |
| 99 | + * distance is less than or equal the smallest max distance */ |
| 100 | + |
| 101 | + for (i = 0; i < BOXVOLUME; i++) { |
| 102 | + d[i] = (unsigned int)~0; |
| 103 | + } |
| 104 | + |
| 105 | + for (i = 0; i < palette->size; i++) { |
| 106 | + if (dmin[i] <= dmax) { |
| 107 | + int rd, gd, bd; |
| 108 | + int ri, gi, bi; |
| 109 | + int rx, gx, bx; |
| 110 | + |
| 111 | + ri = (r0 - palette->palette[i * 4 + 0]) * RSCALE; |
| 112 | + gi = (g0 - palette->palette[i * 4 + 1]) * GSCALE; |
| 113 | + bi = (b0 - palette->palette[i * 4 + 2]) * BSCALE; |
| 114 | + |
| 115 | + rd = ri * ri + gi * gi + bi * bi; |
| 116 | + |
| 117 | + ri = ri * (2 * RSTEP) + RSTEP * RSTEP; |
| 118 | + gi = gi * (2 * GSTEP) + GSTEP * GSTEP; |
| 119 | + bi = bi * (2 * BSTEP) + BSTEP * BSTEP; |
| 120 | + |
| 121 | + rx = ri; |
| 122 | + for (r = j = 0; r < BOX; r++) { |
| 123 | + gd = rd; |
| 124 | + gx = gi; |
| 125 | + for (g = 0; g < BOX; g++) { |
| 126 | + bd = gd; |
| 127 | + bx = bi; |
| 128 | + for (b = 0; b < BOX; b++) { |
| 129 | + if ((unsigned int)bd < d[j]) { |
| 130 | + d[j] = bd; |
| 131 | + c[j] = (UINT8)i; |
| 132 | + } |
| 133 | + bd += bx; |
| 134 | + bx += 2 * BSTEP * BSTEP; |
| 135 | + j++; |
| 136 | + } |
| 137 | + gd += gx; |
| 138 | + gx += 2 * GSTEP * GSTEP; |
| 139 | + } |
| 140 | + rd += rx; |
| 141 | + rx += 2 * RSTEP * RSTEP; |
| 142 | + } |
| 143 | + } |
| 144 | + } |
| 145 | + |
| 146 | + /* Step 3 -- Update cache */ |
| 147 | + |
| 148 | + /* The c array now contains the closest match for each |
| 149 | + * cache slot in the box. Update the cache. */ |
| 150 | + |
| 151 | + j = 0; |
| 152 | + for (r = r0; r < r1; r += 4) { |
| 153 | + for (g = g0; g < g1; g += 4) { |
| 154 | + for (b = b0; b < b1; b += 4) { |
| 155 | + *palette_cache(palette, r, g, b) = c[j++]; |
| 156 | + } |
| 157 | + } |
| 158 | + } |
| 159 | +} |
| 160 | + |
| 161 | +static int |
| 162 | +palette_cache_prepare(ImagingPalette palette) { |
| 163 | + int entries = 64 * 64 * 64; |
| 164 | + |
| 165 | + if (palette->cache == NULL) { |
| 166 | + /* malloc check ok, small constant allocation */ |
| 167 | + palette->cache = (INT16 *)malloc(entries * sizeof(INT16)); |
| 168 | + if (!palette->cache) { |
| 169 | + (void)ImagingError_MemoryError(); |
| 170 | + return -1; |
| 171 | + } |
| 172 | + |
| 173 | + /* Mark all entries as empty */ |
| 174 | + for (int i = 0; i < entries; i++) { |
| 175 | + palette->cache[i] = 0x100; |
| 176 | + } |
| 177 | + } |
| 178 | + |
| 179 | + return 0; |
| 180 | +} |
| 181 | + |
14 | 182 | // The hash will always have up to 50% fill factor. |
15 | 183 | #define EXACT_COLOR_HASH_SIZE (IMAGING_PALETTE_MAX_ENTRIES * 2) |
16 | 184 |
|
@@ -151,9 +319,9 @@ topalette_colour_floyd_steinberg( |
151 | 319 | int palette_index = find_exact_color(ech, r, g, b); |
152 | 320 | if (palette_index < 0) { |
153 | 321 | /* get closest colour */ |
154 | | - INT16 *cache = &ImagingPaletteCache(palette, r, g, b); |
| 322 | + INT16 *cache = palette_cache(palette, r, g, b); |
155 | 323 | if (cache[0] == 0x100) { |
156 | | - ImagingPaletteCacheUpdate(palette, r, g, b); |
| 324 | + palette_cache_update(palette, r, g, b); |
157 | 325 | } |
158 | 326 | palette_index = cache[0]; |
159 | 327 | } |
@@ -229,9 +397,9 @@ topalette_colour_closest( |
229 | 397 | int palette_index = find_exact_color(ech, r, g, b); |
230 | 398 | if (palette_index < 0) { |
231 | 399 | /* get closest colour */ |
232 | | - INT16 *cache = &ImagingPaletteCache(palette, r, g, b); |
| 400 | + INT16 *cache = palette_cache(palette, r, g, b); |
233 | 401 | if (cache[0] == 0x100) { |
234 | | - ImagingPaletteCacheUpdate(palette, r, g, b); |
| 402 | + palette_cache_update(palette, r, g, b); |
235 | 403 | } |
236 | 404 | palette_index = cache[0]; |
237 | 405 | } |
@@ -303,7 +471,7 @@ topalette( |
303 | 471 | struct ExactColorHashInstance exact_color_hash; |
304 | 472 | prepare_exact_color_hash(palette, &exact_color_hash); |
305 | 473 |
|
306 | | - if (ImagingPaletteCachePrepare(palette) < 0) { |
| 474 | + if (palette_cache_prepare(palette) < 0) { |
307 | 475 | // Failed allocation for cache |
308 | 476 | ImagingDelete(imOut); |
309 | 477 | imOut = NULL; |
|
0 commit comments