1 /*
2 * xvsmooth.c - smoothing/color dither routines for XV
3 *
4 * Contains:
5 * byte *SmoothResize(src8, swide, shigh, dwide, dhigh,
6 * rmap, gmap, bmap, rdmap, gdmap, bdmap, maplen)
7 * byte *Smooth24(pic824, is24, swide, shigh, dwide, dhigh,
8 * rmap, gmap, bmap)
9 * byte *DoColorDither(pic24, pic8, w, h, rmap,gmap,bmap,
10 * rdisp, gdisp, bdisp, maplen)
11 * byte *Do332ColorDither(pic24, pic8, w, h, rmap,gmap,bmap,
12 * rdisp, gdisp, bdisp, maplen)
13 */
14
15 #include "copyright.h"
16
17 #include "xv.h"
18
19 static int smoothX PARM((byte *, byte *, int, int, int, int, int,
20 byte *, byte *, byte *));
21 static int smoothY PARM((byte *, byte *, int, int, int, int, int,
22 byte *, byte *, byte *));
23 static int smoothXY PARM((byte *, byte *, int, int, int, int, int,
24 byte *, byte *, byte *));
25
26
27 /***************************************************/
SmoothResize(srcpic8,swide,shigh,dwide,dhigh,rmap,gmap,bmap,rdmap,gdmap,bdmap,maplen)28 byte *SmoothResize(srcpic8, swide, shigh, dwide, dhigh,
29 rmap, gmap, bmap, rdmap, gdmap, bdmap, maplen)
30 byte *srcpic8, *rmap, *gmap, *bmap, *rdmap, *gdmap, *bdmap;
31 int swide, shigh, dwide, dhigh, maplen;
32 {
33 /* generic interface to Smooth and ColorDither code.
34 given an 8-bit-per, swide * shigh image with colormap rmap,gmap,bmap,
35 will generate a new 8-bit-per, dwide * dhigh image, which is dithered
36 using colors found in rdmap, gdmap, bdmap arrays */
37
38 /* returns ptr to a dwide*dhigh array of bytes, or NULL on failure */
39
40 byte *pic24, *pic8;
41
42 pic24 = Smooth24(srcpic8, 0, swide, shigh, dwide, dhigh, rmap, gmap, bmap);
43
44 if (pic24) {
45 pic8 = DoColorDither(pic24, NULL, dwide, dhigh, rmap, gmap, bmap,
46 rdmap, gdmap, bdmap, maplen);
47 free(pic24);
48 return pic8;
49 }
50
51 return (byte *) NULL;
52 }
53
54
55
56 /***************************************************/
Smooth24(pic824,is24,swide,shigh,dwide,dhigh,rmap,gmap,bmap)57 byte *Smooth24(pic824, is24, swide, shigh, dwide, dhigh, rmap, gmap, bmap)
58 byte *pic824, *rmap, *gmap, *bmap;
59 int is24, swide, shigh, dwide, dhigh;
60 {
61 /* does a SMOOTH resize from pic824 (which is either a swide*shigh, 8-bit
62 pic, with colormap rmap,gmap,bmap OR a swide*shigh, 24-bit image, based
63 on whether 'is24' is set) into a dwide * dhigh 24-bit image
64
65 returns a dwide*dhigh 24bit image, or NULL on failure (malloc) */
66 /* rmap,gmap,bmap should be 'desired' colors */
67
68 byte *pic24, *pp;
69 int *cxtab, *pxtab;
70 int y1Off, cyOff;
71 int ex, ey, cx, cy, px, py, apx, apy, x1, y1;
72 int cA, cB, cC, cD;
73 int pA, pB, pC, pD;
74 int retval, bperpix;
75
76 cA = cB = cC = cD = 0;
77 pp = pic24 = (byte *) malloc((size_t) (dwide * dhigh * 3));
78 if (!pic24) {
79 fprintf(stderr,"unable to malloc pic24 in 'Smooth24()'\n");
80 return pic24;
81 }
82
83 bperpix = (is24) ? 3 : 1;
84
85 /* decide which smoothing routine to use based on type of expansion */
86 if (dwide < swide && dhigh < shigh)
87 retval = smoothXY(pic24, pic824, is24, swide, shigh, dwide, dhigh,
88 rmap, gmap, bmap);
89
90 else if (dwide < swide && dhigh >= shigh)
91 retval = smoothX (pic24, pic824, is24, swide, shigh, dwide, dhigh,
92 rmap, gmap, bmap);
93
94 else if (dwide >= swide && dhigh < shigh)
95 retval = smoothY (pic24, pic824, is24, swide, shigh, dwide, dhigh,
96 rmap, gmap, bmap);
97
98 else {
99 /* dwide >= swide && dhigh >= shigh */
100
101 /* cx,cy = original pixel in pic824. px,py = relative position
102 of pixel ex,ey inside of cx,cy as percentages +-50%, +-50%.
103 0,0 = middle of pixel */
104
105 /* we can save a lot of time by precomputing cxtab[] and pxtab[], both
106 dwide arrays of ints that contain values for the equations:
107 cx = (ex * swide) / dwide;
108 px = ((ex * swide * 128) / dwide) - (cx * 128) - 64; */
109
110 cxtab = (int *) malloc(dwide * sizeof(int));
111 if (!cxtab) { free(pic24); return NULL; }
112
113 pxtab = (int *) malloc(dwide * sizeof(int));
114 if (!pxtab) { free(pic24); free(cxtab); return NULL; }
115
116 for (ex=0; ex<dwide; ex++) {
117 cxtab[ex] = (ex * swide) / dwide;
118 pxtab[ex] = (((ex * swide)* 128) / dwide)
119 - (cxtab[ex] * 128) - 64;
120 }
121
122 for (ey=0; ey<dhigh; ey++) {
123 byte *pptr, rA, gA, bA, rB, gB, bB, rC, gC, bC, rD, gD, bD;
124
125 ProgressMeter(0, (dhigh)-1, ey, "Smooth");
126
127 cy = (ey * shigh) / dhigh;
128 py = (((ey * shigh) * 128) / dhigh) - (cy * 128) - 64;
129 if (py<0) { y1 = cy-1; if (y1<0) y1=0; }
130 else { y1 = cy+1; if (y1>shigh-1) y1=shigh-1; }
131
132 cyOff = cy * swide * bperpix; /* current line */
133 y1Off = y1 * swide * bperpix; /* up or down one line, depending */
134
135 if ((ey&15) == 0) WaitCursor();
136
137 for (ex=0; ex<dwide; ex++) {
138 rA = rB = rC = rD = gA = gB = gC = gD = bA = bB = bC = bD = 0;
139
140 cx = cxtab[ex];
141 px = pxtab[ex];
142
143 if (px<0) { x1 = cx-1; if (x1<0) x1=0; }
144 else { x1 = cx+1; if (x1>swide-1) x1=swide-1; }
145
146 if (is24) {
147 pptr = pic824 + y1Off + x1*bperpix; /* corner pixel */
148 rA = *pptr++; gA = *pptr++; bA = *pptr++;
149
150 pptr = pic824 + y1Off + cx*bperpix; /* up/down center pixel */
151 rB = *pptr++; gB = *pptr++; bB = *pptr++;
152
153 pptr = pic824 + cyOff + x1*bperpix; /* left/right center pixel */
154 rC = *pptr++; gC = *pptr++; bC = *pptr++;
155
156 pptr = pic824 + cyOff + cx*bperpix; /* center pixel */
157 rD = *pptr++; gD = *pptr++; bD = *pptr++;
158 }
159 else { /* 8-bit picture */
160 cA = pic824[y1Off + x1]; /* corner pixel */
161 cB = pic824[y1Off + cx]; /* up/down center pixel */
162 cC = pic824[cyOff + x1]; /* left/right center pixel */
163 cD = pic824[cyOff + cx]; /* center pixel */
164 }
165
166 /* quick check */
167 if (!is24 && cA == cB && cB == cC && cC == cD) {
168 /* set this pixel to the same color as in pic8 */
169 *pp++ = rmap[cD]; *pp++ = gmap[cD]; *pp++ = bmap[cD];
170 }
171
172 else {
173 /* compute weighting factors */
174 apx = abs(px); apy = abs(py);
175 pA = (apx * apy) >> 7; /* div 128 */
176 pB = (apy * (128 - apx)) >> 7; /* div 128 */
177 pC = (apx * (128 - apy)) >> 7; /* div 128 */
178 pD = 128 - (pA + pB + pC);
179
180 if (is24) {
181 *pp++ = (((int) (pA * rA))>>7) + (((int) (pB * rB))>>7) +
182 (((int) (pC * rC))>>7) + (((int) (pD * rD))>>7);
183
184 *pp++ = (((int) (pA * gA))>>7) + (((int) (pB * gB))>>7) +
185 (((int) (pC * gC))>>7) + (((int) (pD * gD))>>7);
186
187 *pp++ = (((int) (pA * bA))>>7) + (((int) (pB * bB))>>7) +
188 (((int) (pC * bC))>>7) + (((int) (pD * bD))>>7);
189 }
190 else { /* 8-bit pic */
191 *pp++ = (((int)(pA * rmap[cA]))>>7) + (((int)(pB * rmap[cB]))>>7) +
192 (((int)(pC * rmap[cC]))>>7) + (((int)(pD * rmap[cD]))>>7);
193
194 *pp++ = (((int)(pA * gmap[cA]))>>7) + (((int)(pB * gmap[cB]))>>7) +
195 (((int)(pC * gmap[cC]))>>7) + (((int)(pD * gmap[cD]))>>7);
196
197 *pp++ = (((int)(pA * bmap[cA]))>>7) + (((int)(pB * bmap[cB]))>>7) +
198 (((int)(pC * bmap[cC]))>>7) + (((int)(pD * bmap[cD]))>>7);
199 }
200 }
201 }
202 }
203
204 free(cxtab);
205 free(pxtab);
206 retval = 0; /* okay */
207 }
208
209 if (retval) { /* one of the Smooth**() methods failed */
210 free(pic24);
211 pic24 = (byte *) NULL;
212 }
213
214 return pic24;
215 }
216
217
218
219
220 /***************************************************/
smoothX(pic24,pic824,is24,swide,shigh,dwide,dhigh,rmap,gmap,bmap)221 static int smoothX(pic24, pic824, is24, swide, shigh, dwide, dhigh,
222 rmap, gmap, bmap)
223 byte *pic24, *pic824, *rmap, *gmap, *bmap;
224 int is24, swide, shigh, dwide, dhigh;
225 {
226 byte *cptr, *cptr1;
227 int i, j;
228 int *lbufR, *lbufG, *lbufB;
229 int pixR, pixG, pixB, bperpix;
230 int pcnt0, pcnt1, lastpix, pixcnt, thisline, ypcnt;
231 int *pixarr, *paptr;
232
233 /* returns '0' if okay, '1' if failed (malloc) */
234
235 /* for case where pic8 is shrunk horizontally and stretched vertically
236 maps pic8 into an dwide * dhigh 24-bit picture. Only works correctly
237 when swide>=dwide and shigh<=dhigh */
238
239
240 /* malloc some arrays */
241 lbufR = (int *) calloc((size_t) swide, sizeof(int));
242 lbufG = (int *) calloc((size_t) swide, sizeof(int));
243 lbufB = (int *) calloc((size_t) swide, sizeof(int));
244 pixarr = (int *) calloc((size_t) swide+1, sizeof(int));
245
246 if (!lbufR || !lbufG || !lbufB || !pixarr) {
247 if (lbufR) free(lbufR);
248 if (lbufG) free(lbufG);
249 if (lbufB) free(lbufB);
250 if (pixarr) free(pixarr);
251 return 1;
252 }
253
254 bperpix = (is24) ? 3 : 1;
255
256 for (j=0; j<=swide; j++)
257 pixarr[j] = (j*dwide + (15*swide)/16) / swide;
258
259 cptr = pic824; cptr1 = cptr + swide * bperpix;
260
261 for (i=0; i<dhigh; i++) {
262 ProgressMeter(0, (dhigh)-1, i, "Smooth");
263 if ((i&15) == 0) WaitCursor();
264
265 ypcnt = (((i*shigh)<<6) / dhigh) - 32;
266 if (ypcnt<0) ypcnt = 0;
267
268 pcnt1 = ypcnt & 0x3f; /* 64ths of NEXT line to use */
269 pcnt0 = 64 - pcnt1; /* 64ths of THIS line to use */
270
271 thisline = ypcnt>>6;
272
273 cptr = pic824 + thisline * swide * bperpix;
274 if (thisline+1 < shigh) cptr1 = cptr + swide * bperpix;
275 else cptr1 = cptr;
276
277 if (is24) {
278 for (j=0; j<swide; j++) {
279 lbufR[j] = ((int) ((*cptr++ * pcnt0) + (*cptr1++ * pcnt1))) >> 6;
280 lbufG[j] = ((int) ((*cptr++ * pcnt0) + (*cptr1++ * pcnt1))) >> 6;
281 lbufB[j] = ((int) ((*cptr++ * pcnt0) + (*cptr1++ * pcnt1))) >> 6;
282 }
283 }
284 else { /* 8-bit input pic */
285 for (j=0; j<swide; j++, cptr++, cptr1++) {
286 lbufR[j] = ((int)((rmap[*cptr]* pcnt0) + (rmap[*cptr1]* pcnt1))) >> 6;
287 lbufG[j] = ((int)((gmap[*cptr]* pcnt0) + (gmap[*cptr1]* pcnt1))) >> 6;
288 lbufB[j] = ((int)((bmap[*cptr]* pcnt0) + (bmap[*cptr1]* pcnt1))) >> 6;
289 }
290 }
291
292 pixR = pixG = pixB = pixcnt = lastpix = 0;
293
294 for (j=0, paptr=pixarr; j<=swide; j++,paptr++) {
295 if (*paptr != lastpix) { /* write a pixel to pic24 */
296 if (!pixcnt) pixcnt = 1; /* this NEVER happens: quiets compilers */
297 *pic24++ = pixR / pixcnt;
298 *pic24++ = pixG / pixcnt;
299 *pic24++ = pixB / pixcnt;
300 lastpix = *paptr;
301 pixR = pixG = pixB = pixcnt = 0;
302 }
303
304 if (j<swide) {
305 pixR += lbufR[j];
306 pixG += lbufG[j];
307 pixB += lbufB[j];
308 pixcnt++;
309 }
310 }
311 }
312
313 free(lbufR); free(lbufG); free(lbufB); free(pixarr);
314 return 0;
315 }
316
317
318
319
320
321
322 /***************************************************/
smoothY(pic24,pic824,is24,swide,shigh,dwide,dhigh,rmap,gmap,bmap)323 static int smoothY(pic24, pic824, is24, swide, shigh, dwide, dhigh,
324 rmap, gmap, bmap)
325 byte *pic24, *pic824, *rmap, *gmap, *bmap;
326 int is24, swide, shigh, dwide, dhigh;
327 {
328 byte *clptr, *cptr, *cptr1;
329 int i, j, bperpix;
330 int *lbufR, *lbufG, *lbufB, *pct0, *pct1, *cxarr, *cxptr;
331 int lastline, thisline, linecnt;
332 int retval;
333
334
335 /* returns '0' if okay, '1' if failed (malloc) */
336
337 /* for case where pic8 is shrunk vertically and stretched horizontally
338 maps pic8 into a dwide * dhigh 24-bit picture. Only works correctly
339 when swide<=dwide and shigh>=dhigh */
340
341 retval = 0; /* no probs, yet... */
342
343 bperpix = (is24) ? 3 : 1;
344
345 lbufR = lbufG = lbufB = pct0 = pct1 = cxarr = NULL;
346 lbufR = (int *) calloc((size_t) dwide, sizeof(int));
347 lbufG = (int *) calloc((size_t) dwide, sizeof(int));
348 lbufB = (int *) calloc((size_t) dwide, sizeof(int));
349 pct0 = (int *) calloc((size_t) dwide, sizeof(int));
350 pct1 = (int *) calloc((size_t) dwide, sizeof(int));
351 cxarr = (int *) calloc((size_t) dwide, sizeof(int));
352
353 if (!lbufR || !lbufG || !lbufB || !pct0 || ! pct1 || !cxarr) {
354 retval = 1;
355 goto smyexit;
356 }
357
358
359
360 for (i=0; i<dwide; i++) { /* precompute some handy tables */
361 int cx64;
362 cx64 = (((i * swide) << 6) / dwide) - 32;
363 if (cx64<0) cx64 = 0;
364 pct1[i] = cx64 & 0x3f;
365 pct0[i] = 64 - pct1[i];
366 cxarr[i] = cx64 >> 6;
367 }
368
369
370 lastline = linecnt = 0;
371
372 for (i=0, clptr=pic824; i<=shigh; i++, clptr+=swide*bperpix) {
373 ProgressMeter(0, shigh, i, "Smooth");
374 if ((i&15) == 0) WaitCursor();
375
376 thisline = (i * dhigh + (15*shigh)/16) / shigh;
377
378 if (thisline != lastline) { /* copy a line to pic24 */
379 for (j=0; j<dwide; j++) {
380 *pic24++ = lbufR[j] / linecnt;
381 *pic24++ = lbufG[j] / linecnt;
382 *pic24++ = lbufB[j] / linecnt;
383 }
384
385 xvbzero( (char *) lbufR, dwide * sizeof(int)); /* clear out line bufs */
386 xvbzero( (char *) lbufG, dwide * sizeof(int));
387 xvbzero( (char *) lbufB, dwide * sizeof(int));
388 linecnt = 0; lastline = thisline;
389 }
390
391
392 for (j=0, cxptr=cxarr; j<dwide; j++, cxptr++) {
393 cptr = clptr + *cxptr * bperpix;
394 if (*cxptr < swide-1) cptr1 = cptr + 1*bperpix;
395 else cptr1 = cptr;
396
397 if (is24) {
398 lbufR[j] += ((int)((*cptr++ * pct0[j]) + (*cptr1++ * pct1[j]))) >> 6;
399 lbufG[j] += ((int)((*cptr++ * pct0[j]) + (*cptr1++ * pct1[j]))) >> 6;
400 lbufB[j] += ((int)((*cptr++ * pct0[j]) + (*cptr1++ * pct1[j]))) >> 6;
401 }
402 else { /* 8-bit input pic */
403 lbufR[j] += ((int)((rmap[*cptr]*pct0[j])+(rmap[*cptr1]*pct1[j]))) >> 6;
404 lbufG[j] += ((int)((gmap[*cptr]*pct0[j])+(gmap[*cptr1]*pct1[j]))) >> 6;
405 lbufB[j] += ((int)((bmap[*cptr]*pct0[j])+(bmap[*cptr1]*pct1[j]))) >> 6;
406 }
407 }
408
409 linecnt++;
410 }
411
412
413 smyexit:
414 if (lbufR) free(lbufR);
415 if (lbufG) free(lbufG);
416 if (lbufB) free(lbufB);
417 if (pct0) free(pct0);
418 if (pct1) free(pct1);
419 if (cxarr) free(cxarr);
420
421 return retval;
422 }
423
424
425
426
427
428
429 /***************************************************/
smoothXY(pic24,pic824,is24,swide,shigh,dwide,dhigh,rmap,gmap,bmap)430 static int smoothXY(pic24, pic824, is24, swide, shigh, dwide, dhigh,
431 rmap, gmap, bmap)
432 byte *pic24, *pic824, *rmap, *gmap, *bmap;
433 int is24, swide, shigh, dwide, dhigh;
434 {
435 byte *cptr;
436 int i,j;
437 int *lbufR, *lbufG, *lbufB;
438 int pixR, pixG, pixB, bperpix;
439 int lastline, thisline, lastpix, linecnt, pixcnt;
440 int *pixarr, *paptr;
441
442
443 /* returns '0' if okay, '1' if failed (malloc) */
444
445 /* shrinks pic8 into a dwide * dhigh 24-bit picture. Only works correctly
446 when swide>=dwide and shigh>=dhigh (ie, the picture is shrunk on both
447 axes) */
448
449
450 /* malloc some arrays */
451 lbufR = (int *) calloc((size_t) swide, sizeof(int));
452 lbufG = (int *) calloc((size_t) swide, sizeof(int));
453 lbufB = (int *) calloc((size_t) swide, sizeof(int));
454 pixarr = (int *) calloc((size_t) swide+1, sizeof(int));
455 if (!lbufR || !lbufG || !lbufB || !pixarr) {
456 if (lbufR) free(lbufR);
457 if (lbufG) free(lbufG);
458 if (lbufB) free(lbufB);
459 if (pixarr) free(pixarr);
460 return 1;
461 }
462
463 bperpix = (is24) ? 3 : 1;
464
465 for (j=0; j<=swide; j++)
466 pixarr[j] = (j*dwide + (15*swide)/16) / swide;
467
468 lastline = linecnt = pixR = pixG = pixB = 0;
469 cptr = pic824;
470
471 for (i=0; i<=shigh; i++) {
472 ProgressMeter(0, shigh, i, "Smooth");
473 if ((i&15) == 0) WaitCursor();
474
475 thisline = (i * dhigh + (15*shigh)/16 ) / shigh;
476
477 if ((thisline != lastline)) { /* copy a line to pic24 */
478 pixR = pixG = pixB = pixcnt = lastpix = 0;
479
480 for (j=0, paptr=pixarr; j<=swide; j++,paptr++) {
481 if (*paptr != lastpix) { /* write a pixel to pic24 */
482 if (!pixcnt) pixcnt = 1; /* NEVER happens: quiets compilers */
483 *pic24++ = (pixR/linecnt) / pixcnt;
484 *pic24++ = (pixG/linecnt) / pixcnt;
485 *pic24++ = (pixB/linecnt) / pixcnt;
486 lastpix = *paptr;
487 pixR = pixG = pixB = pixcnt = 0;
488 }
489
490 if (j<swide) {
491 pixR += lbufR[j];
492 pixG += lbufG[j];
493 pixB += lbufB[j];
494 pixcnt++;
495 }
496 }
497
498 lastline = thisline;
499 xvbzero( (char *) lbufR, swide * sizeof(int)); /* clear out line bufs */
500 xvbzero( (char *) lbufG, swide * sizeof(int));
501 xvbzero( (char *) lbufB, swide * sizeof(int));
502 linecnt = 0;
503 }
504
505 if (i<shigh) {
506 if (is24) {
507 for (j=0; j<swide; j++) {
508 lbufR[j] += *cptr++;
509 lbufG[j] += *cptr++;
510 lbufB[j] += *cptr++;
511 }
512 }
513 else {
514 for (j=0; j<swide; j++, cptr++) {
515 lbufR[j] += rmap[*cptr];
516 lbufG[j] += gmap[*cptr];
517 lbufB[j] += bmap[*cptr];
518 }
519 }
520
521 linecnt++;
522 }
523 }
524
525 free(lbufR); free(lbufG); free(lbufB); free(pixarr);
526 return 0;
527 }
528
529
530
531
532 /********************************************/
DoColorDither(pic24,pic8,w,h,rmap,gmap,bmap,rdisp,gdisp,bdisp,maplen)533 byte *DoColorDither(pic24, pic8, w, h, rmap, gmap, bmap,
534 rdisp, gdisp, bdisp, maplen)
535 byte *pic24, *pic8, *rmap, *gmap, *bmap, *rdisp, *gdisp, *bdisp;
536 int w, h, maplen;
537 {
538 /* takes a 24 bit picture, of size w*h, dithers with the colors in
539 rdisp, gdisp, bdisp (which have already been allocated),
540 and generates an 8-bit w*h image, which it returns.
541 ignores input value 'pic8'
542 returns NULL on error
543
544 note: the rdisp,gdisp,bdisp arrays should be the 'displayed' colors,
545 not the 'desired' colors
546
547 if pic24 is NULL, uses the passed-in pic8 (an 8-bit image) as
548 the source, and the rmap,gmap,bmap arrays as the desired colors */
549
550 byte *np, *ep, *newpic;
551 short *cache;
552 int r2, g2, b2;
553 int *thisline, *nextline, *thisptr, *nextptr, *tmpptr;
554 int i, j, rerr, gerr, berr, pwide3;
555 int imax, jmax;
556 int key;
557 long cnt1, cnt2;
558 int fserrmap[512]; /* -255 .. 0 .. +255 */
559
560 /* compute somewhat non-linear floyd-steinberg error mapping table */
561 for (i=j=0; i<=0x40; i++,j++)
562 { fserrmap[256+i] = j; fserrmap[256-i] = -j; }
563 for ( ; i<0x80; i++, j += !(i&1) ? 1 : 0)
564 { fserrmap[256+i] = j; fserrmap[256-i] = -j; }
565 for ( ; i<=0xff; i++)
566 { fserrmap[256+i] = j; fserrmap[256-i] = -j; }
567
568
569 cnt1 = cnt2 = 0;
570 pwide3 = w*3; imax = h-1; jmax = w-1;
571 ep = (pic24) ? pic24 : pic8;
572
573 /* attempt to malloc things */
574 newpic = (byte *) malloc((size_t) (w * h));
575 cache = (short *) calloc((size_t) (2<<14), sizeof(short));
576 thisline = (int *) malloc(pwide3 * sizeof(int));
577 nextline = (int *) malloc(pwide3 * sizeof(int));
578 if (!cache || !newpic || !thisline || !nextline) {
579 if (newpic) free(newpic);
580 if (cache) free(cache);
581 if (thisline) free(thisline);
582 if (nextline) free(nextline);
583
584 return (byte *) NULL;
585 }
586
587 np = newpic;
588
589 /* get first line of picture */
590
591 if (pic24) {
592 for (j=pwide3, tmpptr=nextline; j; j--, ep++)
593 *tmpptr++ = (int) *ep;
594 }
595 else {
596 for (j=w, tmpptr=nextline; j; j--, ep++) {
597 *tmpptr++ = (int) rmap[*ep];
598 *tmpptr++ = (int) gmap[*ep];
599 *tmpptr++ = (int) bmap[*ep];
600 }
601 }
602
603
604 for (i=0; i<h; i++) {
605 ProgressMeter(0, h-1, i, "Dither");
606 if ((i&15) == 0) WaitCursor();
607
608 tmpptr = thisline; thisline = nextline; nextline = tmpptr; /* swap */
609
610 if (i!=imax) { /* get next line */
611 if (!pic24)
612 for (j=w, tmpptr=nextline; j; j--, ep++) {
613 *tmpptr++ = (int) rmap[*ep];
614 *tmpptr++ = (int) gmap[*ep];
615 *tmpptr++ = (int) bmap[*ep];
616 }
617 else
618 for (j=pwide3, tmpptr=nextline; j; j--, ep++) *tmpptr++ = (int) *ep;
619 }
620
621 /* dither a line */
622 for (j=0, thisptr=thisline, nextptr=nextline; j<w; j++,np++) {
623 int k, d, mind, closest;
624
625 r2 = *thisptr++; g2 = *thisptr++; b2 = *thisptr++;
626
627 /* map r2,g2,b2 components (could be outside 0..255 range)
628 into 0..255 range */
629
630 if (r2<0 || g2<0 || b2<0) { /* are there any negatives in RGB? */
631 if (r2<g2) { if (r2<b2) k = 0; else k = 2; }
632 else { if (g2<b2) k = 1; else k = 2; }
633
634 switch (k) {
635 case 0: g2 -= r2; b2 -= r2; d = (abs(r2) * 3) / 2; /* RED */
636 r2 = 0;
637 g2 = (g2>d) ? g2 - d : 0;
638 b2 = (b2>d) ? b2 - d : 0;
639 break;
640
641 case 1: r2 -= g2; b2 -= g2; d = (abs(g2) * 3) / 2; /* GREEN */
642 r2 = (r2>d) ? r2 - d : 0;
643 g2 = 0;
644 b2 = (b2>d) ? b2 - d : 0;
645 break;
646
647 case 2: r2 -= b2; g2 -= b2; d = (abs(b2) * 3) / 2; /* BLUE */
648 r2 = (r2>d) ? r2 - d : 0;
649 g2 = (g2>d) ? g2 - d : 0;
650 b2 = 0;
651 break;
652 }
653 }
654
655 if (r2>255 || g2>255 || b2>255) { /* any overflows in RGB? */
656 if (r2>g2) { if (r2>b2) k = 0; else k = 2; }
657 else { if (g2>b2) k = 1; else k = 2; }
658
659 switch (k) {
660 case 0: g2 = (g2*255)/r2; b2 = (b2*255)/r2; r2=255; break;
661 case 1: r2 = (r2*255)/g2; b2 = (b2*255)/g2; g2=255; break;
662 case 2: r2 = (r2*255)/b2; g2 = (g2*255)/b2; b2=255; break;
663 }
664 }
665
666 key = ((r2&0xf8)<<6) | ((g2&0xf8)<<1) | (b2>>4);
667 if (key >= (2<<14)) FatalError("'key' overflow in DoColorDither()");
668
669 if (cache[key]) { *np = (byte) (cache[key] - 1); cnt1++; }
670 else {
671 /* not in cache, have to search the colortable */
672 cnt2++;
673
674 mind = 10000;
675 for (k=closest=0; k<maplen && mind>7; k++) {
676 d = abs(r2 - rdisp[k])
677 + abs(g2 - gdisp[k])
678 + abs(b2 - bdisp[k]);
679 if (d<mind) { mind = d; closest = k; }
680 }
681 cache[key] = closest + 1;
682 *np = closest;
683 }
684
685
686 /* propogate the error */
687 rerr = r2 - rdisp[*np];
688 gerr = g2 - gdisp[*np];
689 berr = b2 - bdisp[*np];
690
691
692 RANGE(rerr, -255, 255);
693 RANGE(gerr, -255, 255);
694 RANGE(berr, -255, 255);
695 rerr = fserrmap[256+rerr];
696 gerr = fserrmap[256+gerr];
697 berr = fserrmap[256+berr];
698
699
700
701 if (j!=jmax) { /* adjust RIGHT pixel */
702 thisptr[0] += (rerr*7)/16;
703 thisptr[1] += (gerr*7)/16;
704 thisptr[2] += (berr*7)/16;
705 }
706
707 if (i!=imax) { /* do BOTTOM pixel */
708 nextptr[0] += (rerr*5)/16;
709 nextptr[1] += (gerr*5)/16;
710 nextptr[2] += (berr*5)/16;
711
712 if (j>0) { /* do BOTTOM LEFT pixel */
713 nextptr[-3] += (rerr*3)/16;
714 nextptr[-2] += (gerr*3)/16;
715 nextptr[-1] += (berr*3)/16;
716 }
717
718 if (j!=jmax) { /* do BOTTOM RIGHT pixel */
719 nextptr[3] += rerr/16;
720 nextptr[4] += gerr/16;
721 nextptr[5] += berr/16;
722 }
723 nextptr += 3;
724 }
725 }
726 }
727
728
729 free(thisline); free(nextline);
730 free(cache);
731
732 return newpic;
733 }
734
735
736
737 /********************************************/
Do332ColorDither(pic24,pic8,w,h,rmap,gmap,bmap,rdisp,gdisp,bdisp,maplen)738 byte *Do332ColorDither(pic24, pic8, w, h, rmap, gmap, bmap,
739 rdisp, gdisp, bdisp, maplen)
740 byte *pic24, *pic8, *rmap, *gmap, *bmap, *rdisp, *gdisp, *bdisp;
741 int w, h, maplen;
742 {
743 /* some sort of color dither optimized for the 332 std cmap */
744
745 /* takes a 24 bit picture, of size w*h, dithers with the colors in
746 rdisp, gdisp, bdisp (which have already been allocated),
747 and generates an 8-bit w*h image, which it returns.
748 ignores input value 'pic8'
749 returns NULL on error
750
751 note: the rdisp,gdisp,bdisp arrays should be the 'displayed' colors,
752 not the 'desired' colors
753
754 if pic24 is NULL, uses the passed-in pic8 (an 8-bit image) as
755 the source, and the rmap,gmap,bmap arrays as the desired colors */
756
757 byte *np, *ep, *newpic;
758 int r2, g2, b2;
759 int *thisline, *nextline, *thisptr, *nextptr, *tmpptr;
760 int i, j, rerr, gerr, berr, pwide3;
761 int imax, jmax;
762 long cnt1, cnt2;
763 int fserrmap[512]; /* -255 .. 0 .. +255 */
764
765 /* compute somewhat non-linear floyd-steinberg error mapping table */
766 for (i=j=0; i<=0x40; i++,j++)
767 { fserrmap[256+i] = j; fserrmap[256-i] = -j; }
768 for ( ; i<0x80; i++, j += !(i&1) ? 1 : 0)
769 { fserrmap[256+i] = j; fserrmap[256-i] = -j; }
770 for ( ; i<=0xff; i++)
771 { fserrmap[256+i] = j; fserrmap[256-i] = -j; }
772
773
774 cnt1 = cnt2 = 0;
775 pwide3 = w*3; imax = h-1; jmax = w-1;
776
777 /* attempt to malloc things */
778 newpic = (byte *) malloc((size_t) (w * h));
779 thisline = (int *) malloc(pwide3 * sizeof(int));
780 nextline = (int *) malloc(pwide3 * sizeof(int));
781 if (!newpic || !thisline || !nextline) {
782 if (newpic) free(newpic);
783 if (thisline) free(thisline);
784 if (nextline) free(nextline);
785
786 return (byte *) NULL;
787 }
788
789 np = newpic;
790 ep = (pic24) ? pic24 : pic8;
791
792
793 /* get first line of picture */
794
795 if (pic24) {
796 for (j=pwide3, tmpptr=nextline; j; j--, ep++) *tmpptr++ = (int) *ep;
797 }
798 else {
799 for (j=w, tmpptr=nextline; j; j--, ep++) {
800 *tmpptr++ = (int) rmap[*ep];
801 *tmpptr++ = (int) gmap[*ep];
802 *tmpptr++ = (int) bmap[*ep];
803 }
804 }
805
806
807 for (i=0; i<h; i++) {
808 np = newpic + i*w;
809 ProgressMeter(0, h-1, i, "Dither");
810 if ((i&127) == 0) WaitCursor();
811
812 tmpptr = thisline; thisline = nextline; nextline = tmpptr; /* swap */
813
814 if (i!=imax) { /* get next line */
815 if (!pic24)
816 for (j=w, tmpptr=nextline; j; j--, ep++) {
817 *tmpptr++ = (int) rmap[*ep];
818 *tmpptr++ = (int) gmap[*ep];
819 *tmpptr++ = (int) bmap[*ep];
820 }
821 else
822 for (j=pwide3, tmpptr=nextline; j; j--, ep++) *tmpptr++ = (int) *ep;
823 }
824
825
826 /* dither a line, doing odd-lines right-to-left (serpentine) */
827 thisptr = (i&1) ? thisline + w*3 - 3 : thisline;
828 nextptr = (i&1) ? nextline + w*3 - 3 : nextline;
829 if (i&1) np += w-1;
830
831
832 for (j=0; j<w; j++) {
833 int rb,gb,bb;
834
835 r2 = *thisptr++; g2 = *thisptr++; b2 = *thisptr++;
836 if (i&1) thisptr -= 6; /* move left */
837
838 rb = (r2 + 0x10); /* round top 3 bits */
839 RANGE(rb,0,255);
840 rb = rb & 0xe0;
841
842 gb = (g2 + 0x10); /* round 3 bits */
843 RANGE(gb,0,255);
844 gb = gb & 0xe0;
845
846 bb = (b2 + 0x20); /* round 2 bits */
847 RANGE(bb,0,255);
848 bb = bb & 0xc0;
849
850
851 *np = rb | (gb>>3) | (bb>>6);
852
853 /* propogate the error */
854 rerr = r2 - rdisp[*np];
855 gerr = g2 - gdisp[*np];
856 berr = b2 - bdisp[*np];
857
858
859 RANGE(rerr, -255, 255);
860 RANGE(gerr, -255, 255);
861 RANGE(berr, -255, 255);
862 rerr = fserrmap[256+rerr];
863 gerr = fserrmap[256+gerr];
864 berr = fserrmap[256+berr];
865
866
867 if (j!=jmax) { /* adjust LEFT/RIGHT pixel */
868 thisptr[0] += (rerr/2); rerr -= (rerr/2);
869 thisptr[1] += (gerr/2); gerr -= (gerr/2);
870 thisptr[2] += (berr/2); berr -= (berr/2);
871 }
872
873 if (i!=imax) { /* adjust BOTTOM pixel */
874 nextptr[0] += rerr; /* possibly all err if we're at l/r edge */
875 nextptr[1] += gerr;
876 nextptr[2] += berr;
877 }
878
879 if (i&1) { nextptr -= 3; np--; }
880 else { nextptr += 3; np++; }
881 }
882 }
883
884
885 free(thisline); free(nextline);
886
887 return newpic;
888 }
889
890
891
892