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
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+
3752static INT16 *
3853palette_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
4358palette_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