Skip to content

Commit 3eb5509

Browse files
committed
Use palette cache to figure out if we might have an exact match
1 parent be0d717 commit 3eb5509

1 file changed

Lines changed: 63 additions & 21 deletions

File tree

src/libImaging/ConvertToPalette.c

Lines changed: 63 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,14 @@
1111

1212
#include "Imaging.h"
1313

14+
#if defined(_MSC_VER)
15+
#define NOINLINE __declspec(noinline)
16+
#elif defined(__GNUC__)
17+
#define NOINLINE __attribute__((noinline))
18+
#else
19+
#define NOINLINE
20+
#endif
21+
1422
/*
1523
* The coarse colour mapping is loosely based on the corresponding code in
1624
* the IJG JPEG library by Thomas G. Lane. Original algorithms by
@@ -34,12 +42,19 @@
3442
#define BOX 8
3543
#define BOXVOLUME (BOX * BOX * BOX)
3644

45+
// PIL palettes may contain up to 256 entries.
46+
#define PALETTE_CACHE_INDEX_MASK 0xff
47+
// Cache entry is empty.
48+
#define PALETTE_CACHE_EMPTY 0x100
49+
// The box described by this cache entry may contain an exact palette color.
50+
#define PALETTE_CACHE_HAS_EXACT 0x200
51+
3752
static INT16 *
3853
palette_cache(ImagingPalette palette, int r, int g, int b) {
3954
return &palette->cache[(r >> 2) + (g >> 2) * 64 + (b >> 2) * 64 * 64];
4055
}
4156

42-
static void
57+
static NOINLINE void
4358
palette_cache_update(ImagingPalette palette, int r, int g, int b) {
4459
int i, j;
4560
unsigned int dmin[IMAGING_PALETTE_MAX_ENTRIES], dmax;
@@ -152,7 +167,8 @@ palette_cache_update(ImagingPalette palette, int r, int g, int b) {
152167
for (r = r0; r < r1; r += 4) {
153168
for (g = g0; g < g1; g += 4) {
154169
for (b = b0; b < b1; b += 4) {
155-
*palette_cache(palette, r, g, b) = c[j++];
170+
INT16 *cache = palette_cache(palette, r, g, b);
171+
*cache = c[j++] | (*cache & PALETTE_CACHE_HAS_EXACT);
156172
}
157173
}
158174
}
@@ -172,7 +188,17 @@ palette_cache_prepare(ImagingPalette palette) {
172188

173189
/* Mark all entries as empty */
174190
for (int i = 0; i < entries; i++) {
175-
palette->cache[i] = 0x100;
191+
palette->cache[i] = PALETTE_CACHE_EMPTY;
192+
}
193+
194+
/* Mark cells that might contain an exact palette colour. */
195+
for (int i = 0; i < palette->size; i++) {
196+
*palette_cache(
197+
palette,
198+
palette->palette[i * 4],
199+
palette->palette[i * 4 + 1],
200+
palette->palette[i * 4 + 2]
201+
) |= PALETTE_CACHE_HAS_EXACT;
176202
}
177203
}
178204

@@ -237,6 +263,38 @@ find_exact_color(const ExactColorHash ech, int r, int g, int b) {
237263
return -1;
238264
}
239265

266+
static int
267+
find_palette_color(
268+
ImagingPalette palette, const ExactColorHash ech, int r, int g, int b
269+
) {
270+
INT16 *cache = palette_cache(palette, r, g, b);
271+
INT16 cached = *cache;
272+
273+
if (cached <= PALETTE_CACHE_INDEX_MASK) {
274+
// Filled, and there is no possibility
275+
// for an exact color in this box,
276+
// so return the cached index.
277+
return cached;
278+
}
279+
280+
if (cached & PALETTE_CACHE_HAS_EXACT) {
281+
int palette_index = find_exact_color(ech, r, g, b);
282+
if (palette_index >= 0) {
283+
// Found it! We do _not_ update the palette cache,
284+
// because it's a relatively slow operation,
285+
// and we have the answer here already.
286+
return palette_index;
287+
}
288+
}
289+
290+
if (cached & PALETTE_CACHE_EMPTY) {
291+
palette_cache_update(palette, r, g, b);
292+
cached = *cache;
293+
}
294+
295+
return cached & PALETTE_CACHE_INDEX_MASK;
296+
}
297+
240298
#if defined(_MSC_VER)
241299
#pragma optimize("", off)
242300
#endif
@@ -316,15 +374,7 @@ topalette_colour_floyd_steinberg(
316374
g = CLIP8(in[1] + (g + e[3 + 1]) / 16);
317375
b = CLIP8(in[2] + (b + e[3 + 2]) / 16);
318376

319-
int palette_index = find_exact_color(ech, r, g, b);
320-
if (palette_index < 0) {
321-
/* get closest colour */
322-
INT16 *cache = palette_cache(palette, r, g, b);
323-
if (cache[0] == 0x100) {
324-
palette_cache_update(palette, r, g, b);
325-
}
326-
palette_index = cache[0];
327-
}
377+
int palette_index = find_palette_color(palette, ech, r, g, b);
328378
if (alpha) {
329379
UINT32 v =
330380
MAKE_UINT32(palette_index, palette_index, palette_index, 255);
@@ -394,15 +444,7 @@ topalette_colour_closest(
394444

395445
for (int x = 0; x < xsize; x++, in += 4) {
396446
int r = in[0], g = in[1], b = in[2];
397-
int palette_index = find_exact_color(ech, r, g, b);
398-
if (palette_index < 0) {
399-
/* get closest colour */
400-
INT16 *cache = palette_cache(palette, r, g, b);
401-
if (cache[0] == 0x100) {
402-
palette_cache_update(palette, r, g, b);
403-
}
404-
palette_index = cache[0];
405-
}
447+
int palette_index = find_palette_color(palette, ech, r, g, b);
406448
if (alpha) {
407449
UINT32 v =
408450
MAKE_UINT32(palette_index, palette_index, palette_index, 255);

0 commit comments

Comments
 (0)