pikl 0.2.7-x86-mswin32 → 0.2.8-x86-mswin32
Sign up to get free protection for your applications and to get access to all the features.
- data/Manifest.txt +23 -0
- data/ext/pikl/decrease/fsdither.h +554 -0
- data/ext/pikl/decrease/median.c +1179 -0
- data/ext/pikl/decrease/median.h +7 -0
- data/ext/pikl/decrease/neuquan5.c +563 -0
- data/ext/pikl/decrease/neuquant.h +62 -0
- data/ext/pikl/decrease/wu.c +447 -0
- data/ext/pikl/decrease/wu.h +7 -0
- data/ext/pikl/pikl_affine.c +250 -0
- data/ext/pikl/pikl_affine.h +20 -0
- data/ext/pikl/pikl_blur.c +244 -0
- data/ext/pikl/pikl_blur.h +12 -0
- data/ext/pikl/pikl_decrease.c +126 -0
- data/ext/pikl/pikl_decrease.h +19 -0
- data/ext/pikl/pikl_effect2.c +240 -0
- data/ext/pikl/pikl_effect2.h +55 -0
- data/ext/pikl/pikl_effect3.c +266 -0
- data/ext/pikl/pikl_effect3.h +12 -0
- data/ext/pikl/pikl_effect4.c +495 -0
- data/ext/pikl/pikl_effect4.h +12 -0
- data/ext/pikl/pikl_pattern.c +611 -0
- data/ext/pikl/pikl_pattern.h +12 -0
- data/ext/pikl/pikl_scrap.c +731 -0
- data/ext/pikl/pikl_scrap.h +12 -0
- data/lib/pikl/version.rb +1 -1
- metadata +26 -3
@@ -0,0 +1,1179 @@
|
|
1
|
+
/*
|
2
|
+
Based upon a GIMP filter ("to-indexed.c"):
|
3
|
+
"The GIMP -- an image manipulation program
|
4
|
+
Copyright (C) 1995 Spencer Kimball and Peter Mattis"
|
5
|
+
|
6
|
+
"This filter takes an rgb input image and creates a new
|
7
|
+
indexed color image."
|
8
|
+
|
9
|
+
median_cut, 2-pass, floyd no/yes
|
10
|
+
char *out = to_indexed(input_image, num, dither, xsize, ysize, &colormap);
|
11
|
+
|
12
|
+
Benny:
|
13
|
+
v0.2 - Win95 GPF fixed.
|
14
|
+
v0.3 - weeded out some functions.
|
15
|
+
*/
|
16
|
+
|
17
|
+
#include <stdio.h>
|
18
|
+
#include <stdlib.h>
|
19
|
+
#include <string.h>
|
20
|
+
#include <malloc.h>
|
21
|
+
//#include <mem.h>
|
22
|
+
|
23
|
+
|
24
|
+
#include "fsdither.h" // tables:
|
25
|
+
/* 'range_array' 'floyd_steinberg_error1' 'floyd_steinberg_error2'
|
26
|
+
'floyd_steinberg_error3' 'floyd_steinberg_error4'*/
|
27
|
+
|
28
|
+
#define MAXNUMCOLORS 256
|
29
|
+
|
30
|
+
/* dither type */
|
31
|
+
#define NODITHER 0
|
32
|
+
#define FSDITHER 1
|
33
|
+
|
34
|
+
#define PRECISION_R 6
|
35
|
+
#define PRECISION_G 6
|
36
|
+
//#define PRECISION_B 6 // worse
|
37
|
+
#define PRECISION_B 5 // ori
|
38
|
+
|
39
|
+
//#if 0
|
40
|
+
#define R_SCALE
|
41
|
+
#define G_SCALE
|
42
|
+
#define B_SCALE
|
43
|
+
//#else
|
44
|
+
///* scale RGB distances by *2,*3,*1 */
|
45
|
+
//#define R_SCALE << 1
|
46
|
+
//#define G_SCALE * 3
|
47
|
+
//#define B_SCALE
|
48
|
+
//#endif
|
49
|
+
|
50
|
+
|
51
|
+
#define HIST_R_ELEMS (1<<PRECISION_R)
|
52
|
+
#define HIST_G_ELEMS (1<<PRECISION_G)
|
53
|
+
#define HIST_B_ELEMS (1<<PRECISION_B)
|
54
|
+
|
55
|
+
#define MR HIST_G_ELEMS*HIST_B_ELEMS
|
56
|
+
#define MG HIST_B_ELEMS
|
57
|
+
|
58
|
+
#define BITS_IN_SAMPLE 8
|
59
|
+
|
60
|
+
#define R_SHIFT (BITS_IN_SAMPLE - PRECISION_R)
|
61
|
+
#define G_SHIFT (BITS_IN_SAMPLE - PRECISION_G)
|
62
|
+
#define B_SHIFT (BITS_IN_SAMPLE - PRECISION_B)
|
63
|
+
|
64
|
+
typedef struct _Color Color;
|
65
|
+
typedef struct _QuantizeObj QuantizeObj;
|
66
|
+
typedef void (*Pass_Func) (QuantizeObj *, unsigned char *, unsigned char *, long, long);
|
67
|
+
//typedef void (*Cleanup_Func) (QuantizeObj *);
|
68
|
+
typedef unsigned long ColorFreq;
|
69
|
+
typedef ColorFreq *Histogram;
|
70
|
+
|
71
|
+
struct _Color {
|
72
|
+
int red;
|
73
|
+
int green;
|
74
|
+
int blue;
|
75
|
+
};
|
76
|
+
|
77
|
+
struct _QuantizeObj {
|
78
|
+
Pass_Func first_pass; /* first pass over image data creates colormap */
|
79
|
+
Pass_Func second_pass; /* second pass maps from image data to colormap */
|
80
|
+
// Cleanup_Func delete_func; /* function to clean up data associated with private */
|
81
|
+
// int bpp; /* bytes per pixel (grayscale vs rgb) */
|
82
|
+
int desired_number_of_colors; /* Number of colors we will allow */
|
83
|
+
int actual_number_of_colors; /* Number of colors actually needed */
|
84
|
+
Color cmap[256]; /* colormap created by quantization */
|
85
|
+
Histogram histogram; /* holds the histogram */
|
86
|
+
};
|
87
|
+
|
88
|
+
typedef struct {
|
89
|
+
/* The bounds of the box (inclusive); expressed as histogram indexes */
|
90
|
+
int Rmin, Rmax;
|
91
|
+
int Gmin, Gmax;
|
92
|
+
int Bmin, Bmax;
|
93
|
+
/* The volume (actually 2-norm) of the box */
|
94
|
+
int volume;
|
95
|
+
/* The number of nonzero histogram cells within this box */
|
96
|
+
long colorcount;
|
97
|
+
} box , *boxptr;
|
98
|
+
|
99
|
+
typedef struct {
|
100
|
+
long ncolors;
|
101
|
+
long dither;
|
102
|
+
} Options;
|
103
|
+
|
104
|
+
//void error(char*);
|
105
|
+
void error(char*msg){
|
106
|
+
fprintf(stderr, "%s\n", msg);
|
107
|
+
}
|
108
|
+
|
109
|
+
/*
|
110
|
+
static void *xmalloc(unsigned long size)
|
111
|
+
{
|
112
|
+
void *p;
|
113
|
+
p = malloc(size);
|
114
|
+
if (!p) error("could not xmallocate memory");
|
115
|
+
return p;
|
116
|
+
}
|
117
|
+
*/
|
118
|
+
|
119
|
+
static void xfree(void *p)
|
120
|
+
{
|
121
|
+
if (p)
|
122
|
+
free(p);
|
123
|
+
}
|
124
|
+
|
125
|
+
static void zero_histogram_rgb(Histogram histogram)
|
126
|
+
{
|
127
|
+
int r, g, b;
|
128
|
+
for (r = 0; r < HIST_R_ELEMS; r++)
|
129
|
+
for (g = 0; g < HIST_G_ELEMS; g++)
|
130
|
+
for (b = 0; b < HIST_B_ELEMS; b++)
|
131
|
+
histogram[r * MR + g * MG + b] = 0;
|
132
|
+
}
|
133
|
+
|
134
|
+
static void generate_histogram_rgb(histogram, src, width, height)
|
135
|
+
Histogram histogram;
|
136
|
+
unsigned char *src;
|
137
|
+
long width;
|
138
|
+
long height;
|
139
|
+
{
|
140
|
+
int num_elems;
|
141
|
+
ColorFreq *col;
|
142
|
+
|
143
|
+
num_elems = width * height;
|
144
|
+
zero_histogram_rgb(histogram);
|
145
|
+
|
146
|
+
while (num_elems--) {
|
147
|
+
col = &histogram[(src[0] >> R_SHIFT) * MR +
|
148
|
+
(src[1] >> G_SHIFT) * MG +
|
149
|
+
(src[2] >> B_SHIFT)];
|
150
|
+
(*col)++;
|
151
|
+
src += 3;
|
152
|
+
}
|
153
|
+
}
|
154
|
+
|
155
|
+
static boxptr
|
156
|
+
find_biggest_color_pop(boxlist, numboxes)
|
157
|
+
boxptr boxlist;
|
158
|
+
int numboxes;
|
159
|
+
/* Find the splittable box with the largest color population */
|
160
|
+
/* Returns 0 if no splittable boxes remain */
|
161
|
+
{
|
162
|
+
boxptr boxp;
|
163
|
+
int i;
|
164
|
+
long maxc = 0;
|
165
|
+
boxptr which = 0;
|
166
|
+
|
167
|
+
for (i = 0, boxp = boxlist; i < numboxes; i++, boxp++) {
|
168
|
+
if (boxp->colorcount > maxc && boxp->volume > 0) {
|
169
|
+
which = boxp;
|
170
|
+
maxc = boxp->colorcount;
|
171
|
+
}
|
172
|
+
}
|
173
|
+
|
174
|
+
return which;
|
175
|
+
}
|
176
|
+
|
177
|
+
|
178
|
+
static boxptr
|
179
|
+
find_biggest_volume(boxlist, numboxes)
|
180
|
+
boxptr boxlist;
|
181
|
+
int numboxes;
|
182
|
+
/* Find the splittable box with the largest (scaled) volume */
|
183
|
+
/* Returns 0 if no splittable boxes remain */
|
184
|
+
{
|
185
|
+
boxptr boxp;
|
186
|
+
int i;
|
187
|
+
int maxv = 0;
|
188
|
+
boxptr which = 0;
|
189
|
+
|
190
|
+
for (i = 0, boxp = boxlist; i < numboxes; i++, boxp++) {
|
191
|
+
if (boxp->volume > maxv) {
|
192
|
+
which = boxp;
|
193
|
+
maxv = boxp->volume;
|
194
|
+
}
|
195
|
+
}
|
196
|
+
|
197
|
+
return which;
|
198
|
+
}
|
199
|
+
|
200
|
+
|
201
|
+
static void update_box_rgb(histogram, boxp)
|
202
|
+
Histogram histogram;
|
203
|
+
boxptr boxp;
|
204
|
+
/* Shrink the min/max bounds of a box to enclose only nonzero elements, */
|
205
|
+
/* and recompute its volume and population */
|
206
|
+
{
|
207
|
+
ColorFreq *histp;
|
208
|
+
int R, G, B;
|
209
|
+
int Rmin, Rmax, Gmin, Gmax, Bmin, Bmax;
|
210
|
+
int dist0, dist1, dist2;
|
211
|
+
long ccount;
|
212
|
+
|
213
|
+
Rmin = boxp->Rmin;
|
214
|
+
Rmax = boxp->Rmax;
|
215
|
+
Gmin = boxp->Gmin;
|
216
|
+
Gmax = boxp->Gmax;
|
217
|
+
Bmin = boxp->Bmin;
|
218
|
+
Bmax = boxp->Bmax;
|
219
|
+
|
220
|
+
if (Rmax > Rmin)
|
221
|
+
for (R = Rmin; R <= Rmax; R++)
|
222
|
+
for (G = Gmin; G <= Gmax; G++) {
|
223
|
+
histp = histogram + R * MR + G * MG + Bmin;
|
224
|
+
for (B = Bmin; B <= Bmax; B++)
|
225
|
+
if (*histp++ != 0) {
|
226
|
+
boxp->Rmin = Rmin = R;
|
227
|
+
goto have_Rmin;
|
228
|
+
}
|
229
|
+
}
|
230
|
+
have_Rmin:
|
231
|
+
if (Rmax > Rmin)
|
232
|
+
for (R = Rmax; R >= Rmin; R--)
|
233
|
+
for (G = Gmin; G <= Gmax; G++) {
|
234
|
+
histp = histogram + R * MR + G * MG + Bmin;
|
235
|
+
for (B = Bmin; B <= Bmax; B++)
|
236
|
+
if (*histp++ != 0) {
|
237
|
+
boxp->Rmax = Rmax = R;
|
238
|
+
goto have_Rmax;
|
239
|
+
}
|
240
|
+
}
|
241
|
+
have_Rmax:
|
242
|
+
if (Gmax > Gmin)
|
243
|
+
for (G = Gmin; G <= Gmax; G++)
|
244
|
+
for (R = Rmin; R <= Rmax; R++) {
|
245
|
+
histp = histogram + R * MR + G * MG + Bmin;
|
246
|
+
for (B = Bmin; B <= Bmax; B++)
|
247
|
+
if (*histp++ != 0) {
|
248
|
+
boxp->Gmin = Gmin = G;
|
249
|
+
goto have_Gmin;
|
250
|
+
}
|
251
|
+
}
|
252
|
+
have_Gmin:
|
253
|
+
if (Gmax > Gmin)
|
254
|
+
for (G = Gmax; G >= Gmin; G--)
|
255
|
+
for (R = Rmin; R <= Rmax; R++) {
|
256
|
+
histp = histogram + R * MR + G * MG + Bmin;
|
257
|
+
for (B = Bmin; B <= Bmax; B++)
|
258
|
+
if (*histp++ != 0) {
|
259
|
+
boxp->Gmax = Gmax = G;
|
260
|
+
goto have_Gmax;
|
261
|
+
}
|
262
|
+
}
|
263
|
+
have_Gmax:
|
264
|
+
if (Bmax > Bmin)
|
265
|
+
for (B = Bmin; B <= Bmax; B++)
|
266
|
+
for (R = Rmin; R <= Rmax; R++) {
|
267
|
+
histp = histogram + R * MR + Gmin * MG + B;
|
268
|
+
for (G = Gmin; G <= Gmax; G++, histp += MG)
|
269
|
+
if (*histp != 0) {
|
270
|
+
boxp->Bmin = Bmin = B;
|
271
|
+
goto have_Bmin;
|
272
|
+
}
|
273
|
+
}
|
274
|
+
have_Bmin:
|
275
|
+
if (Bmax > Bmin)
|
276
|
+
for (B = Bmax; B >= Bmin; B--)
|
277
|
+
for (R = Rmin; R <= Rmax; R++) {
|
278
|
+
histp = histogram + R * MR + Gmin * MG + B;
|
279
|
+
for (G = Gmin; G <= Gmax; G++, histp += MG)
|
280
|
+
if (*histp != 0) {
|
281
|
+
boxp->Bmax = Bmax = B;
|
282
|
+
goto have_Bmax;
|
283
|
+
}
|
284
|
+
}
|
285
|
+
have_Bmax:
|
286
|
+
|
287
|
+
/* Update box volume.
|
288
|
+
* We use 2-norm rather than real volume here; this biases the method
|
289
|
+
* against making long narrow boxes, and it has the side benefit that
|
290
|
+
* a box is splittable iff norm > 0.
|
291
|
+
* Since the differences are expressed in histogram-cell units,
|
292
|
+
* we have to shift back to JSAMPLE units to get consistent distances;
|
293
|
+
* after which, we scale according to the selected distance scale factors.
|
294
|
+
*/
|
295
|
+
dist0 = ((Rmax - Rmin) << R_SHIFT) R_SCALE;
|
296
|
+
dist1 = ((Gmax - Gmin) << G_SHIFT) G_SCALE;
|
297
|
+
dist2 = ((Bmax - Bmin) << B_SHIFT) B_SCALE;
|
298
|
+
boxp->volume = dist0 * dist0 + dist1 * dist1 + dist2 * dist2;
|
299
|
+
|
300
|
+
/* Now scan remaining volume of box and compute population */
|
301
|
+
ccount = 0;
|
302
|
+
for (R = Rmin; R <= Rmax; R++)
|
303
|
+
for (G = Gmin; G <= Gmax; G++) {
|
304
|
+
histp = histogram + R * MR + G * MG + Bmin;
|
305
|
+
for (B = Bmin; B <= Bmax; B++, histp++)
|
306
|
+
if (*histp != 0) {
|
307
|
+
ccount++;
|
308
|
+
}
|
309
|
+
}
|
310
|
+
|
311
|
+
boxp->colorcount = ccount;
|
312
|
+
}
|
313
|
+
|
314
|
+
|
315
|
+
static int median_cut_rgb(histogram, boxlist, numboxes, desired_colors)
|
316
|
+
Histogram histogram;
|
317
|
+
boxptr boxlist;
|
318
|
+
int numboxes;
|
319
|
+
int desired_colors;
|
320
|
+
/* Repeatedly select and split the largest box until we have enough boxes */
|
321
|
+
{
|
322
|
+
int n, lb;
|
323
|
+
int R, G, B, cmax;
|
324
|
+
boxptr b1, b2;
|
325
|
+
|
326
|
+
while (numboxes < desired_colors) {
|
327
|
+
/* Select box to split.
|
328
|
+
* Current algorithm: by population for first half, then by volume.
|
329
|
+
*/
|
330
|
+
if (numboxes * 2 <= desired_colors) {
|
331
|
+
b1 = find_biggest_color_pop(boxlist, numboxes);
|
332
|
+
} else {
|
333
|
+
b1 = find_biggest_volume(boxlist, numboxes);
|
334
|
+
}
|
335
|
+
|
336
|
+
if (b1 == 0) /* no splittable boxes left! */
|
337
|
+
break;
|
338
|
+
b2 = boxlist + numboxes; /* where new box will go */
|
339
|
+
/* Copy the color bounds to the new box. */
|
340
|
+
b2->Rmax = b1->Rmax;
|
341
|
+
b2->Gmax = b1->Gmax;
|
342
|
+
b2->Bmax = b1->Bmax;
|
343
|
+
b2->Rmin = b1->Rmin;
|
344
|
+
b2->Gmin = b1->Gmin;
|
345
|
+
b2->Bmin = b1->Bmin;
|
346
|
+
/* Choose which axis to split the box on.
|
347
|
+
* Current algorithm: longest scaled axis.
|
348
|
+
* See notes in update_box about scaling distances.
|
349
|
+
*/
|
350
|
+
R = ((b1->Rmax - b1->Rmin) << R_SHIFT) R_SCALE;
|
351
|
+
G = ((b1->Gmax - b1->Gmin) << G_SHIFT) G_SCALE;
|
352
|
+
B = ((b1->Bmax - b1->Bmin) << B_SHIFT) B_SCALE;
|
353
|
+
/* We want to break any ties in favor of green, then red, blue last.
|
354
|
+
*/
|
355
|
+
cmax = G;
|
356
|
+
n = 1;
|
357
|
+
if (R > cmax) {
|
358
|
+
cmax = R;
|
359
|
+
n = 0;
|
360
|
+
}
|
361
|
+
if (B > cmax) {
|
362
|
+
n = 2;
|
363
|
+
}
|
364
|
+
/* Choose split point along selected axis, and update box bounds.
|
365
|
+
* Current algorithm: split at halfway point.
|
366
|
+
* (Since the box has been shrunk to minimum volume,
|
367
|
+
* any split will produce two nonempty subboxes.)
|
368
|
+
* Note that lb value is max for lower box, so must be < old max.
|
369
|
+
*/
|
370
|
+
switch (n) {
|
371
|
+
case 0:
|
372
|
+
lb = (b1->Rmax + b1->Rmin) / 2;
|
373
|
+
b1->Rmax = lb;
|
374
|
+
b2->Rmin = lb + 1;
|
375
|
+
break;
|
376
|
+
case 1:
|
377
|
+
lb = (b1->Gmax + b1->Gmin) / 2;
|
378
|
+
b1->Gmax = lb;
|
379
|
+
b2->Gmin = lb + 1;
|
380
|
+
break;
|
381
|
+
case 2:
|
382
|
+
lb = (b1->Bmax + b1->Bmin) / 2;
|
383
|
+
b1->Bmax = lb;
|
384
|
+
b2->Bmin = lb + 1;
|
385
|
+
break;
|
386
|
+
}
|
387
|
+
/* Update stats for boxes */
|
388
|
+
update_box_rgb(histogram, b1);
|
389
|
+
update_box_rgb(histogram, b2);
|
390
|
+
numboxes++;
|
391
|
+
}
|
392
|
+
return numboxes;
|
393
|
+
}
|
394
|
+
|
395
|
+
|
396
|
+
static void compute_color_rgb(quantobj, histogram, boxp, icolor)
|
397
|
+
QuantizeObj *quantobj;
|
398
|
+
Histogram histogram;
|
399
|
+
boxptr boxp;
|
400
|
+
int icolor;
|
401
|
+
/* Compute representative color for a box, put it in colormap[icolor] */
|
402
|
+
{
|
403
|
+
/* Current algorithm: mean weighted by pixels (not colors) */
|
404
|
+
/* Note it is important to get the rounding correct! */
|
405
|
+
ColorFreq *histp;
|
406
|
+
int R, G, B;
|
407
|
+
int Rmin, Rmax;
|
408
|
+
int Gmin, Gmax;
|
409
|
+
int Bmin, Bmax;
|
410
|
+
long count;
|
411
|
+
long total = 0;
|
412
|
+
long Rtotal = 0;
|
413
|
+
long Gtotal = 0;
|
414
|
+
long Btotal = 0;
|
415
|
+
|
416
|
+
Rmin = boxp->Rmin;
|
417
|
+
Rmax = boxp->Rmax;
|
418
|
+
Gmin = boxp->Gmin;
|
419
|
+
Gmax = boxp->Gmax;
|
420
|
+
Bmin = boxp->Bmin;
|
421
|
+
Bmax = boxp->Bmax;
|
422
|
+
|
423
|
+
for (R = Rmin; R <= Rmax; R++)
|
424
|
+
for (G = Gmin; G <= Gmax; G++) {
|
425
|
+
histp = histogram + R * MR + G * MG + Bmin;
|
426
|
+
for (B = Bmin; B <= Bmax; B++) {
|
427
|
+
if ((count = *histp++) != 0) {
|
428
|
+
total += count;
|
429
|
+
Rtotal += ((R << R_SHIFT) + ((1 << R_SHIFT) >> 1)) * count;
|
430
|
+
Gtotal += ((G << G_SHIFT) + ((1 << G_SHIFT) >> 1)) * count;
|
431
|
+
Btotal += ((B << B_SHIFT) + ((1 << B_SHIFT) >> 1)) * count;
|
432
|
+
}
|
433
|
+
}
|
434
|
+
}
|
435
|
+
|
436
|
+
quantobj->cmap[icolor].red = (Rtotal + (total >> 1)) / total;
|
437
|
+
quantobj->cmap[icolor].green = (Gtotal + (total >> 1)) / total;
|
438
|
+
quantobj->cmap[icolor].blue = (Btotal + (total >> 1)) / total;
|
439
|
+
}
|
440
|
+
|
441
|
+
|
442
|
+
static void select_colors_rgb(quantobj, histogram)
|
443
|
+
QuantizeObj *quantobj;
|
444
|
+
Histogram histogram;
|
445
|
+
/* Master routine for color selection */
|
446
|
+
{
|
447
|
+
boxptr boxlist;
|
448
|
+
int numboxes;
|
449
|
+
int desired = quantobj->desired_number_of_colors;
|
450
|
+
int i;
|
451
|
+
|
452
|
+
/* Allocate workspace for box list */
|
453
|
+
boxlist = (boxptr) malloc(desired * sizeof(box));
|
454
|
+
if (!boxlist) error("could not alloc mem");
|
455
|
+
|
456
|
+
/* Initialize one box containing whole space */
|
457
|
+
numboxes = 1;
|
458
|
+
boxlist[0].Rmin = 0;
|
459
|
+
boxlist[0].Rmax = (1 << PRECISION_R) - 1;
|
460
|
+
boxlist[0].Gmin = 0;
|
461
|
+
boxlist[0].Gmax = (1 << PRECISION_G) - 1;
|
462
|
+
boxlist[0].Bmin = 0;
|
463
|
+
boxlist[0].Bmax = (1 << PRECISION_B) - 1;
|
464
|
+
/* Shrink it to actually-used volume and set its statistics */
|
465
|
+
update_box_rgb(histogram, boxlist);
|
466
|
+
/* Perform median-cut to produce final box list */
|
467
|
+
numboxes = median_cut_rgb(histogram, boxlist, numboxes, desired);
|
468
|
+
quantobj->actual_number_of_colors = numboxes;
|
469
|
+
/* Compute the representative color for each box, fill colormap */
|
470
|
+
for (i = 0; i < numboxes; i++)
|
471
|
+
compute_color_rgb(quantobj, histogram, boxlist + i, i);
|
472
|
+
|
473
|
+
//add by soezimaster
|
474
|
+
free(boxlist);
|
475
|
+
}
|
476
|
+
|
477
|
+
|
478
|
+
/*
|
479
|
+
* These routines are concerned with the time-critical task of mapping input
|
480
|
+
* colors to the nearest color in the selected colormap.
|
481
|
+
*
|
482
|
+
* We re-use the histogram space as an "inverse color map", essentially a
|
483
|
+
* cache for the results of nearest-color searches. All colors within a
|
484
|
+
* histogram cell will be mapped to the same colormap entry, namely the one
|
485
|
+
* closest to the cell's center. This may not be quite the closest entry to
|
486
|
+
* the actual input color, but it's almost as good. A zero in the cache
|
487
|
+
* indicates we haven't found the nearest color for that cell yet; the array
|
488
|
+
* is cleared to zeroes before starting the mapping pass. When we find the
|
489
|
+
* nearest color for a cell, its colormap index plus one is recorded in the
|
490
|
+
* cache for future use. The pass2 scanning routines call fill_inverse_cmap
|
491
|
+
* when they need to use an unfilled entry in the cache.
|
492
|
+
*
|
493
|
+
* Our method of efficiently finding nearest colors is based on the "locally
|
494
|
+
* sorted search" idea described by Heckbert and on the incremental distance
|
495
|
+
* calculation described by Spencer W. Thomas in chapter III.1 of Graphics
|
496
|
+
* Gems II (James Arvo, ed. Academic Press, 1991). Thomas points out that
|
497
|
+
* the distances from a given colormap entry to each cell of the histogram can
|
498
|
+
* be computed quickly using an incremental method: the differences between
|
499
|
+
* distances to adjacent cells themselves differ by a constant. This allows a
|
500
|
+
* fairly fast implementation of the "brute force" approach of computing the
|
501
|
+
* distance from every colormap entry to every histogram cell. Unfortunately,
|
502
|
+
* it needs a work array to hold the best-distance-so-far for each histogram
|
503
|
+
* cell (because the inner loop has to be over cells, not colormap entries).
|
504
|
+
* The work array elements have to be ints, so the work array would need
|
505
|
+
* 256Kb at our recommended precision. This is not feasible in DOS machines.
|
506
|
+
|
507
|
+
[ 256*1024/4 = 65,536 ]
|
508
|
+
|
509
|
+
* To get around these problems, we apply Thomas' method to compute the
|
510
|
+
* nearest colors for only the cells within a small subbox of the histogram.
|
511
|
+
* The work array need be only as big as the subbox, so the memory usage
|
512
|
+
* problem is solved. Furthermore, we need not fill subboxes that are never
|
513
|
+
* referenced in pass2; many images use only part of the color gamut, so a
|
514
|
+
* fair amount of work is saved. An additional advantage of this
|
515
|
+
* approach is that we can apply Heckbert's locality criterion to quickly
|
516
|
+
* eliminate colormap entries that are far away from the subbox; typically
|
517
|
+
* three-fourths of the colormap entries are rejected by Heckbert's criterion,
|
518
|
+
* and we need not compute their distances to individual cells in the subbox.
|
519
|
+
* The speed of this approach is heavily influenced by the subbox size: too
|
520
|
+
* small means too much overhead, too big loses because Heckbert's criterion
|
521
|
+
* can't eliminate as many colormap entries. Empirically the best subbox
|
522
|
+
* size seems to be about 1/512th of the histogram (1/8th in each direction).
|
523
|
+
*
|
524
|
+
* Thomas' article also describes a refined method which is asymptotically
|
525
|
+
* faster than the brute-force method, but it is also far more complex and
|
526
|
+
* cannot efficiently be applied to small subboxes. It is therefore not
|
527
|
+
* useful for programs intended to be portable to DOS machines. On machines
|
528
|
+
* with plenty of memory, filling the whole histogram in one shot with Thomas'
|
529
|
+
* refined method might be faster than the present code --- but then again,
|
530
|
+
* it might not be any faster, and it's certainly more complicated.
|
531
|
+
*/
|
532
|
+
|
533
|
+
/* log2(histogram cells in update box) for each axis; this can be adjusted */
|
534
|
+
#define BOX_R_LOG (PRECISION_R-3)
|
535
|
+
#define BOX_G_LOG (PRECISION_G-3)
|
536
|
+
#define BOX_B_LOG (PRECISION_B-3)
|
537
|
+
|
538
|
+
#define BOX_R_ELEMS (1<<BOX_R_LOG) /* # of hist cells in update box */
|
539
|
+
#define BOX_G_ELEMS (1<<BOX_G_LOG)
|
540
|
+
#define BOX_B_ELEMS (1<<BOX_B_LOG)
|
541
|
+
|
542
|
+
#define BOX_R_SHIFT (R_SHIFT + BOX_R_LOG)
|
543
|
+
#define BOX_G_SHIFT (G_SHIFT + BOX_G_LOG)
|
544
|
+
#define BOX_B_SHIFT (B_SHIFT + BOX_B_LOG)
|
545
|
+
|
546
|
+
/*
|
547
|
+
* The next three routines implement inverse colormap filling. They could
|
548
|
+
* all be folded into one big routine, but splitting them up this way saves
|
549
|
+
* some stack space (the mindist[] and bestdist[] arrays need not coexist)
|
550
|
+
* and may allow some compilers to produce better code by registerizing more
|
551
|
+
* inner-loop variables.
|
552
|
+
*/
|
553
|
+
|
554
|
+
static int find_nearby_colors(quantobj, minR, minG, minB, colorlist)
|
555
|
+
QuantizeObj *quantobj;
|
556
|
+
int minR;
|
557
|
+
int minG;
|
558
|
+
int minB;
|
559
|
+
int colorlist[];
|
560
|
+
/* Locate the colormap entries close enough to an update box to be candidates
|
561
|
+
* for the nearest entry to some cell(s) in the update box. The update box
|
562
|
+
* is specified by the center coordinates of its first cell. The number of
|
563
|
+
* candidate colormap entries is returned, and their colormap indexes are
|
564
|
+
* placed in colorlist[].
|
565
|
+
* This routine uses Heckbert's "locally sorted search" criterion to select
|
566
|
+
* the colors that need further consideration.
|
567
|
+
*/
|
568
|
+
{
|
569
|
+
int numcolors = quantobj->actual_number_of_colors;
|
570
|
+
int maxR, maxG, maxB;
|
571
|
+
int centerR, centerG, centerB;
|
572
|
+
int i, x, ncolors;
|
573
|
+
int minmaxdist, min_dist, max_dist, tdist;
|
574
|
+
int mindist[MAXNUMCOLORS]; /* min distance to colormap entry i */
|
575
|
+
|
576
|
+
/* Compute true coordinates of update box's upper corner and center.
|
577
|
+
* Actually we compute the coordinates of the center of the upper-corner
|
578
|
+
* histogram cell, which are the upper bounds of the volume we care about.
|
579
|
+
* Note that since ">>" rounds down, the "center" values may be closer to
|
580
|
+
* min than to max; hence comparisons to them must be "<=", not "<".
|
581
|
+
*/
|
582
|
+
maxR = minR + ((1 << BOX_R_SHIFT) - (1 << R_SHIFT));
|
583
|
+
centerR = (minR + maxR) >> 1;
|
584
|
+
maxG = minG + ((1 << BOX_G_SHIFT) - (1 << G_SHIFT));
|
585
|
+
centerG = (minG + maxG) >> 1;
|
586
|
+
maxB = minB + ((1 << BOX_B_SHIFT) - (1 << B_SHIFT));
|
587
|
+
centerB = (minB + maxB) >> 1;
|
588
|
+
|
589
|
+
/* For each color in colormap, find:
|
590
|
+
* 1. its minimum squared-distance to any point in the update box
|
591
|
+
* (zero if color is within update box);
|
592
|
+
* 2. its maximum squared-distance to any point in the update box.
|
593
|
+
* Both of these can be found by considering only the corners of the box.
|
594
|
+
* We save the minimum distance for each color in mindist[];
|
595
|
+
* only the smallest maximum distance is of interest.
|
596
|
+
*/
|
597
|
+
minmaxdist = 0x7FFFFFFFL;
|
598
|
+
|
599
|
+
for (i = 0; i < numcolors; i++) {
|
600
|
+
/* We compute the squared-R-distance term, then add in the other two. */
|
601
|
+
x = quantobj->cmap[i].red;
|
602
|
+
if (x < minR) {
|
603
|
+
tdist = (x - minR) R_SCALE;
|
604
|
+
min_dist = tdist * tdist;
|
605
|
+
tdist = (x - maxR) R_SCALE;
|
606
|
+
max_dist = tdist * tdist;
|
607
|
+
} else if (x > maxR) {
|
608
|
+
tdist = (x - maxR) R_SCALE;
|
609
|
+
min_dist = tdist * tdist;
|
610
|
+
tdist = (x - minR) R_SCALE;
|
611
|
+
max_dist = tdist * tdist;
|
612
|
+
} else {
|
613
|
+
/* within cell range so no contribution to min_dist */
|
614
|
+
min_dist = 0;
|
615
|
+
if (x <= centerR) {
|
616
|
+
tdist = (x - maxR) R_SCALE;
|
617
|
+
max_dist = tdist * tdist;
|
618
|
+
} else {
|
619
|
+
tdist = (x - minR) R_SCALE;
|
620
|
+
max_dist = tdist * tdist;
|
621
|
+
}
|
622
|
+
}
|
623
|
+
|
624
|
+
x = quantobj->cmap[i].green;
|
625
|
+
if (x < minG) {
|
626
|
+
tdist = (x - minG) G_SCALE;
|
627
|
+
min_dist += tdist * tdist;
|
628
|
+
tdist = (x - maxG) G_SCALE;
|
629
|
+
max_dist += tdist * tdist;
|
630
|
+
} else if (x > maxG) {
|
631
|
+
tdist = (x - maxG) G_SCALE;
|
632
|
+
min_dist += tdist * tdist;
|
633
|
+
tdist = (x - minG) G_SCALE;
|
634
|
+
max_dist += tdist * tdist;
|
635
|
+
} else {
|
636
|
+
/* within cell range so no contribution to min_dist */
|
637
|
+
if (x <= centerG) {
|
638
|
+
tdist = (x - maxG) G_SCALE;
|
639
|
+
max_dist += tdist * tdist;
|
640
|
+
} else {
|
641
|
+
tdist = (x - minG) G_SCALE;
|
642
|
+
max_dist += tdist * tdist;
|
643
|
+
}
|
644
|
+
}
|
645
|
+
|
646
|
+
x = quantobj->cmap[i].blue;
|
647
|
+
if (x < minB) {
|
648
|
+
tdist = (x - minB) B_SCALE;
|
649
|
+
min_dist += tdist * tdist;
|
650
|
+
tdist = (x - maxB) B_SCALE;
|
651
|
+
max_dist += tdist * tdist;
|
652
|
+
} else if (x > maxB) {
|
653
|
+
tdist = (x - maxB) B_SCALE;
|
654
|
+
min_dist += tdist * tdist;
|
655
|
+
tdist = (x - minB) B_SCALE;
|
656
|
+
max_dist += tdist * tdist;
|
657
|
+
} else {
|
658
|
+
/* within cell range so no contribution to min_dist */
|
659
|
+
if (x <= centerB) {
|
660
|
+
tdist = (x - maxB) B_SCALE;
|
661
|
+
max_dist += tdist * tdist;
|
662
|
+
} else {
|
663
|
+
tdist = (x - minB) B_SCALE;
|
664
|
+
max_dist += tdist * tdist;
|
665
|
+
}
|
666
|
+
}
|
667
|
+
|
668
|
+
mindist[i] = min_dist; /* save away the results */
|
669
|
+
if (max_dist < minmaxdist)
|
670
|
+
minmaxdist = max_dist;
|
671
|
+
}
|
672
|
+
|
673
|
+
/* Now we know that no cell in the update box is more than minmaxdist
|
674
|
+
* away from some colormap entry. Therefore, only colors that are
|
675
|
+
* within minmaxdist of some part of the box need be considered.
|
676
|
+
*/
|
677
|
+
ncolors = 0;
|
678
|
+
for (i = 0; i < numcolors; i++) {
|
679
|
+
if (mindist[i] <= minmaxdist)
|
680
|
+
colorlist[ncolors++] = i;
|
681
|
+
}
|
682
|
+
return ncolors;
|
683
|
+
}
|
684
|
+
|
685
|
+
|
686
|
+
static void find_best_colors(quantobj, minR, minG, minB, numcolors, colorlist, bestcolor)
|
687
|
+
QuantizeObj *quantobj;
|
688
|
+
int minR;
|
689
|
+
int minG;
|
690
|
+
int minB;
|
691
|
+
int numcolors;
|
692
|
+
int colorlist[];
|
693
|
+
int bestcolor[];
|
694
|
+
/* Find the closest colormap entry for each cell in the update box,
|
695
|
+
given the list of candidate colors prepared by find_nearby_colors.
|
696
|
+
Return the indexes of the closest entries in the bestcolor[] array.
|
697
|
+
This routine uses Thomas' incremental distance calculation method to
|
698
|
+
find the distance from a colormap entry to successive cells in the box.
|
699
|
+
*/
|
700
|
+
{
|
701
|
+
int iR, iG, iB;
|
702
|
+
int i, icolor;
|
703
|
+
int *bptr; /* pointer into bestdist[] array */
|
704
|
+
int *cptr; /* pointer into bestcolor[] array */
|
705
|
+
int dist0, dist1; /* initial distance values */
|
706
|
+
int dist2; /* current distance in inner loop */
|
707
|
+
int xx0, xx1; /* distance increments */
|
708
|
+
int xx2;
|
709
|
+
int inR, inG, inB; /* initial values for increments */
|
710
|
+
|
711
|
+
/* This array holds the distance to the nearest-so-far color for each cell */
|
712
|
+
int bestdist[BOX_R_ELEMS * BOX_G_ELEMS * BOX_B_ELEMS];
|
713
|
+
|
714
|
+
/* Initialize best-distance for each cell of the update box */
|
715
|
+
bptr = bestdist;
|
716
|
+
for (i = BOX_R_ELEMS * BOX_G_ELEMS * BOX_B_ELEMS - 1; i >= 0; i--)
|
717
|
+
*bptr++ = 0x7FFFFFFFL;
|
718
|
+
|
719
|
+
/* For each color selected by find_nearby_colors,
|
720
|
+
* compute its distance to the center of each cell in the box.
|
721
|
+
* If that's less than best-so-far, update best distance and color number.
|
722
|
+
*/
|
723
|
+
|
724
|
+
/* Nominal steps between cell centers ("x" in Thomas article) */
|
725
|
+
#define STEP_R ((1 << R_SHIFT) R_SCALE)
|
726
|
+
#define STEP_G ((1 << G_SHIFT) G_SCALE)
|
727
|
+
#define STEP_B ((1 << B_SHIFT) B_SCALE)
|
728
|
+
|
729
|
+
for (i = 0; i < numcolors; i++) {
|
730
|
+
icolor = colorlist[i];
|
731
|
+
/* Compute (square of) distance from minR/G/B to this color */
|
732
|
+
inR = (minR - quantobj->cmap[icolor].red) R_SCALE;
|
733
|
+
dist0 = inR * inR;
|
734
|
+
inG = (minG - quantobj->cmap[icolor].green) G_SCALE;
|
735
|
+
dist0 += inG * inG;
|
736
|
+
inB = (minB - quantobj->cmap[icolor].blue) B_SCALE;
|
737
|
+
dist0 += inB * inB;
|
738
|
+
/* Form the initial difference increments */
|
739
|
+
inR = inR * (2 * STEP_R) + STEP_R * STEP_R;
|
740
|
+
inG = inG * (2 * STEP_G) + STEP_G * STEP_G;
|
741
|
+
inB = inB * (2 * STEP_B) + STEP_B * STEP_B;
|
742
|
+
/* Now loop over all cells in box, updating distance per Thomas method */
|
743
|
+
bptr = bestdist;
|
744
|
+
cptr = bestcolor;
|
745
|
+
xx0 = inR;
|
746
|
+
for (iR = BOX_R_ELEMS - 1; iR >= 0; iR--) {
|
747
|
+
dist1 = dist0;
|
748
|
+
xx1 = inG;
|
749
|
+
for (iG = BOX_G_ELEMS - 1; iG >= 0; iG--) {
|
750
|
+
dist2 = dist1;
|
751
|
+
xx2 = inB;
|
752
|
+
for (iB = BOX_B_ELEMS - 1; iB >= 0; iB--) {
|
753
|
+
if (dist2 < *bptr) {
|
754
|
+
*bptr = dist2;
|
755
|
+
*cptr = icolor;
|
756
|
+
}
|
757
|
+
dist2 += xx2;
|
758
|
+
xx2 += 2 * STEP_B * STEP_B;
|
759
|
+
bptr++;
|
760
|
+
cptr++;
|
761
|
+
}
|
762
|
+
dist1 += xx1;
|
763
|
+
xx1 += 2 * STEP_G * STEP_G;
|
764
|
+
}
|
765
|
+
dist0 += xx0;
|
766
|
+
xx0 += 2 * STEP_R * STEP_R;
|
767
|
+
}
|
768
|
+
}
|
769
|
+
}
|
770
|
+
|
771
|
+
static void fill_inverse_cmap_rgb(quantobj, histogram, R, G, B)
|
772
|
+
QuantizeObj *quantobj;
|
773
|
+
Histogram histogram;
|
774
|
+
int R;
|
775
|
+
int G;
|
776
|
+
int B;
|
777
|
+
/* Fill the inverse-colormap entries in the update box that contains
|
778
|
+
histogram cell R/G/B. (Only that one cell MUST be filled, but
|
779
|
+
we can fill as many others as we wish.) */
|
780
|
+
{
|
781
|
+
int minR, minG, minB; /* lower left corner of update box */
|
782
|
+
int iR, iG, iB;
|
783
|
+
int *cptr; /* pointer into bestcolor[] array */
|
784
|
+
ColorFreq *cachep; /* pointer into main cache array */
|
785
|
+
/* This array lists the candidate colormap indexes. */
|
786
|
+
int colorlist[MAXNUMCOLORS];
|
787
|
+
int numcolors; /* number of candidate colors */
|
788
|
+
/* This array holds the actually closest colormap index for each cell. */
|
789
|
+
int bestcolor[BOX_R_ELEMS * BOX_G_ELEMS * BOX_B_ELEMS];
|
790
|
+
|
791
|
+
/* Convert cell coordinates to update box ID */
|
792
|
+
R >>= BOX_R_LOG;
|
793
|
+
G >>= BOX_G_LOG;
|
794
|
+
B >>= BOX_B_LOG;
|
795
|
+
|
796
|
+
/* Compute true coordinates of update box's origin corner.
|
797
|
+
* Actually we compute the coordinates of the center of the corner
|
798
|
+
* histogram cell, which are the lower bounds of the volume we care about.
|
799
|
+
*/
|
800
|
+
minR = (R << BOX_R_SHIFT) + ((1 << R_SHIFT) >> 1);
|
801
|
+
minG = (G << BOX_G_SHIFT) + ((1 << G_SHIFT) >> 1);
|
802
|
+
minB = (B << BOX_B_SHIFT) + ((1 << B_SHIFT) >> 1);
|
803
|
+
|
804
|
+
/* Determine which colormap entries are close enough to be candidates
|
805
|
+
* for the nearest entry to some cell in the update box.
|
806
|
+
*/
|
807
|
+
numcolors = find_nearby_colors(quantobj, minR, minG, minB, colorlist);
|
808
|
+
|
809
|
+
/* Determine the actually nearest colors. */
|
810
|
+
find_best_colors(quantobj, minR, minG, minB, numcolors, colorlist,
|
811
|
+
bestcolor);
|
812
|
+
|
813
|
+
/* Save the best color numbers (plus 1) in the main cache array */
|
814
|
+
R <<= BOX_R_LOG; /* convert ID back to base cell indexes */
|
815
|
+
G <<= BOX_G_LOG;
|
816
|
+
B <<= BOX_B_LOG;
|
817
|
+
cptr = bestcolor;
|
818
|
+
for (iR = 0; iR < BOX_R_ELEMS; iR++) {
|
819
|
+
for (iG = 0; iG < BOX_G_ELEMS; iG++) {
|
820
|
+
cachep = &histogram[(R + iR) * MR + (G + iG) * MG + B];
|
821
|
+
for (iB = 0; iB < BOX_B_ELEMS; iB++) {
|
822
|
+
*cachep++ = (*cptr++) + 1;
|
823
|
+
}
|
824
|
+
}
|
825
|
+
}
|
826
|
+
}
|
827
|
+
|
828
|
+
/* This is pass 1 */
|
829
|
+
static void median_cut_pass1_rgb(quantobj, src, dest, width, height)
|
830
|
+
QuantizeObj *quantobj;
|
831
|
+
unsigned char *src;
|
832
|
+
unsigned char *dest;
|
833
|
+
long width;
|
834
|
+
long height;
|
835
|
+
{
|
836
|
+
generate_histogram_rgb(quantobj->histogram, src, width, height);
|
837
|
+
select_colors_rgb(quantobj, quantobj->histogram);
|
838
|
+
}
|
839
|
+
|
840
|
+
|
841
|
+
/* Map some rows of pixels to the output colormapped representation. */
|
842
|
+
static void median_cut_pass2_no_dither_rgb(quantobj, src, dest, width, height)
|
843
|
+
QuantizeObj *quantobj;
|
844
|
+
unsigned char *src;
|
845
|
+
unsigned char *dest;
|
846
|
+
long width;
|
847
|
+
long height;
|
848
|
+
/* This version performs no dithering */
|
849
|
+
{
|
850
|
+
Histogram histogram = quantobj->histogram;
|
851
|
+
ColorFreq *cachep;
|
852
|
+
int R, G, B;
|
853
|
+
int row, col;
|
854
|
+
|
855
|
+
zero_histogram_rgb(histogram);
|
856
|
+
for (row = 0; row < height; row++) {
|
857
|
+
for (col = 0; col < width; col++) {
|
858
|
+
/* get pixel value and index into the cache */
|
859
|
+
R = (*src++) >> R_SHIFT;
|
860
|
+
G = (*src++) >> G_SHIFT;
|
861
|
+
B = (*src++) >> B_SHIFT;
|
862
|
+
cachep = &histogram[R * MR + G * MG + B];
|
863
|
+
/* If we have not seen this color before, find nearest colormap entry
|
864
|
+
and update the cache */
|
865
|
+
if (*cachep == 0)
|
866
|
+
fill_inverse_cmap_rgb(quantobj, histogram, R, G, B);
|
867
|
+
/* Now emit the colormap index for this cell */
|
868
|
+
*dest++ = *cachep - 1;
|
869
|
+
}
|
870
|
+
|
871
|
+
}
|
872
|
+
}
|
873
|
+
|
874
|
+
/*
|
875
|
+
Initialize the error-limiting transfer function (lookup table).
|
876
|
+
The raw F-S error computation can potentially compute error values of up to
|
877
|
+
+- MAXJSAMPLE. But we want the maximum correction applied to a pixel to be
|
878
|
+
much less, otherwise obviously wrong pixels will be created. (Typical
|
879
|
+
effects include weird fringes at color-area boundaries, isolated bright
|
880
|
+
pixels in a dark area, etc.) The standard advice for avoiding this problem
|
881
|
+
is to ensure that the "corners" of the color cube are allocated as output
|
882
|
+
colors; then repeated errors in the same direction cannot cause cascading
|
883
|
+
error buildup. However, that only prevents the error from getting
|
884
|
+
completely out of hand; Aaron Giles reports that error limiting improves
|
885
|
+
the results even with corner colors allocated.
|
886
|
+
|
887
|
+
A simple clamping of the error values to about +- MAXJSAMPLE/8 works pretty
|
888
|
+
well, but the smoother transfer function used below is even better. Thanks
|
889
|
+
to Aaron Giles for this idea.
|
890
|
+
*/
|
891
|
+
|
892
|
+
static int *init_error_limit()
|
893
|
+
/* Allocate and fill in the error_limiter table */
|
894
|
+
{
|
895
|
+
int *table;
|
896
|
+
int in, out;
|
897
|
+
|
898
|
+
table = malloc((255 * 2 + 1) * sizeof(int));
|
899
|
+
if (!table) error("could not alloc mem");
|
900
|
+
table += 255; /* so we can index -255 ... +255 */
|
901
|
+
|
902
|
+
#define STEPSIZE 16
|
903
|
+
|
904
|
+
/* Map errors 1:1 up to +- 16 */
|
905
|
+
out = 0;
|
906
|
+
for (in = 0; in < STEPSIZE; in++, out++) {
|
907
|
+
table[in] = out;
|
908
|
+
table[-in] = -out;
|
909
|
+
}
|
910
|
+
|
911
|
+
/* Map errors 1:2 up to +- 3*16 */
|
912
|
+
for (; in < STEPSIZE * 3; in++, out += (in & 1) ? 0 : 1) {
|
913
|
+
table[in] = out;
|
914
|
+
table[-in] = -out;
|
915
|
+
}
|
916
|
+
|
917
|
+
/* Clamp the rest to final out value (which is 32) */
|
918
|
+
for (; in <= 255; in++) {
|
919
|
+
table[in] = out;
|
920
|
+
table[-in] = -out;
|
921
|
+
}
|
922
|
+
|
923
|
+
#undef STEPSIZE
|
924
|
+
|
925
|
+
return table;
|
926
|
+
}
|
927
|
+
|
928
|
+
|
929
|
+
/* Map some rows of pixels to the output colormapped representation.
|
930
|
+
Perform floyd-steinberg dithering. */
|
931
|
+
static void median_cut_pass2_fs_dither_rgb(quantobj, src, dest, width, height)
|
932
|
+
QuantizeObj *quantobj;
|
933
|
+
unsigned char *src;
|
934
|
+
unsigned char *dest;
|
935
|
+
long width;
|
936
|
+
long height;
|
937
|
+
{
|
938
|
+
Histogram histogram = quantobj->histogram;
|
939
|
+
ColorFreq *cachep;
|
940
|
+
Color *color;
|
941
|
+
unsigned char *src_row;
|
942
|
+
unsigned char *dest_row;
|
943
|
+
int *error_limiter;
|
944
|
+
short *fs_err1, *fs_err2;
|
945
|
+
short *fs_err3, *fs_err4;
|
946
|
+
int *red_n_row, *red_p_row;
|
947
|
+
int *grn_n_row, *grn_p_row;
|
948
|
+
int *blu_n_row, *blu_p_row;
|
949
|
+
int *rnr, *rpr;
|
950
|
+
int *gnr, *gpr;
|
951
|
+
int *bnr, *bpr;
|
952
|
+
int *tmp;
|
953
|
+
int r, g, b;
|
954
|
+
int re, ge, be;
|
955
|
+
int row, col;
|
956
|
+
int index;
|
957
|
+
int rowstride;
|
958
|
+
int step_dest, step_src;
|
959
|
+
int odd_row;
|
960
|
+
// short *range_limiter;
|
961
|
+
unsigned char *range_limiter;
|
962
|
+
|
963
|
+
zero_histogram_rgb(histogram);
|
964
|
+
|
965
|
+
error_limiter = init_error_limit();
|
966
|
+
range_limiter = range_array + 256;
|
967
|
+
|
968
|
+
red_n_row = malloc(sizeof(int) * (width + 2));
|
969
|
+
if (!red_n_row) error("could not alloc mem");
|
970
|
+
red_p_row = malloc(sizeof(int) * (width + 2));
|
971
|
+
if (!red_p_row) error("could not alloc mem");
|
972
|
+
grn_n_row = malloc(sizeof(int) * (width + 2));
|
973
|
+
if (!grn_n_row) error("could not alloc mem");
|
974
|
+
grn_p_row = malloc(sizeof(int) * (width + 2));
|
975
|
+
if (!grn_p_row) error("could not alloc mem");
|
976
|
+
blu_n_row = malloc(sizeof(int) * (width + 2));
|
977
|
+
if (!blu_n_row) error("could not alloc mem");
|
978
|
+
blu_p_row = malloc(sizeof(int) * (width + 2));
|
979
|
+
if (!blu_p_row) error("could not alloc mem");
|
980
|
+
|
981
|
+
memset(red_p_row, 0, sizeof(int) * (width + 2) );
|
982
|
+
memset(grn_p_row, 0, sizeof(int) * (width + 2));
|
983
|
+
memset(blu_p_row, 0, sizeof(int) * (width + 2));
|
984
|
+
|
985
|
+
fs_err1 = floyd_steinberg_error1 + 511;
|
986
|
+
fs_err2 = floyd_steinberg_error2 + 511;
|
987
|
+
fs_err3 = floyd_steinberg_error3 + 511;
|
988
|
+
fs_err4 = floyd_steinberg_error4 + 511;
|
989
|
+
|
990
|
+
src_row = src;
|
991
|
+
dest_row = dest;
|
992
|
+
rowstride = width * 3;
|
993
|
+
odd_row = 0;
|
994
|
+
|
995
|
+
for (row = 0; row < height; row++) {
|
996
|
+
src = src_row;
|
997
|
+
dest = dest_row;
|
998
|
+
|
999
|
+
src_row += rowstride;
|
1000
|
+
dest_row += width;
|
1001
|
+
|
1002
|
+
rnr = red_n_row;
|
1003
|
+
gnr = grn_n_row;
|
1004
|
+
bnr = blu_n_row;
|
1005
|
+
rpr = red_p_row + 1;
|
1006
|
+
gpr = grn_p_row + 1;
|
1007
|
+
bpr = blu_p_row + 1;
|
1008
|
+
|
1009
|
+
if (odd_row) {
|
1010
|
+
step_dest = -1;
|
1011
|
+
step_src = -3;
|
1012
|
+
|
1013
|
+
src += rowstride - 3;
|
1014
|
+
dest += width - 1;
|
1015
|
+
|
1016
|
+
rnr += width + 1;
|
1017
|
+
gnr += width + 1;
|
1018
|
+
bnr += width + 1;
|
1019
|
+
rpr += width;
|
1020
|
+
gpr += width;
|
1021
|
+
bpr += width;
|
1022
|
+
|
1023
|
+
*(rnr - 1) = *(gnr - 1) = *(bnr - 1) = 0;
|
1024
|
+
} else {
|
1025
|
+
step_dest = 1;
|
1026
|
+
step_src = 3;
|
1027
|
+
|
1028
|
+
*(rnr + 1) = *(gnr + 1) = *(bnr + 1) = 0;
|
1029
|
+
}
|
1030
|
+
|
1031
|
+
*rnr = *gnr = *bnr = 0;
|
1032
|
+
|
1033
|
+
for (col = 0; col < width; col++) {
|
1034
|
+
r = range_limiter[src[0] + error_limiter[*rpr]];
|
1035
|
+
g = range_limiter[src[1] + error_limiter[*gpr]];
|
1036
|
+
b = range_limiter[src[2] + error_limiter[*bpr]];
|
1037
|
+
|
1038
|
+
re = r >> R_SHIFT;
|
1039
|
+
ge = g >> G_SHIFT;
|
1040
|
+
be = b >> B_SHIFT;
|
1041
|
+
|
1042
|
+
cachep = &histogram[re * MR + ge * MG + be];
|
1043
|
+
/* If we have not seen this color before,
|
1044
|
+
find nearest colormap entry
|
1045
|
+
and update the cache */
|
1046
|
+
if (*cachep == 0)
|
1047
|
+
fill_inverse_cmap_rgb(quantobj, histogram, re, ge, be);
|
1048
|
+
|
1049
|
+
index = *cachep - 1;
|
1050
|
+
*dest = index;
|
1051
|
+
|
1052
|
+
color = &quantobj->cmap[index];
|
1053
|
+
re = r - color->red;
|
1054
|
+
ge = g - color->green;
|
1055
|
+
be = b - color->blue;
|
1056
|
+
|
1057
|
+
if (odd_row) {
|
1058
|
+
*(--rpr) += fs_err1[re];
|
1059
|
+
*(--gpr) += fs_err1[ge];
|
1060
|
+
*(--bpr) += fs_err1[be];
|
1061
|
+
|
1062
|
+
*rnr-- += fs_err2[re];
|
1063
|
+
*gnr-- += fs_err2[ge];
|
1064
|
+
*bnr-- += fs_err2[be];
|
1065
|
+
|
1066
|
+
*rnr += fs_err3[re];
|
1067
|
+
*gnr += fs_err3[ge];
|
1068
|
+
*bnr += fs_err3[be];
|
1069
|
+
|
1070
|
+
*(rnr - 1) = fs_err4[re];
|
1071
|
+
*(gnr - 1) = fs_err4[ge];
|
1072
|
+
*(bnr - 1) = fs_err4[be];
|
1073
|
+
} else {
|
1074
|
+
*(++rpr) += fs_err1[re];
|
1075
|
+
*(++gpr) += fs_err1[ge];
|
1076
|
+
*(++bpr) += fs_err1[be];
|
1077
|
+
|
1078
|
+
*rnr++ += fs_err2[re];
|
1079
|
+
*gnr++ += fs_err2[ge];
|
1080
|
+
*bnr++ += fs_err2[be];
|
1081
|
+
|
1082
|
+
*rnr += fs_err3[re];
|
1083
|
+
*gnr += fs_err3[ge];
|
1084
|
+
*bnr += fs_err3[be];
|
1085
|
+
|
1086
|
+
*(rnr + 1) = fs_err4[re];
|
1087
|
+
*(gnr + 1) = fs_err4[ge];
|
1088
|
+
*(bnr + 1) = fs_err4[be];
|
1089
|
+
}
|
1090
|
+
|
1091
|
+
dest += step_dest;
|
1092
|
+
src += step_src;
|
1093
|
+
}
|
1094
|
+
|
1095
|
+
tmp = red_n_row;
|
1096
|
+
red_n_row = red_p_row;
|
1097
|
+
red_p_row = tmp;
|
1098
|
+
|
1099
|
+
tmp = grn_n_row;
|
1100
|
+
grn_n_row = grn_p_row;
|
1101
|
+
grn_p_row = tmp;
|
1102
|
+
|
1103
|
+
tmp = blu_n_row;
|
1104
|
+
blu_n_row = blu_p_row;
|
1105
|
+
blu_p_row = tmp;
|
1106
|
+
|
1107
|
+
odd_row = !odd_row;
|
1108
|
+
|
1109
|
+
}
|
1110
|
+
|
1111
|
+
xfree(error_limiter - 255);
|
1112
|
+
xfree(red_n_row);
|
1113
|
+
xfree(red_p_row);
|
1114
|
+
xfree(grn_n_row);
|
1115
|
+
xfree(grn_p_row);
|
1116
|
+
xfree(blu_n_row);
|
1117
|
+
xfree(blu_p_row);
|
1118
|
+
}
|
1119
|
+
|
1120
|
+
static QuantizeObj *initialize_median_cut(int num_colors, int dither_type)
|
1121
|
+
{
|
1122
|
+
QuantizeObj *quantobj;
|
1123
|
+
|
1124
|
+
/* Initialize the data structures */
|
1125
|
+
quantobj = malloc(sizeof(QuantizeObj));
|
1126
|
+
if (!quantobj) error("could not alloc mem");
|
1127
|
+
|
1128
|
+
quantobj->histogram = malloc(sizeof(ColorFreq) *
|
1129
|
+
HIST_R_ELEMS *
|
1130
|
+
HIST_G_ELEMS *
|
1131
|
+
HIST_B_ELEMS);
|
1132
|
+
if (!quantobj->histogram) error("could not alloc mem");
|
1133
|
+
|
1134
|
+
quantobj->desired_number_of_colors = num_colors;
|
1135
|
+
quantobj->first_pass = median_cut_pass1_rgb;
|
1136
|
+
|
1137
|
+
switch (dither_type) {
|
1138
|
+
case NODITHER:
|
1139
|
+
quantobj->second_pass = median_cut_pass2_no_dither_rgb;
|
1140
|
+
break;
|
1141
|
+
case FSDITHER:
|
1142
|
+
quantobj->second_pass = median_cut_pass2_fs_dither_rgb;
|
1143
|
+
break;
|
1144
|
+
}
|
1145
|
+
|
1146
|
+
return quantobj;
|
1147
|
+
}
|
1148
|
+
|
1149
|
+
///* Externs: */
|
1150
|
+
//extern unsigned char *Picture256;
|
1151
|
+
//extern unsigned char QuantizedPalette[768];
|
1152
|
+
|
1153
|
+
//void to_indexed(char*input,long ncolors,long dither,int width,int height)
|
1154
|
+
void to_indexed(char*input,long ncolors,long dither,int width,int height,
|
1155
|
+
unsigned char *Picture256, unsigned char *QuantizedPalette)
|
1156
|
+
{
|
1157
|
+
QuantizeObj *quantobj;
|
1158
|
+
int i, j;
|
1159
|
+
|
1160
|
+
quantobj = initialize_median_cut(ncolors, dither ? FSDITHER : NODITHER);
|
1161
|
+
(*quantobj->first_pass) (quantobj, input, Picture256, width, height);
|
1162
|
+
(*quantobj->second_pass) (quantobj, input, Picture256, width, height);
|
1163
|
+
for (i = 0, j = 0; i < quantobj->actual_number_of_colors; i++) {
|
1164
|
+
//#if 0
|
1165
|
+
// rgb
|
1166
|
+
QuantizedPalette[j++] = quantobj->cmap[i].red;
|
1167
|
+
QuantizedPalette[j++] = quantobj->cmap[i].green;
|
1168
|
+
QuantizedPalette[j++] = quantobj->cmap[i].blue;
|
1169
|
+
//#else
|
1170
|
+
// bgr
|
1171
|
+
// QuantizedPalette[j++] = quantobj->cmap[i].blue;
|
1172
|
+
// QuantizedPalette[j++] = quantobj->cmap[i].green;
|
1173
|
+
// QuantizedPalette[j++] = quantobj->cmap[i].red;
|
1174
|
+
//#endif
|
1175
|
+
}
|
1176
|
+
xfree(quantobj->histogram);
|
1177
|
+
xfree(quantobj);
|
1178
|
+
}
|
1179
|
+
/*-*/
|