Pillow
307 строк · 8.1 Кб
1/*
2* The Python Imaging Library
3* $Id$
4*
5* imaging palette object
6*
7* history:
8* 1996-05-05 fl Added to library
9* 1996-05-27 fl Added colour mapping stuff
10* 1997-05-12 fl Support RGBA palettes
11* 2005-02-09 fl Removed grayscale entries from web palette
12*
13* Copyright (c) Secret Labs AB 1997-2005. All rights reserved.
14* Copyright (c) Fredrik Lundh 1995-1997.
15*
16* See the README file for information on usage and redistribution.
17*/
18
19#include "Imaging.h"
20
21#include <math.h>
22
23ImagingPalette
24ImagingPaletteNew(const char *mode) {
25/* Create a palette object */
26
27int i;
28ImagingPalette palette;
29
30if (strcmp(mode, "RGB") && strcmp(mode, "RGBA")) {
31return (ImagingPalette)ImagingError_ModeError();
32}
33
34palette = calloc(1, sizeof(struct ImagingPaletteInstance));
35if (!palette) {
36return (ImagingPalette)ImagingError_MemoryError();
37}
38
39strncpy(palette->mode, mode, IMAGING_MODE_LENGTH - 1);
40palette->mode[IMAGING_MODE_LENGTH - 1] = 0;
41
42palette->size = 0;
43for (i = 0; i < 256; i++) {
44palette->palette[i * 4 + 3] = 255; /* opaque */
45}
46
47return palette;
48}
49
50ImagingPalette
51ImagingPaletteNewBrowser(void) {
52/* Create a standard "browser" palette object */
53
54int i, r, g, b;
55ImagingPalette palette;
56
57palette = ImagingPaletteNew("RGB");
58if (!palette) {
59return NULL;
60}
61
62/* FIXME: Add 10-level windows palette here? */
63
64/* Simple 6x6x6 colour cube */
65i = 10;
66for (b = 0; b < 256; b += 51) {
67for (g = 0; g < 256; g += 51) {
68for (r = 0; r < 256; r += 51) {
69palette->palette[i * 4 + 0] = r;
70palette->palette[i * 4 + 1] = g;
71palette->palette[i * 4 + 2] = b;
72i++;
73}
74}
75}
76palette->size = i;
77
78/* FIXME: add 30-level grayscale wedge here? */
79
80return palette;
81}
82
83ImagingPalette
84ImagingPaletteDuplicate(ImagingPalette palette) {
85/* Duplicate palette descriptor */
86
87ImagingPalette new_palette;
88
89if (!palette) {
90return NULL;
91}
92/* malloc check ok, small constant allocation */
93new_palette = malloc(sizeof(struct ImagingPaletteInstance));
94if (!new_palette) {
95return (ImagingPalette)ImagingError_MemoryError();
96}
97
98memcpy(new_palette, palette, sizeof(struct ImagingPaletteInstance));
99
100/* Don't share the cache */
101new_palette->cache = NULL;
102
103return new_palette;
104}
105
106void
107ImagingPaletteDelete(ImagingPalette palette) {
108/* Destroy palette object */
109
110if (palette) {
111if (palette->cache) {
112free(palette->cache);
113}
114free(palette);
115}
116}
117
118/* -------------------------------------------------------------------- */
119/* Colour mapping */
120/* -------------------------------------------------------------------- */
121
122/* This code is used to map RGB triplets to palette indices, using
123a palette index cache. */
124
125/*
126* This implementation is loosely based on the corresponding code in
127* the IJG JPEG library by Thomas G. Lane. Original algorithms by
128* Paul Heckbert and Spencer W. Thomas.
129*
130* The IJG JPEG library is copyright (C) 1991-1995, Thomas G. Lane. */
131
132#define DIST(a, b, s) (a - b) * (a - b) * s
133
134/* Colour weights (no scaling, for now) */
135#define RSCALE 1
136#define GSCALE 1
137#define BSCALE 1
138
139/* Calculated scaled distances */
140#define RDIST(a, b) DIST(a, b, RSCALE *RSCALE)
141#define GDIST(a, b) DIST(a, b, GSCALE *GSCALE)
142#define BDIST(a, b) DIST(a, b, BSCALE *BSCALE)
143
144/* Incremental steps */
145#define RSTEP (4 * RSCALE)
146#define GSTEP (4 * GSCALE)
147#define BSTEP (4 * BSCALE)
148
149#define BOX 8
150
151#define BOXVOLUME BOX *BOX *BOX
152
153void
154ImagingPaletteCacheUpdate(ImagingPalette palette, int r, int g, int b) {
155int i, j;
156unsigned int dmin[256], dmax;
157int r0, g0, b0;
158int r1, g1, b1;
159int rc, gc, bc;
160unsigned int d[BOXVOLUME];
161UINT8 c[BOXVOLUME];
162
163/* Get box boundaries for the given (r,g,b)-triplet. Each box
164covers eight cache slots (32 colour values, that is). */
165
166r0 = r & 0xe0;
167r1 = r0 + 0x1f;
168rc = (r0 + r1) / 2;
169g0 = g & 0xe0;
170g1 = g0 + 0x1f;
171gc = (g0 + g1) / 2;
172b0 = b & 0xe0;
173b1 = b0 + 0x1f;
174bc = (b0 + b1) / 2;
175
176/* Step 1 -- Select relevant palette entries (after Heckbert) */
177
178/* For each palette entry, calculate the min and max distances to
179* any position in the box given by the colour we're looking for. */
180
181dmax = (unsigned int)~0;
182
183for (i = 0; i < palette->size; i++) {
184int r, g, b;
185unsigned int tmin, tmax;
186
187/* Find min and max distances to any point in the box */
188r = palette->palette[i * 4 + 0];
189tmin = (r < r0) ? RDIST(r, r0) : (r > r1) ? RDIST(r, r1) : 0;
190tmax = (r <= rc) ? RDIST(r, r1) : RDIST(r, r0);
191
192g = palette->palette[i * 4 + 1];
193tmin += (g < g0) ? GDIST(g, g0) : (g > g1) ? GDIST(g, g1) : 0;
194tmax += (g <= gc) ? GDIST(g, g1) : GDIST(g, g0);
195
196b = palette->palette[i * 4 + 2];
197tmin += (b < b0) ? BDIST(b, b0) : (b > b1) ? BDIST(b, b1) : 0;
198tmax += (b <= bc) ? BDIST(b, b1) : BDIST(b, b0);
199
200dmin[i] = tmin;
201if (tmax < dmax) {
202dmax = tmax; /* keep the smallest max distance only */
203}
204}
205
206/* Step 2 -- Incrementally update cache slot (after Thomas) */
207
208/* Find the box containing the nearest palette entry, and update
209* all slots in that box. We only check boxes for which the min
210* distance is less than or equal the smallest max distance */
211
212for (i = 0; i < BOXVOLUME; i++) {
213d[i] = (unsigned int)~0;
214}
215
216for (i = 0; i < palette->size; i++) {
217if (dmin[i] <= dmax) {
218int rd, gd, bd;
219int ri, gi, bi;
220int rx, gx, bx;
221
222ri = (r0 - palette->palette[i * 4 + 0]) * RSCALE;
223gi = (g0 - palette->palette[i * 4 + 1]) * GSCALE;
224bi = (b0 - palette->palette[i * 4 + 2]) * BSCALE;
225
226rd = ri * ri + gi * gi + bi * bi;
227
228ri = ri * (2 * RSTEP) + RSTEP * RSTEP;
229gi = gi * (2 * GSTEP) + GSTEP * GSTEP;
230bi = bi * (2 * BSTEP) + BSTEP * BSTEP;
231
232rx = ri;
233for (r = j = 0; r < BOX; r++) {
234gd = rd;
235gx = gi;
236for (g = 0; g < BOX; g++) {
237bd = gd;
238bx = bi;
239for (b = 0; b < BOX; b++) {
240if ((unsigned int)bd < d[j]) {
241d[j] = bd;
242c[j] = (UINT8)i;
243}
244bd += bx;
245bx += 2 * BSTEP * BSTEP;
246j++;
247}
248gd += gx;
249gx += 2 * GSTEP * GSTEP;
250}
251rd += rx;
252rx += 2 * RSTEP * RSTEP;
253}
254}
255}
256
257/* Step 3 -- Update cache */
258
259/* The c array now contains the closest match for each
260* cache slot in the box. Update the cache. */
261
262j = 0;
263for (r = r0; r < r1; r += 4) {
264for (g = g0; g < g1; g += 4) {
265for (b = b0; b < b1; b += 4) {
266ImagingPaletteCache(palette, r, g, b) = c[j++];
267}
268}
269}
270}
271
272int
273ImagingPaletteCachePrepare(ImagingPalette palette) {
274/* Add a colour cache to a palette */
275
276int i;
277int entries = 64 * 64 * 64;
278
279if (palette->cache == NULL) {
280/* The cache is 512k. It might be a good idea to break it
281up into a pointer array (e.g. an 8-bit image?) */
282
283/* malloc check ok, small constant allocation */
284palette->cache = (INT16 *)malloc(entries * sizeof(INT16));
285if (!palette->cache) {
286(void)ImagingError_MemoryError();
287return -1;
288}
289
290/* Mark all entries as empty */
291for (i = 0; i < entries; i++) {
292palette->cache[i] = 0x100;
293}
294}
295
296return 0;
297}
298
299void
300ImagingPaletteCacheDelete(ImagingPalette palette) {
301/* Release the colour cache, if any */
302
303if (palette && palette->cache) {
304free(palette->cache);
305palette->cache = NULL;
306}
307}
308