source: trunk/kitgen/8.x/blt/generic/bltImage.c@ 191

Last change on this file since 191 was 175, checked in by demin, 12 years ago

initial commit

File size: 73.6 KB
Line 
1
2/*
3 * bltImage.c --
4 *
5 * This module implements image processing procedures for the BLT
6 * toolkit.
7 *
8 * Copyright 1997-1998 Lucent Technologies, Inc.
9 *
10 * Permission to use, copy, modify, and distribute this software and
11 * its documentation for any purpose and without fee is hereby
12 * granted, provided that the above copyright notice appear in all
13 * copies and that both that the copyright notice and warranty
14 * disclaimer appear in supporting documentation, and that the names
15 * of Lucent Technologies any of their entities not be used in
16 * advertising or publicity pertaining to distribution of the software
17 * without specific, written prior permission.
18 *
19 * Lucent Technologies disclaims all warranties with regard to this
20 * software, including all implied warranties of merchantability and
21 * fitness. In no event shall Lucent Technologies be liable for any
22 * special, indirect or consequential damages or any damages
23 * whatsoever resulting from loss of use, data or profits, whether in
24 * an action of contract, negligence or other tortuous action, arising
25 * out of or in connection with the use or performance of this
26 * software.
27 */
28
29#include "bltInt.h"
30#include "bltImage.h"
31#include "bltHash.h"
32#include <X11/Xutil.h>
33#ifndef WIN32
34#include <X11/Xproto.h>
35#endif
36
37#define CLAMP(c) ((((c) < 0.0) ? 0.0 : ((c) > 255.0) ? 255.0 : (c)))
38
39/*
40 *----------------------------------------------------------------------
41 *
42 * Blt_CreateColorImage --
43 *
44 * Allocates a color image of a designated height and width.
45 *
46 * This routine will be augmented with other types of information
47 * such as a color table, etc.
48 *
49 * Results:
50 * Returns the new color image.
51 *
52 *----------------------------------------------------------------------
53 */
54Blt_ColorImage
55Blt_CreateColorImage(width, height)
56 int width, height; /* Dimensions of new image */
57{
58 struct ColorImage *imagePtr;
59 size_t size;
60
61 size = width * height;
62 imagePtr = Blt_Malloc(sizeof(struct ColorImage));
63 assert(imagePtr);
64 imagePtr->bits = Blt_Malloc(sizeof(Pix32) * size);
65 assert(imagePtr->bits);
66
67 imagePtr->width = width;
68 imagePtr->height = height;
69 return imagePtr;
70}
71
72/*
73 *----------------------------------------------------------------------
74 *
75 * Blt_FreeColorImage --
76 *
77 * Deallocates the given color image.
78 *
79 * Results:
80 * None.
81 *
82 *----------------------------------------------------------------------
83 */
84void
85Blt_FreeColorImage(imagePtr)
86 struct ColorImage *imagePtr;
87{
88 Blt_Free(imagePtr->bits);
89 Blt_Free(imagePtr);
90}
91
92void
93Blt_GammaCorrectColorImage(src, newGamma)
94 Blt_ColorImage src;
95 double newGamma;
96{
97 unsigned int nPixels;
98 register Pix32 *srcPtr, *endPtr;
99 register unsigned int i;
100 double value;
101 unsigned char lut[256];
102 double invGamma;
103
104 invGamma = 1.0 / newGamma;
105 for (i = 0; i < 256; i++) {
106 value = 255.0 * pow((double)i / 255.0, invGamma);
107 lut[i] = (unsigned char)CLAMP(value);
108 }
109 nPixels = Blt_ColorImageWidth(src) * Blt_ColorImageHeight(src);
110 srcPtr = Blt_ColorImageBits(src);
111 for (endPtr = srcPtr + nPixels; srcPtr < endPtr; srcPtr++) {
112 srcPtr->Red = lut[srcPtr->Red];
113 srcPtr->Green = lut[srcPtr->Green];
114 srcPtr->Blue = lut[srcPtr->Blue];
115 }
116}
117
118/*
119 *----------------------------------------------------------------------
120 *
121 * Blt_ColorImageToGreyscale --
122 *
123 * Converts a color image to PostScript grey scale (1 component)
124 * output. Luminosity isn't computed using the old NTSC formula,
125 *
126 * Y = 0.299 * Red + 0.587 * Green + 0.114 * Blue
127 *
128 * but the following
129 *
130 * Y = 0.212671 * Red + 0.715160 * Green + 0.072169 * Blue
131 *
132 * which better represents contemporary monitors.
133 *
134 * Results:
135 * The color image is converted to greyscale.
136 *
137 *----------------------------------------------------------------------
138 */
139void
140Blt_ColorImageToGreyscale(image)
141 Blt_ColorImage image;
142{
143 register Pix32 *srcPtr, *endPtr;
144 double Y;
145 int nPixels;
146 int width, height;
147
148 width = Blt_ColorImageWidth(image);
149 height = Blt_ColorImageHeight(image);
150 nPixels = width * height;
151 srcPtr = Blt_ColorImageBits(image);
152 for (endPtr = srcPtr + nPixels; srcPtr < endPtr; srcPtr++) {
153 Y = ((0.212671 * (double)srcPtr->Red) +
154 (0.715160 * (double)srcPtr->Green) +
155 (0.072169 * (double)srcPtr->Blue));
156 srcPtr->Red = srcPtr->Green = srcPtr->Blue = (unsigned char)CLAMP(Y);
157 }
158}
159
160/*
161 *----------------------------------------------------------------------
162 *
163 * Blt_ColorImageToPhoto --
164 *
165 * Translates a color image into a Tk photo.
166 *
167 * Results:
168 * The photo is re-written with the new color image.
169 *
170 *----------------------------------------------------------------------
171 */
172void
173Blt_ColorImageToPhoto(src, photo)
174 Blt_ColorImage src; /* Image to use as source */
175 Tk_PhotoHandle photo; /* Photo to write color image into */
176{
177 Tk_PhotoImageBlock dest;
178 int width, height;
179
180 width = Blt_ColorImageWidth(src);
181 height = Blt_ColorImageHeight(src);
182
183 Tk_PhotoGetImage(photo, &dest);
184 dest.pixelSize = sizeof(Pix32);
185 dest.pitch = sizeof(Pix32) * width;
186 dest.width = width;
187 dest.height = height;
188 dest.offset[0] = Tk_Offset(Pix32, Red);
189 dest.offset[1] = Tk_Offset(Pix32, Green);
190 dest.offset[2] = Tk_Offset(Pix32, Blue);
191 dest.offset[3] = Tk_Offset(Pix32, Alpha);
192 dest.pixelPtr = (unsigned char *)Blt_ColorImageBits(src);
193 Tk_PhotoSetSize(photo, width, height);
194 Tk_PhotoPutBlock(photo, &dest, 0, 0, width, height);
195}
196
197/*
198 *----------------------------------------------------------------------
199 *
200 * Blt_PhotoRegionToColorImage --
201 *
202 * Create a photo to a color image.
203 *
204 * Results:
205 * The new color image is returned.
206 *
207 *----------------------------------------------------------------------
208 */
209Blt_ColorImage
210Blt_PhotoRegionToColorImage(photo, x, y, width, height)
211 Tk_PhotoHandle photo; /* Source photo image to scale */
212 int x, y;
213 int width, height;
214{
215 Tk_PhotoImageBlock src;
216 Blt_ColorImage image;
217 register Pix32 *destPtr;
218 register unsigned char *srcData;
219 register int offset;
220 unsigned int offR, offG, offB, offA;
221
222 Tk_PhotoGetImage(photo, &src);
223 if (x < 0) {
224 x = 0;
225 }
226 if (y < 0) {
227 y = 0;
228 }
229 if (width < 0) {
230 width = src.width;
231 }
232 if (height < 0) {
233 height = src.height;
234 }
235 if ((x + width) > src.width) {
236 width = src.width - x;
237 }
238 if ((height + y) > src.height) {
239 height = src.width - y;
240 }
241 image = Blt_CreateColorImage(width, height);
242 destPtr = Blt_ColorImageBits(image);
243
244 offset = (x * src.pixelSize) + (y * src.pitch);
245
246 offR = src.offset[0];
247 offG = src.offset[1];
248 offB = src.offset[2];
249 offA = src.offset[3];
250
251 if (src.pixelSize == 4) {
252 for (y = 0; y < height; y++) {
253 srcData = src.pixelPtr + offset;
254 for (x = 0; x < width; x++) {
255 destPtr->Red = srcData[offR];
256 destPtr->Green = srcData[offG];
257 destPtr->Blue = srcData[offB];
258 destPtr->Alpha = srcData[offA];
259 srcData += src.pixelSize;
260 destPtr++;
261 }
262 offset += src.pitch;
263 }
264 } else if (src.pixelSize == 3) {
265 for (y = 0; y < height; y++) {
266 srcData = src.pixelPtr + offset;
267 for (x = 0; x < width; x++) {
268 destPtr->Red = srcData[offR];
269 destPtr->Green = srcData[offG];
270 destPtr->Blue = srcData[offB];
271 /* No transparency information */
272 destPtr->Alpha = (unsigned char)-1;
273 srcData += src.pixelSize;
274 destPtr++;
275 }
276 offset += src.pitch;
277 }
278 } else {
279 for (y = 0; y < height; y++) {
280 srcData = src.pixelPtr + offset;
281 for (x = 0; x < width; x++) {
282 destPtr->Red = destPtr->Green = destPtr->Blue = srcData[offA];
283 /* No transparency information */
284 destPtr->Alpha = (unsigned char)-1;
285 srcData += src.pixelSize;
286 destPtr++;
287 }
288 offset += src.pitch;
289 }
290 }
291 return image;
292}
293
294/*
295 *----------------------------------------------------------------------
296 *
297 * Blt_PhotoToColorImage --
298 *
299 * Create a photo to a color image.
300 *
301 * Results:
302 * The new color image is returned.
303 *
304 *----------------------------------------------------------------------
305 */
306Blt_ColorImage
307Blt_PhotoToColorImage(photo)
308 Tk_PhotoHandle photo; /* Source photo image to scale */
309
310{
311 Blt_ColorImage image;
312 Tk_PhotoImageBlock src;
313 int width, height;
314 register Pix32 *destPtr;
315 register int offset;
316 register int x, y;
317 register unsigned char *srcData;
318
319 Tk_PhotoGetImage(photo, &src);
320 width = src.width;
321 height = src.height;
322 image = Blt_CreateColorImage(width, height);
323 destPtr = Blt_ColorImageBits(image);
324 offset = 0;
325 if (src.pixelSize == 4) {
326 for (y = 0; y < height; y++) {
327 srcData = src.pixelPtr + offset;
328 for (x = 0; x < width; x++) {
329 destPtr->Red = srcData[src.offset[0]];
330 destPtr->Green = srcData[src.offset[1]];
331 destPtr->Blue = srcData[src.offset[2]];
332 destPtr->Alpha = srcData[src.offset[3]];
333 srcData += src.pixelSize;
334 destPtr++;
335 }
336 offset += src.pitch;
337 }
338 } else if (src.pixelSize == 3) {
339 for (y = 0; y < height; y++) {
340 srcData = src.pixelPtr + offset;
341 for (x = 0; x < width; x++) {
342 destPtr->Red = srcData[src.offset[0]];
343 destPtr->Green = srcData[src.offset[1]];
344 destPtr->Blue = srcData[src.offset[2]];
345 /* No transparency information */
346 destPtr->Alpha = (unsigned char)-1;
347 srcData += src.pixelSize;
348 destPtr++;
349 }
350 offset += src.pitch;
351 }
352 } else {
353 for (y = 0; y < height; y++) {
354 srcData = src.pixelPtr + offset;
355 for (x = 0; x < width; x++) {
356 destPtr->Red = destPtr->Green = destPtr->Blue =
357 srcData[src.offset[0]];
358 /* No transparency information */
359 destPtr->Alpha = (unsigned char)-1;
360 srcData += src.pixelSize;
361 destPtr++;
362 }
363 offset += src.pitch;
364 }
365 }
366 return image;
367}
368
369/*
370 * filter function definitions
371 */
372
373static ResampleFilterProc DefaultFilter;
374static ResampleFilterProc BellFilter;
375static ResampleFilterProc BesselFilter;
376static ResampleFilterProc BoxFilter;
377static ResampleFilterProc BSplineFilter;
378static ResampleFilterProc CatRomFilter;
379static ResampleFilterProc DummyFilter;
380static ResampleFilterProc GaussianFilter;
381static ResampleFilterProc GiFilter;
382static ResampleFilterProc Lanczos3Filter;
383static ResampleFilterProc MitchellFilter;
384static ResampleFilterProc SincFilter;
385static ResampleFilterProc TriangleFilter;
386static Tk_ImageChangedProc TempImageChangedProc;
387
388static double
389DefaultFilter(x)
390 double x;
391{
392 if (x < 0.0) {
393 x = -x;
394 }
395 if (x < 1.0) {
396 /* f(x) = 2x^3 - 3x^2 + 1, -1 <= x <= 1 */
397 return (2.0 * x - 3.0) * x * x + 1.0;
398 }
399 return 0.0;
400}
401
402/* Just for testing */
403static double
404DummyFilter(x)
405 double x;
406{
407 return FABS(x);
408}
409
410/*
411 *
412 * Finite filters in increasing order:
413 * Box (constant)
414 * Triangle (linear)
415 * Bell
416 * BSpline (cubic)
417 *
418 */
419static double
420BoxFilter(x)
421 double x;
422{
423 if ((x < -0.5) || (x > 0.5)) {
424 return 0.0;
425 }
426 return 1.0;
427}
428
429static double
430TriangleFilter(x)
431 double x;
432{
433 if (x < 0.0) {
434 x = -x;
435 }
436 if (x < 1.0) {
437 return (1.0 - x);
438 }
439 return 0.0;
440}
441
442static double
443BellFilter(x)
444 double x;
445{
446 if (x < 0.0) {
447 x = -x;
448 }
449 if (x < 0.5) {
450 return (0.75 - (x * x));
451 }
452 if (x < 1.5) {
453 x = (x - 1.5);
454 return (0.5 * (x * x));
455 }
456 return 0.0;
457}
458
459static double
460BSplineFilter(x)
461 double x;
462{
463 double x2;
464
465 if (x < 0.0) {
466 x = -x;
467 }
468 if (x < 1) {
469 x2 = x * x;
470 return ((.5 * x2 * x) - x2 + (2.0 / 3.0));
471 } else if (x < 2) {
472 x = 2 - x;
473 return ((x * x * x) / 6.0);
474 }
475 return 0.0;
476}
477
478/*
479 *
480 * Infinite Filters:
481 * Sinc perfect lowpass filter
482 * Bessel circularly symmetric 2-D filter
483 * Gaussian
484 * Lanczos3
485 * Mitchell
486 */
487
488static double
489SincFilter(x)
490 double x;
491{
492 x *= M_PI;
493 if (x == 0.0) {
494 return 1.0;
495 }
496 return (sin(x) / x);
497}
498
499static double
500BesselFilter(x)
501 double x;
502{
503#ifdef NEED_DECL_J1
504 extern double j1 _ANSI_ARGS_((double value));
505#endif
506 /*
507 * See Pratt "Digital Image Processing" p. 97 for Bessel functions
508 * zeros are at approx x=1.2197, 2.2331, 3.2383, 4.2411, 5.2428, 6.2439,
509 * 7.2448, 8.2454
510 */
511#ifdef __BORLANDC__
512 return 0.0;
513#else
514 return (x == 0.0) ? M_PI / 4.0 : j1(M_PI * x) / (x + x);
515#endif
516}
517
518#define SQRT_2PI 0.79788456080286541 /* sqrt(2.0 / M_PI) */
519
520static double
521GaussianFilter(x)
522 double x;
523{
524 return exp(-2.0 * x * x) * SQRT_2PI;
525}
526
527static double
528Lanczos3Filter(x)
529 double x;
530{
531 if (x < 0) {
532 x = -x;
533 }
534 if (x < 3.0) {
535 return (SincFilter(x) * SincFilter(x / 3.0));
536 }
537 return 0.0;
538}
539
540#define B 0.3333333333333333 /* (1.0 / 3.0) */
541#define C 0.3333333333333333 /* (1.0 / 3.0) */
542
543static double
544MitchellFilter(x)
545 double x;
546{
547 double x2;
548
549 x2 = x * x;
550 if (x < 0) {
551 x = -x;
552 }
553 if (x < 1.0) {
554 x = (((12.0 - 9.0 * B - 6.0 * C) * (x * x2)) +
555 ((-18.0 + 12.0 * B + 6.0 * C) * x2) + (6.0 - 2 * B));
556 return (x / 6.0);
557 } else if (x < 2.0) {
558 x = (((-1.0 * B - 6.0 * C) * (x * x2)) + ((6.0 * B + 30.0 * C) * x2) +
559 ((-12.0 * B - 48.0 * C) * x) + (8.0 * B + 24 * C));
560 return (x / 6.0);
561 }
562 return 0.0;
563}
564
565/*
566 * Catmull-Rom spline
567 */
568static double
569CatRomFilter(x)
570 double x;
571{
572 if (x < -2.) {
573 return 0.0;
574 }
575 if (x < -1.0) {
576 return 0.5 * (4.0 + x * (8.0 + x * (5.0 + x)));
577 }
578 if (x < 0.0) {
579 return 0.5 * (2.0 + x * x * (-5.0 + x * -3.0));
580 }
581 if (x < 1.0) {
582 return 0.5 * (2.0 + x * x * (-5.0 + x * 3.0));
583 }
584 if (x < 2.0) {
585 return 0.5 * (4.0 + x * (-8.0 + x * (5.0 - x)));
586 }
587 return 0.0;
588}
589
590/* approximation to the gaussian integral [x, inf) */
591static double
592GiFilter(x)
593 double x;
594{
595 if (x > 1.5) {
596 return 0.0;
597 } else if (x < -1.5) {
598 return 1.0;
599 } else {
600#define I6 0.166666666666667
601#define I4 0.25
602#define I3 0.333333333333333
603 double x2 = x * x;
604 double x3 = x2 * x;
605
606 if (x > 0.5) {
607 return .5625 - ( x3 * I6 - 3 * x2 * I4 + 1.125 * x);
608 } else if (x > -0.5) {
609 return 0.5 - (0.75 * x - x3 * I3);
610 } else {
611 return 0.4375 + (-x3 * I6 - 3 * x2 * I4 - 1.125 * x);
612 }
613 }
614}
615
616
617
618static ResampleFilter filterTable[] =
619{
620 /* name, function, support */
621 {"bell", BellFilter, 1.5 },
622 {"bessel", BesselFilter, 3.2383 },
623 {"box", BoxFilter, 0.5 },
624 {"bspline", BSplineFilter, 2.0 },
625 {"catrom", CatRomFilter, 2.0 },
626 {"default", DefaultFilter, 1.0 },
627 {"dummy", DummyFilter, 0.5 },
628 {"gauss8", GaussianFilter, 8.0 },
629 {"gaussian", GaussianFilter, 1.25 },
630 {"gi", GiFilter, 1.25 },
631 {"lanczos3", Lanczos3Filter, 3.0 },
632 {"mitchell", MitchellFilter, 2.0 },
633 {"none", (ResampleFilterProc *)NULL, 0.0 },
634 {"sinc", SincFilter, 4.0 },
635 {"triangle", TriangleFilter, 1.0 },
636};
637
638static int nFilters = sizeof(filterTable) / sizeof(ResampleFilter);
639
640ResampleFilter *bltBoxFilterPtr = &(filterTable[1]);
641
642
643/*
644 *----------------------------------------------------------------------
645 *
646 * Blt_GetResampleFilter --
647 *
648 * Finds a 1-D filter associated by the given filter name.
649 *
650 * Results:
651 * A standard Tcl result. Returns TCL_OK is the filter was
652 * found. The filter information (proc and support) is returned
653 * via filterPtrPtr. Otherwise TCL_ERROR is returned and an error
654 * message is left in interp->result.
655 *
656 *----------------------------------------------------------------------
657 */
658int
659Blt_GetResampleFilter(interp, name, filterPtrPtr)
660 Tcl_Interp *interp;
661 char *name;
662 ResampleFilter **filterPtrPtr;
663{
664 ResampleFilter *filterPtr, *endPtr;
665
666 endPtr = filterTable + nFilters;
667 for (filterPtr = filterTable; filterPtr < endPtr; filterPtr++) {
668 if (strcmp(name, filterPtr->name) == 0) {
669 *filterPtrPtr = (filterPtr->proc == NULL) ? NULL : filterPtr;
670 return TCL_OK;
671 }
672 }
673 Tcl_AppendResult(interp, "can't find filter \"", name, "\"", (char *)NULL);
674 return TCL_ERROR;
675}
676
677
678/*
679 * Scaled integers are fixed point values. The upper 18 bits is the integer
680 * portion, the lower 14 bits the fractional remainder. Must be careful
681 * not to overflow the values (especially during multiplication).
682 *
683 * The following operations are defined:
684 *
685 * S * n Scaled integer times an integer.
686 * S1 + S2 Scaled integer plus another scaled integer.
687 *
688 */
689
690#define float2si(f) (int)((f) * 16384.0 + 0.5)
691#define uchar2si(b) (((int)(b)) << 14)
692#define si2int(s) (((s) + 8192) >> 14)
693
694#ifdef notdef
695typedef struct {
696 int pixel;
697 union Weight {
698 int i; /* Fixed point, scaled integer. */
699 float f;
700 } weight;
701} Sample;
702
703typedef struct {
704 int count; /* Number of contributors */
705 Sample *samples; /* Array of contributors */
706} Contribution;
707
708typedef struct {
709 int pixel;
710 union Weight {
711 int i; /* Fixed point, scaled integer. */
712 float f;
713 } weight;
714} Sample;
715#endif
716
717
718typedef union {
719 int i; /* Fixed point, scaled integer. */
720 float f;
721} Weight;
722
723typedef struct {
724 int count; /* Number of samples. */
725 int start;
726 Weight weights[1]; /* Array of weights. */
727} Sample;
728
729static size_t
730ComputeWeights(srcWidth, destWidth, filterPtr, samplePtrPtr)
731 int srcWidth, destWidth;
732 ResampleFilter *filterPtr;
733 Sample **samplePtrPtr;
734{
735 Sample *samples;
736 double scale;
737 int filterSize;
738 double center;
739 register Sample *s;
740 register Weight *weight;
741 register int x, i;
742 register int left, right; /* filter bounds */
743 double factor, sum;
744 size_t size;
745
746 /* Pre-calculate filter contributions for a row */
747 scale = (double)destWidth / (double)srcWidth;
748
749 if (scale < 1.0) {
750 double radius, fscale;
751
752 /* Downsample */
753
754 radius = filterPtr->support / scale;
755 fscale = 1.0 / scale;
756 filterSize = (int)(radius * 2 + 2);
757
758 size = sizeof(Sample) + (filterSize - 1) * sizeof(Weight);
759 samples = Blt_Calloc(destWidth, size);
760 assert(samples);
761
762 s = samples;
763 for (x = 0; x < destWidth; x++) {
764 center = (double)x * fscale;
765
766 /* Determine bounds of filter and its density */
767 left = (int)(center - radius + 0.5);
768 if (left < 0) {
769 left = 0;
770 }
771 right = (int)(center + radius + 0.5);
772 if (right >= srcWidth) {
773 right = srcWidth - 1;
774 }
775 sum = 0.0;
776 s->start = left;
777 for (weight = s->weights, i = left; i <= right; i++, weight++) {
778 weight->f = (float)
779 (*filterPtr->proc) (((double)i + 0.5 - center) * scale);
780 sum += weight->f;
781 }
782 s->count = right - left + 1;
783
784 factor = (sum == 0.0) ? 1.0 : (1.0 / sum);
785 for (weight = s->weights, i = left; i <= right; i++, weight++) {
786 weight->f = (float)(weight->f * factor);
787 weight->i = float2si(weight->f);
788 }
789 s = (Sample *)((char *)s + size);
790 }
791 } else {
792 double fscale;
793 /* Upsample */
794
795 filterSize = (int)(filterPtr->support * 2 + 2);
796 size = sizeof(Sample) + (filterSize - 1) * sizeof(Weight);
797 samples = Blt_Calloc(destWidth, size);
798 assert(samples);
799
800 fscale = 1.0 / scale;
801
802 s = samples;
803 for (x = 0; x < destWidth; x++) {
804 center = (double)x * fscale;
805 left = (int)(center - filterPtr->support + 0.5);
806 if (left < 0) {
807 left = 0;
808 }
809 right = (int)(center + filterPtr->support + 0.5);
810 if (right >= srcWidth) {
811 right = srcWidth - 1;
812 }
813 sum = 0.0;
814 s->start = left;
815 for (weight = s->weights, i = left; i <= right; i++, weight++) {
816 weight->f = (float)
817 (*filterPtr->proc) ((double)i - center + 0.5);
818 sum += weight->f;
819 }
820 s->count = right - left + 1;
821 factor = (sum == 0.0) ? 1.0 : (1.0 / sum);
822 for (weight = s->weights, i = left; i <= right; i++, weight++) {
823 weight->f = (float)(weight->f * factor);
824 weight->i = float2si(weight->f);
825 }
826 s = (Sample *)((char *)s + size);
827 }
828 }
829 *samplePtrPtr = samples;
830 return size;
831}
832
833/*
834 * The following macro converts a fixed-point scaled integer to a
835 * byte, clamping the value between 0 and 255.
836 */
837#define SICLAMP(s) \
838 (unsigned char)(((s) < 0) ? 0 : ((s) > 4177920) ? 255 : (si2int(s)))
839
840static void
841ZoomImageVertically(src, dest, filterPtr)
842 Blt_ColorImage src, dest;
843 ResampleFilter *filterPtr;
844{
845 Sample *samples, *s, *endPtr;
846 int destWidth, destHeight;
847 int red, green, blue, alpha;
848 int srcWidth, srcHeight;
849 register Pix32 *srcColumnPtr;
850 register Pix32 *srcPtr, *destPtr;
851 register Weight *weight;
852 int x, i;
853 size_t size; /* Size of sample. */
854
855 srcWidth = Blt_ColorImageWidth(src);
856 srcHeight = Blt_ColorImageHeight(src);
857 destWidth = Blt_ColorImageWidth(dest);
858 destHeight = Blt_ColorImageHeight(dest);
859
860 /* Pre-calculate filter contributions for a row */
861 size = ComputeWeights(srcHeight, destHeight, filterPtr, &samples);
862 endPtr = (Sample *)((char *)samples + (destHeight * size));
863
864 /* Apply filter to zoom vertically from tmp to destination */
865 for (x = 0; x < srcWidth; x++) {
866 srcColumnPtr = Blt_ColorImageBits(src) + x;
867 destPtr = Blt_ColorImageBits(dest) + x;
868 for (s = samples; s < endPtr; s = (Sample *)((char *)s + size)) {
869 red = green = blue = alpha = 0;
870 srcPtr = srcColumnPtr + (s->start * srcWidth);
871 for (weight = s->weights, i = 0; i < s->count; i++, weight++) {
872 red += srcPtr->Red * weight->i;
873 green += srcPtr->Green * weight->i;
874 blue += srcPtr->Blue * weight->i;
875 alpha += srcPtr->Alpha * weight->i;
876 srcPtr += srcWidth;
877 }
878 destPtr->Red = SICLAMP(red);
879 destPtr->Green = SICLAMP(green);
880 destPtr->Blue = SICLAMP(blue);
881 destPtr->Alpha = SICLAMP(alpha);
882 destPtr += destWidth;
883
884 }
885 }
886 /* Free the memory allocated for filter weights */
887 Blt_Free(samples);
888}
889
890static void
891ZoomImageHorizontally(src, dest, filterPtr)
892 Blt_ColorImage src, dest;
893 ResampleFilter *filterPtr;
894{
895 Sample *samples, *s, *endPtr;
896 Weight *weight;
897 int destWidth;
898 int red, green, blue, alpha;
899 int srcWidth, srcHeight;
900 int y, i;
901 register Pix32 *srcPtr, *destPtr;
902 register Pix32 *srcRowPtr;
903 size_t size; /* Size of sample. */
904
905 srcWidth = Blt_ColorImageWidth(src);
906 srcHeight = Blt_ColorImageHeight(src);
907 destWidth = Blt_ColorImageWidth(dest);
908
909 /* Pre-calculate filter contributions for a row */
910 size = ComputeWeights(srcWidth, destWidth, filterPtr, &samples);
911 endPtr = (Sample *)((char *)samples + (destWidth * size));
912
913 /* Apply filter to zoom horizontally from srcPtr to tmpPixels */
914 srcRowPtr = Blt_ColorImageBits(src);
915 destPtr = Blt_ColorImageBits(dest);
916 for (y = 0; y < srcHeight; y++) {
917 for (s = samples; s < endPtr; s = (Sample *)((char *)s + size)) {
918 red = green = blue = alpha = 0;
919 srcPtr = srcRowPtr + s->start;
920 for (weight = s->weights, i = 0; i < s->count; i++, weight++) {
921 red += srcPtr->Red * weight->i;
922 green += srcPtr->Green * weight->i;
923 blue += srcPtr->Blue * weight->i;
924 alpha += srcPtr->Alpha * weight->i;
925 srcPtr++;
926 }
927 destPtr->Red = SICLAMP(red);
928 destPtr->Green = SICLAMP(green);
929 destPtr->Blue = SICLAMP(blue);
930 destPtr->Alpha = SICLAMP(alpha);
931 destPtr++;
932 }
933 srcRowPtr += srcWidth;
934 }
935 /* free the memory allocated for horizontal filter weights */
936 Blt_Free(samples);
937}
938
939/*
940 *----------------------------------------------------------------------
941 *
942 * Blt_ResampleColorImage --
943 *
944 * Resamples a given color image using 1-D filters and returns
945 * a new color image of the designated size.
946 *
947 * Results:
948 * Returns the resampled color image. The original color image
949 * is left intact.
950 *
951 *----------------------------------------------------------------------
952 */
953Blt_ColorImage
954Blt_ResampleColorImage(src, width, height, horzFilterPtr, vertFilterPtr)
955 Blt_ColorImage src;
956 int width, height;
957 ResampleFilter *horzFilterPtr, *vertFilterPtr;
958{
959 Blt_ColorImage tmp, dest;
960
961 /*
962 * It's usually faster to zoom vertically last. This has to do
963 * with the fact that images are stored in contiguous rows.
964 */
965
966 tmp = Blt_CreateColorImage(width, Blt_ColorImageHeight(src));
967 ZoomImageHorizontally(src, tmp, horzFilterPtr);
968 dest = Blt_CreateColorImage(width, height);
969 ZoomImageVertically(tmp, dest, vertFilterPtr);
970 Blt_FreeColorImage(tmp);
971 return dest;
972}
973
974/*
975 *----------------------------------------------------------------------
976 *
977 * Blt_ResamplePhoto --
978 *
979 * Resamples a Tk photo image using 1-D filters and writes the
980 * image into another Tk photo. It is possible for the
981 * source and destination to be the same photo.
982 *
983 * Results:
984 * The designated destination photo will contain the resampled
985 * color image. The original photo is left intact.
986 *
987 *----------------------------------------------------------------------
988 */
989void
990Blt_ResamplePhoto(srcPhoto, x, y, width, height, destPhoto, horzFilterPtr,
991 vertFilterPtr)
992 Tk_PhotoHandle srcPhoto; /* Source photo image to scale */
993 int x, y;
994 int width, height;
995 Tk_PhotoHandle destPhoto; /* Resulting scaled photo image */
996 ResampleFilter *horzFilterPtr, *vertFilterPtr;
997{
998 Blt_ColorImage srcImage, destImage;
999 Tk_PhotoImageBlock dest;
1000
1001 Tk_PhotoGetImage(destPhoto, &dest);
1002 srcImage = Blt_PhotoRegionToColorImage(srcPhoto, x, y, width, height);
1003 destImage = Blt_ResampleColorImage(srcImage, dest.width, dest.height,
1004 horzFilterPtr, vertFilterPtr);
1005 Blt_FreeColorImage(srcImage);
1006 Blt_ColorImageToPhoto(destImage, destPhoto);
1007 Blt_FreeColorImage(destImage);
1008}
1009
1010/*
1011 *----------------------------------------------------------------------
1012 *
1013 * Blt_ResizePhoto --
1014 *
1015 * Scales the region of the source image to the size of the
1016 * destination image. This routine performs raw scaling of
1017 * the image and unlike Blt_ResamplePhoto does not handle
1018 * aliasing effects from subpixel sampling. It is possible
1019 * for the source and destination to be the same photo.
1020 *
1021 * Results:
1022 * The designated destination photo will contain the resampled
1023 * color image. The original photo is left intact.
1024 *
1025 *----------------------------------------------------------------------
1026 */
1027void
1028Blt_ResizePhoto(srcPhoto, x, y, width, height, destPhoto)
1029 Tk_PhotoHandle srcPhoto; /* Source photo image to scaled. */
1030 register int x, y; /* Region of source photo to be
1031 * scaled. */
1032 int width, height;
1033 Tk_PhotoHandle destPhoto; /* (out) Resulting scaled photo image.
1034 * Scaling factors are derived from
1035 * the destination photo's
1036 * dimensions. */
1037{
1038 double xScale, yScale;
1039 Blt_ColorImage destImage;
1040 Pix32 *destPtr;
1041 Tk_PhotoImageBlock src, dest;
1042 unsigned char *srcPtr, *srcRowPtr;
1043 int *mapX, *mapY;
1044 register int sx, sy;
1045 int left, right, top, bottom;
1046
1047 Tk_PhotoGetImage(srcPhoto, &src);
1048 Tk_PhotoGetImage(destPhoto, &dest);
1049
1050 left = x, top = y, right = x + width - 1, bottom = y + height - 1;
1051 destImage = Blt_CreateColorImage(dest.width, dest.height);
1052 xScale = (double)width / (double)dest.width;
1053 yScale = (double)height / (double)dest.height;
1054 mapX = (int *)Blt_Malloc(sizeof(int) * dest.width);
1055 mapY = (int *)Blt_Malloc(sizeof(int) * dest.height);
1056 for(x = 0; x < dest.width; x++) {
1057 sx = (int)(xScale * (double)(x + left));
1058 if (sx > right) {
1059 sx = right;
1060 }
1061 mapX[x] = sx;
1062 }
1063 for(y = 0; y < dest.height; y++) {
1064 sy = (int)(yScale * (double)(y + top));
1065 if (sy > bottom) {
1066 sy = bottom;
1067 }
1068 mapY[y] = sy;
1069 }
1070 destPtr = Blt_ColorImageBits(destImage);
1071 if (src.pixelSize == 4) {
1072 for (y = 0; y < dest.height; y++) {
1073 srcRowPtr = src.pixelPtr + (mapY[y] * src.pitch);
1074 for (x = 0; x < dest.width; x++) {
1075 srcPtr = srcRowPtr + (mapX[x] * src.pixelSize);
1076 destPtr->Red = srcPtr[src.offset[0]];
1077 destPtr->Green = srcPtr[src.offset[1]];
1078 destPtr->Blue = srcPtr[src.offset[2]];
1079 destPtr->Alpha = srcPtr[src.offset[3]];
1080 destPtr++;
1081 }
1082 }
1083 } else if (src.pixelSize == 3) {
1084 for (y = 0; y < dest.height; y++) {
1085 srcRowPtr = src.pixelPtr + (mapY[y] * src.pitch);
1086 for (x = 0; x < dest.width; x++) {
1087 srcPtr = srcRowPtr + (mapX[x] * src.pixelSize);
1088 destPtr->Red = srcPtr[src.offset[0]];
1089 destPtr->Green = srcPtr[src.offset[1]];
1090 destPtr->Blue = srcPtr[src.offset[2]];
1091 destPtr->Alpha = (unsigned char)-1;
1092 destPtr++;
1093 }
1094 }
1095 } else {
1096 for (y = 0; y < dest.height; y++) {
1097 srcRowPtr = src.pixelPtr + (mapY[y] * src.pitch);
1098 for (x = 0; x < dest.width; x++) {
1099 srcPtr = srcRowPtr + (mapX[x] * src.pixelSize);
1100 destPtr->Red = destPtr->Green = destPtr->Blue =
1101 srcPtr[src.offset[0]];
1102 destPtr->Alpha = (unsigned char)-1;
1103 destPtr++;
1104 }
1105 }
1106 }
1107 Blt_Free(mapX);
1108 Blt_Free(mapY);
1109 Blt_ColorImageToPhoto(destImage, destPhoto);
1110 Blt_FreeColorImage(destImage);
1111}
1112
1113/*
1114 *----------------------------------------------------------------------
1115 *
1116 * Blt_ResizeColorImage --
1117 *
1118 * Scales the region of the source image to the size of the
1119 * destination image. This routine performs raw scaling of
1120 * the image and unlike Blt_ResamplePhoto does not perform
1121 * any antialiasing.
1122 *
1123 * Results:
1124 * Returns the new resized color image. The original image
1125 * is left intact.
1126 *
1127 *----------------------------------------------------------------------
1128 */
1129Blt_ColorImage
1130Blt_ResizeColorImage(src, x, y, width, height, destWidth, destHeight)
1131 Blt_ColorImage src; /* Source color image to be scaled. */
1132 register int x, y; /* Region of source image to scaled. */
1133 int width, height;
1134 int destWidth, destHeight; /* Requested dimensions of the scaled
1135 * image. */
1136{
1137 register int sx, sy;
1138 double xScale, yScale;
1139 Blt_ColorImage dest;
1140 Pix32 *srcPtr, *srcRowPtr, *destPtr;
1141 int *mapX, *mapY;
1142 int left, right, top, bottom;
1143
1144 left = x, top = y; right = x + width - 1, bottom = y + height - 1;
1145
1146 dest = Blt_CreateColorImage(destWidth, destHeight);
1147 xScale = (double)width / (double)destWidth;
1148 yScale = (double)height / (double)destHeight;
1149 mapX = (int *)Blt_Malloc(sizeof(int) * destWidth);
1150 mapY = (int *)Blt_Malloc(sizeof(int) * destHeight);
1151 for(x = 0; x < destWidth; x++) {
1152 sx = (int)(xScale * (double)(x + left));
1153 if (sx > right) {
1154 sx = right;
1155 }
1156 mapX[x] = sx;
1157 }
1158 for(y = 0; y < destHeight; y++) {
1159 sy = (int)(yScale * (double)(y + top));
1160 if (sy > bottom) {
1161 sy = bottom;
1162 }
1163 mapY[y] = sy;
1164 }
1165 destPtr = Blt_ColorImageBits(dest);
1166 for (y = 0; y < destHeight; y++) {
1167 srcRowPtr = Blt_ColorImageBits(src) +
1168 (Blt_ColorImageWidth(src) * mapY[y]);
1169 for (x = 0; x < destWidth; x++) {
1170 srcPtr = srcRowPtr + mapX[x];
1171 destPtr->value = srcPtr->value; /* Copy the pixel. */
1172 destPtr++;
1173 }
1174 }
1175 Blt_Free(mapX);
1176 Blt_Free(mapY);
1177 return dest;
1178}
1179
1180/*
1181 *----------------------------------------------------------------------
1182 *
1183 * Blt_ResizeColorSubimage --
1184 *
1185 * Scales the region of the source image to the size of the
1186 * destination image. This routine performs raw scaling of
1187 * the image and unlike Blt_ResamplePhoto does not perform
1188 * any antialiasing.
1189 *
1190 * Results:
1191 * Returns the new resized color image. The original image
1192 * is left intact.
1193 *
1194 *----------------------------------------------------------------------
1195 */
1196Blt_ColorImage
1197Blt_ResizeColorSubimage(
1198 Blt_ColorImage src, /* Source color image to be scaled. */
1199 int regionX,
1200 int regionY, /* Offset of subimage in destination. */
1201 int regionWidth, /* Dimension of subimage. */
1202 int regionHeight,
1203 int destWidth,
1204 int destHeight) /* Dimensions of the entire scaled
1205 image. */
1206{
1207 Blt_ColorImage dest;
1208 Pix32 *srcPtr, *srcRowPtr, *destPtr;
1209 double xScale, yScale;
1210 int *mapX, *mapY;
1211 int srcWidth, srcHeight;
1212 register int sx, sy;
1213 register int x, y;
1214
1215 srcWidth = Blt_ColorImageWidth(src);
1216 srcHeight = Blt_ColorImageHeight(src);
1217
1218 xScale = (double)srcWidth / (double)destWidth;
1219 yScale = (double)srcHeight / (double)destHeight;
1220 mapX = Blt_Malloc(sizeof(int) * regionWidth);
1221 mapY = Blt_Malloc(sizeof(int) * regionHeight);
1222
1223 /* Precompute scaling factors for each row and column. */
1224 for(x = 0; x < regionWidth; x++) {
1225 sx = (int)(xScale * (double)(x + regionX));
1226 if (sx >= srcWidth) {
1227 sx = srcWidth - 1;
1228 }
1229 mapX[x] = sx;
1230 }
1231 for(y = 0; y < regionHeight; y++) {
1232 sy = (int)(yScale * (double)(y + regionY));
1233 if (sy > srcHeight) {
1234 sy = srcHeight - 1;
1235 }
1236 mapY[y] = sy;
1237 }
1238
1239 dest = Blt_CreateColorImage(regionWidth, regionHeight);
1240 destPtr = Blt_ColorImageBits(dest);
1241 for (y = 0; y < regionHeight; y++) {
1242 srcRowPtr = Blt_ColorImageBits(src) +
1243 (Blt_ColorImageWidth(src) * mapY[y]);
1244 for (x = 0; x < regionWidth; x++) {
1245 srcPtr = srcRowPtr + mapX[x];
1246 destPtr->value = srcPtr->value; /* Copy the pixel. */
1247 destPtr++;
1248 }
1249 }
1250 Blt_Free(mapX);
1251 Blt_Free(mapY);
1252 return dest;
1253}
1254
1255/*
1256 * FIXME: Boundary handling could be better (pixels are replicated).
1257 * It's slow. Take boundary tests out of inner loop.
1258 */
1259Blt_ColorImage
1260Blt_ConvolveColorImage(src, filterPtr)
1261 Blt_ColorImage src;
1262 Filter2D *filterPtr;
1263{
1264 Blt_ColorImage dest;
1265 register Pix32 *srcPtr, *destPtr;
1266#define MAXROWS 24
1267 register int sx, sy, dx, dy;
1268 register int x, y;
1269 double red, green, blue;
1270 int width, height;
1271 int radius;
1272 register double *valuePtr;
1273
1274 width = Blt_ColorImageWidth(src);
1275 height = Blt_ColorImageHeight(src);
1276
1277 dest = Blt_CreateColorImage(width, height);
1278 radius = (int)filterPtr->support;
1279 if (radius < 1) {
1280 radius = 1;
1281 }
1282 destPtr = Blt_ColorImageBits(dest);
1283 for (dy = 0; dy < height; dy++) {
1284 for (dx = 0; dx < width; dx++) {
1285 red = green = blue = 0.0;
1286 valuePtr = filterPtr->kernel;
1287 for (sy = (dy - radius); sy <= (dy + radius); sy++) {
1288 y = sy;
1289 if (y < 0) {
1290 y = 0;
1291 } else if (y >= height) {
1292 y = height - 1;
1293 }
1294 for (sx = (dx - radius); sx <= (dx + radius); sx++) {
1295 x = sx;
1296 if (x < 0) {
1297 x = 0;
1298 } else if (sx >= width) {
1299 x = width - 1;
1300 }
1301 srcPtr = Blt_ColorImagePixel(src, x, y);
1302 red += *valuePtr * (double)srcPtr->Red;
1303 green += *valuePtr * (double)srcPtr->Green;
1304 blue += *valuePtr * (double)srcPtr->Blue;
1305#ifdef notdef
1306 fprintf(stderr, "%d,%d = r=%f,g=%f,b=%f\n", x, y,
1307 red, green, blue);
1308#endif
1309 valuePtr++;
1310 }
1311 }
1312 red /= filterPtr->sum;
1313 green /= filterPtr->sum;
1314 blue /= filterPtr->sum;
1315 destPtr->Red = (unsigned char)CLAMP(red);
1316 destPtr->Green = (unsigned char)CLAMP(green);
1317 destPtr->Blue = (unsigned char)CLAMP(blue);
1318 destPtr->Alpha = (unsigned char)-1;
1319 destPtr++;
1320 }
1321 }
1322 return dest;
1323}
1324
1325
1326/*
1327 *----------------------------------------------------------------------
1328 *
1329 * Blt_SnapPhoto --
1330 *
1331 * Takes a snapshot of an X drawable (pixmap or window) and
1332 * writes it to an existing Tk photo image.
1333 *
1334 * Results:
1335 * A standard Tcl result.
1336 *
1337 * Side Effects:
1338 * The named Tk photo is updated with the snapshot.
1339 *
1340 *----------------------------------------------------------------------
1341 */
1342int
1343Blt_SnapPhoto(interp, tkwin, drawable, x, y, width, height, destWidth,
1344 destHeight, photoName, inputGamma)
1345 Tcl_Interp *interp; /* Interpreter to report errors back to */
1346 Tk_Window tkwin;
1347 Drawable drawable; /* Window or pixmap to be snapped */
1348 int x, y; /* Offset of image from drawable origin. */
1349 int width, height; /* Dimension of the drawable */
1350 int destWidth, destHeight; /* Desired size of the Tk photo */
1351 char *photoName; /* Name of an existing Tk photo image. */
1352 double inputGamma;
1353{
1354 Tk_PhotoHandle photo; /* The photo image to write into. */
1355 Blt_ColorImage image;
1356
1357 photo = Blt_FindPhoto(interp, photoName);
1358 if (photo == NULL) {
1359 Tcl_AppendResult(interp, "can't find photo \"", photoName, "\"",
1360 (char *)NULL);
1361 return TCL_ERROR;
1362 }
1363 image = Blt_DrawableToColorImage(tkwin, drawable, x, y, width, height,
1364 inputGamma);
1365 if (image == NULL) {
1366 Tcl_AppendResult(interp,
1367 "can't grab window or pixmap (possibly obscured?)", (char *)NULL);
1368 return TCL_ERROR; /* Can't grab window image */
1369 }
1370 if ((destWidth != width) || (destHeight != height)) {
1371 Blt_ColorImage destImage;
1372
1373 /*
1374 * The requested size for the destination image is different than
1375 * that of the source snapshot. Resample the image as necessary.
1376 * We'll use a cheap box filter. I'm assuming that the destination
1377 * image will typically be smaller than the original.
1378 */
1379 destImage = Blt_ResampleColorImage(image, destWidth, destHeight,
1380 bltBoxFilterPtr, bltBoxFilterPtr);
1381 Blt_FreeColorImage(image);
1382 image = destImage;
1383 }
1384 Blt_ColorImageToPhoto(image, photo);
1385 Blt_FreeColorImage(image);
1386 return TCL_OK;
1387}
1388
1389#if HAVE_JPEG
1390/*
1391 *----------------------------------------------------------------------
1392 *
1393 * Blt_JPEGToPhoto --
1394 *
1395 * Reads a JPEG file and converts it into a Tk photo.
1396 *
1397 * Results:
1398 * A standard Tcl result. If successful, TCL_OK is returned
1399 * and the designated photo is re-written with the image.
1400 * Otherwise, TCL_ERROR is returned and interp->result will
1401 * contain an error message.
1402 *
1403 *----------------------------------------------------------------------
1404 */
1405int
1406Blt_JPEGToPhoto(interp, fileName, photo)
1407 Tcl_Interp *interp;
1408 char *fileName;
1409 Tk_PhotoHandle photo; /* The photo image to write into. */
1410{
1411 Blt_ColorImage image;
1412
1413 image = Blt_JPEGToColorImage(interp, fileName);
1414 if (image == NULL) {
1415 return TCL_ERROR;
1416 }
1417 Blt_ColorImageToPhoto(image, photo);
1418 Blt_FreeColorImage(image);
1419 return TCL_OK;
1420}
1421#endif /* HAVE_JPEG */
1422
1423/*
1424 * --------------------------------------------------------------------------
1425 *
1426 * ShearY --
1427 *
1428 * Shears a row horizontally. Antialiasing limited to filtering
1429 * two adjacent pixels. So the shear angle must be between +-45
1430 * degrees.
1431 *
1432 * Results:
1433 * None.
1434 *
1435 * Side Effects:
1436 * The sheared image is drawn into the destination color image.
1437 *
1438 * --------------------------------------------------------------------------
1439 */
1440static void
1441ShearY(src, dest, y, offset, frac, bgColor)
1442 Blt_ColorImage src, dest;
1443 int y; /* Designates the row to be sheared */
1444 int offset; /* Difference between of */
1445 double frac;
1446 Pix32 bgColor;
1447{
1448 Pix32 *srcPtr, *destPtr;
1449 Pix32 *srcRowPtr, *destRowPtr;
1450 register int x, dx;
1451 int destWidth;
1452 int srcWidth;
1453 int red, blue, green, alpha;
1454 int leftRed, leftGreen, leftBlue, leftAlpha;
1455 int oldLeftRed, oldLeftGreen, oldLeftBlue, oldLeftAlpha;
1456 int ifrac;
1457
1458 srcWidth = Blt_ColorImageWidth(src);
1459 destWidth = Blt_ColorImageWidth(dest);
1460
1461 destRowPtr = Blt_ColorImageBits(dest) + (y * destWidth);
1462 srcRowPtr = Blt_ColorImageBits(src) + (y * srcWidth);
1463
1464 destPtr = destRowPtr;
1465 for (x = 0; x < offset; x++) {
1466 *destPtr++ = bgColor;
1467 }
1468 destPtr = destRowPtr + offset;
1469 srcPtr = srcRowPtr;
1470 dx = offset;
1471
1472 oldLeftRed = uchar2si(bgColor.Red);
1473 oldLeftGreen = uchar2si(bgColor.Green);
1474 oldLeftBlue = uchar2si(bgColor.Blue);
1475 oldLeftAlpha = uchar2si(bgColor.Alpha);
1476
1477 ifrac = float2si(frac);
1478 for (x = 0; x < srcWidth; x++, dx++) { /* Loop through row pixels */
1479 leftRed = srcPtr->Red * ifrac;
1480 leftGreen = srcPtr->Green * ifrac;
1481 leftBlue = srcPtr->Blue * ifrac;
1482 leftAlpha = srcPtr->Alpha * ifrac;
1483 if ((dx >= 0) && (dx < destWidth)) {
1484 red = uchar2si(srcPtr->Red) - (leftRed - oldLeftRed);
1485 green = uchar2si(srcPtr->Green) - (leftGreen - oldLeftGreen);
1486 blue = uchar2si(srcPtr->Blue) - (leftBlue - oldLeftBlue);
1487 alpha = uchar2si(srcPtr->Alpha) - (leftAlpha - oldLeftAlpha);
1488 destPtr->Red = SICLAMP(red);
1489 destPtr->Green = SICLAMP(green);
1490 destPtr->Blue = SICLAMP(blue);
1491 destPtr->Alpha = SICLAMP(alpha);
1492 }
1493 oldLeftRed = leftRed;
1494 oldLeftGreen = leftGreen;
1495 oldLeftBlue = leftBlue;
1496 oldLeftAlpha = leftAlpha;
1497 srcPtr++, destPtr++;
1498 }
1499 x = srcWidth + offset;
1500 destPtr = Blt_ColorImageBits(dest) + (y * destWidth) + x;
1501 if (x < destWidth) {
1502 leftRed = uchar2si(bgColor.Red);
1503 leftGreen = uchar2si(bgColor.Green);
1504 leftBlue = uchar2si(bgColor.Blue);
1505 leftAlpha = uchar2si(bgColor.Alpha);
1506
1507 red = leftRed + oldLeftRed - (bgColor.Red * ifrac);
1508 green = leftGreen + oldLeftGreen - (bgColor.Green * ifrac);
1509 blue = leftBlue + oldLeftBlue - (bgColor.Blue * ifrac);
1510 alpha = leftAlpha + oldLeftAlpha - (bgColor.Alpha * ifrac);
1511 destPtr->Red = SICLAMP(red);
1512 destPtr->Green = SICLAMP(green);
1513 destPtr->Blue = SICLAMP(blue);
1514 destPtr->Alpha = SICLAMP(alpha);
1515 destPtr++;
1516 }
1517 for (x++; x < destWidth; x++) {
1518 *destPtr++ = bgColor;
1519 }
1520}
1521
1522/*
1523 * --------------------------------------------------------------------------
1524 *
1525 * ShearX --
1526 *
1527 * Shears a column. Antialiasing is limited to filtering two
1528 * adjacent pixels. So the shear angle must be between +-45
1529 * degrees.
1530 *
1531 * Results:
1532 * None.
1533 *
1534 * Side Effects:
1535 * The sheared image is drawn into the destination color image.
1536 *
1537 * --------------------------------------------------------------------------
1538 */
1539static void
1540ShearX(src, dest, x, offset, frac, bgColor)
1541 Blt_ColorImage src, dest;
1542 int x; /* Column in source image to be sheared. */
1543 int offset; /* Offset of */
1544 double frac; /* Fraction of subpixel. */
1545 Pix32 bgColor;
1546{
1547 Pix32 *srcPtr, *destPtr;
1548 register int y, dy;
1549#ifdef notef
1550 int srcWidth;
1551 int destWidth;
1552#endif
1553 int destHeight;
1554 int srcHeight;
1555 int red, blue, green, alpha;
1556 int leftRed, leftGreen, leftBlue, leftAlpha;
1557 int oldLeftRed, oldLeftGreen, oldLeftBlue, oldLeftAlpha;
1558 int ifrac;
1559
1560#ifdef notdef
1561 srcWidth = Blt_ColorImageWidth(src);
1562 destWidth = Blt_ColorImageWidth(dest);
1563#endif
1564 srcHeight = Blt_ColorImageHeight(src);
1565 destHeight = Blt_ColorImageHeight(dest);
1566#ifdef notdef
1567 destPtr = Blt_ColorImageBits(dest) + x;
1568#endif
1569 for (y = 0; y < offset; y++) {
1570 destPtr = Blt_ColorImagePixel(dest, x, y);
1571 *destPtr = bgColor;
1572#ifdef notdef
1573 destPtr += destWidth;
1574#endif
1575 }
1576
1577 oldLeftRed = uchar2si(bgColor.Red);
1578 oldLeftGreen = uchar2si(bgColor.Green);
1579 oldLeftBlue = uchar2si(bgColor.Blue);
1580 oldLeftAlpha = uchar2si(bgColor.Alpha);
1581#ifdef notdef
1582 destPtr = Blt_ColorImageBits(dest) + x + offset;
1583 srcPtr = Blt_ColorImageBits(src) + x;
1584#endif
1585 dy = offset;
1586 ifrac = float2si(frac);
1587 for (y = 0; y < srcHeight; y++, dy++) {
1588 srcPtr = Blt_ColorImagePixel(src, x, y);
1589 leftRed = srcPtr->Red * ifrac;
1590 leftGreen = srcPtr->Green * ifrac;
1591 leftBlue = srcPtr->Blue * ifrac;
1592 leftAlpha = srcPtr->Alpha * ifrac;
1593 if ((dy >= 0) && (dy < destHeight)) {
1594 destPtr = Blt_ColorImagePixel(dest, x, dy);
1595 red = uchar2si(srcPtr->Red) - (leftRed - oldLeftRed);
1596 green = uchar2si(srcPtr->Green) - (leftGreen - oldLeftGreen);
1597 blue = uchar2si(srcPtr->Blue) - (leftBlue - oldLeftBlue);
1598 alpha = uchar2si(srcPtr->Alpha) - (leftAlpha - oldLeftAlpha);
1599 destPtr->Red = SICLAMP(red);
1600 destPtr->Green = SICLAMP(green);
1601 destPtr->Blue = SICLAMP(blue);
1602 destPtr->Alpha = SICLAMP(alpha);
1603 }
1604 oldLeftRed = leftRed;
1605 oldLeftGreen = leftGreen;
1606 oldLeftBlue = leftBlue;
1607 oldLeftAlpha = leftAlpha;
1608#ifdef notdef
1609 srcPtr += srcWidth;
1610 destPtr += destWidth;
1611#endif
1612 }
1613 y = srcHeight + offset;
1614#ifdef notdef
1615 destPtr = Blt_ColorImageBits(dest) + (y * destWidth) + x + offset;
1616#endif
1617 if (y < destHeight) {
1618 leftRed = uchar2si(bgColor.Red);
1619 leftGreen = uchar2si(bgColor.Green);
1620 leftBlue = uchar2si(bgColor.Blue);
1621 leftAlpha = uchar2si(bgColor.Alpha);
1622
1623 destPtr = Blt_ColorImagePixel(dest, x, y);
1624 red = leftRed + oldLeftRed - (bgColor.Red * ifrac);
1625 green = leftGreen + oldLeftGreen - (bgColor.Green * ifrac);
1626 blue = leftBlue + oldLeftBlue - (bgColor.Blue * ifrac);
1627 alpha = leftAlpha + oldLeftAlpha - (bgColor.Alpha * ifrac);
1628 destPtr->Red = SICLAMP(red);
1629 destPtr->Green = SICLAMP(green);
1630 destPtr->Blue = SICLAMP(blue);
1631 destPtr->Alpha = SICLAMP(alpha);
1632#ifdef notdef
1633 destPtr += destWidth;
1634#endif
1635 }
1636
1637 for (y++; y < destHeight; y++) {
1638 destPtr = Blt_ColorImagePixel(dest, x, y);
1639 *destPtr = bgColor;
1640#ifdef notdef
1641 destPtr += destWidth;
1642#endif
1643 }
1644}
1645
1646/*
1647 * ---------------------------------------------------------------------------
1648 *
1649 * Rotate45 --
1650 *
1651 * Rotates an image by a given angle. The angle must be in the
1652 * range -45.0 to 45.0 inclusive. Anti-aliasing filtering is
1653 * performed on two adjacent pixels, so the angle can't be so
1654 * great as to force a sheared pixel to occupy 3 destination
1655 * pixels. Performs a three shear rotation described below.
1656 *
1657 * Reference: Alan W. Paeth, "A Fast Algorithm for General Raster
1658 * Rotation", Graphics Gems, pp 179-195.
1659 *
1660 *
1661 * Results:
1662 * Returns a newly allocated rotated image.
1663 *
1664 * ---------------------------------------------------------------------------
1665 */
1666static Blt_ColorImage
1667Rotate45(src, theta, bgColor)
1668 Blt_ColorImage src;
1669 double theta;
1670 Pix32 bgColor;
1671{
1672 int tmpWidth, tmpHeight;
1673 int srcWidth, srcHeight;
1674 double sinTheta, cosTheta, tanTheta;
1675 double skewf;
1676 int skewi;
1677 Blt_ColorImage tmp1, tmp2, dest;
1678 register int x, y;
1679
1680 sinTheta = sin(theta);
1681 cosTheta = cos(theta);
1682 tanTheta = tan(theta * 0.5);
1683
1684 srcWidth = Blt_ColorImageWidth(src);
1685 srcHeight = Blt_ColorImageHeight(src);
1686
1687 tmpWidth = srcWidth + (int)(srcHeight * FABS(tanTheta));
1688 tmpHeight = srcHeight;
1689
1690 /* 1st shear */
1691
1692 tmp1 = Blt_CreateColorImage(tmpWidth, tmpHeight);
1693 assert(tmp1);
1694
1695 if (tanTheta >= 0.0) { /* Positive angle */
1696 for (y = 0; y < tmpHeight; y++) {
1697 skewf = (y + 0.5) * tanTheta;
1698 skewi = (int)floor(skewf);
1699 ShearY(src, tmp1, y, skewi, skewf - skewi, bgColor);
1700 }
1701 } else { /* Negative angle */
1702 for (y = 0; y < tmpHeight; y++) {
1703 skewf = ((y - srcHeight) + 0.5) * tanTheta;
1704 skewi = (int)floor(skewf);
1705 ShearY(src, tmp1, y, skewi, skewf - skewi, bgColor);
1706 }
1707 }
1708 tmpHeight = (int)(srcWidth * FABS(sinTheta) + srcHeight * cosTheta) + 1;
1709
1710 tmp2 = Blt_CreateColorImage(tmpWidth, tmpHeight);
1711 assert(tmp2);
1712
1713 /* 2nd shear */
1714
1715 if (sinTheta > 0.0) { /* Positive angle */
1716 skewf = (srcWidth - 1) * sinTheta;
1717 } else { /* Negative angle */
1718 skewf = (srcWidth - tmpWidth) * -sinTheta;
1719 }
1720 for (x = 0; x < tmpWidth; x++) {
1721 skewi = (int)floor(skewf);
1722 ShearX(tmp1, tmp2, x, skewi, skewf - skewi, bgColor);
1723 skewf -= sinTheta;
1724 }
1725
1726 Blt_FreeColorImage(tmp1);
1727
1728 /* 3rd shear */
1729
1730 tmpWidth = (int)(srcHeight * FABS(sinTheta) + srcWidth * cosTheta) + 1;
1731
1732 dest = Blt_CreateColorImage(tmpWidth, tmpHeight);
1733 assert(dest);
1734
1735 if (sinTheta >= 0.0) { /* Positive angle */
1736 skewf = (srcWidth - 1) * sinTheta * -tanTheta;
1737 } else { /* Negative angle */
1738 skewf = tanTheta * ((srcWidth - 1) * -sinTheta - (tmpHeight - 1));
1739 }
1740 for (y = 0; y < tmpHeight; y++) {
1741 skewi = (int)floor(skewf);
1742 ShearY(tmp2, dest, y, skewi, skewf - skewi, bgColor);
1743 skewf += tanTheta;
1744 }
1745 Blt_FreeColorImage(tmp2);
1746 return dest;
1747}
1748
1749/*
1750 * ---------------------------------------------------------------------------
1751 *
1752 * CopyColorImage --
1753 *
1754 * Creates a copy of the given color image.
1755 *
1756 * Results:
1757 * Returns the new copy.
1758 *
1759 * ---------------------------------------------------------------------------
1760 */
1761static Blt_ColorImage
1762CopyColorImage(src)
1763 Blt_ColorImage src;
1764{
1765 unsigned int width, height;
1766 Pix32 *srcPtr, *destPtr;
1767 Blt_ColorImage dest;
1768
1769 width = Blt_ColorImageWidth(src);
1770 height = Blt_ColorImageHeight(src);
1771 dest = Blt_CreateColorImage(width, height);
1772 srcPtr = Blt_ColorImageBits(src);
1773 destPtr = Blt_ColorImageBits(dest);
1774 memcpy(destPtr, srcPtr, width * height * sizeof(Pix32));
1775 return dest;
1776}
1777
1778/*
1779 * ---------------------------------------------------------------------------
1780 *
1781 * Rotate90 --
1782 *
1783 * Rotates the given color image by 90 degrees. This is part
1784 * of the special case right-angle rotations that do not create
1785 * subpixel aliasing.
1786 *
1787 * Results:
1788 * Returns a newly allocated, rotated color image.
1789 *
1790 * ---------------------------------------------------------------------------
1791 */
1792static Blt_ColorImage
1793Rotate90(src)
1794 Blt_ColorImage src;
1795{
1796 int width, height, offset;
1797 Pix32 *srcPtr, *destPtr;
1798 Blt_ColorImage dest;
1799 register int x, y;
1800
1801 height = Blt_ColorImageWidth(src);
1802 width = Blt_ColorImageHeight(src);
1803
1804 srcPtr = Blt_ColorImageBits(src);
1805 dest = Blt_CreateColorImage(width, height);
1806 offset = (height - 1) * width;
1807
1808 for (x = 0; x < width; x++) {
1809 destPtr = Blt_ColorImageBits(dest) + offset + x;
1810 for (y = 0; y < height; y++) {
1811 *destPtr = *srcPtr++;
1812 destPtr -= width;
1813 }
1814 }
1815 return dest;
1816}
1817
1818/*
1819 * ---------------------------------------------------------------------------
1820 *
1821 * Rotate180 --
1822 *
1823 * Rotates the given color image by 180 degrees. This is one of
1824 * the special case orthogonal rotations that do not create
1825 * subpixel aliasing.
1826 *
1827 * Results:
1828 * Returns a newly allocated, rotated color image.
1829 *
1830 * ---------------------------------------------------------------------------
1831 */
1832static Blt_ColorImage
1833Rotate180(src)
1834 Blt_ColorImage src;
1835{
1836 int width, height, offset;
1837 Pix32 *srcPtr, *destPtr;
1838 Blt_ColorImage dest;
1839 register int x, y;
1840
1841 width = Blt_ColorImageWidth(src);
1842 height = Blt_ColorImageHeight(src);
1843 dest = Blt_CreateColorImage(width, height);
1844
1845 srcPtr = Blt_ColorImageBits(src);
1846 offset = (height - 1) * width;
1847 for (y = 0; y < height; y++) {
1848 destPtr = Blt_ColorImageBits(dest) + offset + width - 1;
1849 for (x = 0; x < width; x++) {
1850 *destPtr-- = *srcPtr++;
1851 }
1852 offset -= width;
1853 }
1854 return dest;
1855}
1856
1857/*
1858 * ---------------------------------------------------------------------------
1859 *
1860 * Rotate270 --
1861 *
1862 * Rotates the given color image by 270 degrees. This is part
1863 * of the special case right-angle rotations that do not create
1864 * subpixel aliasing.
1865 *
1866 * Results:
1867 * Returns a newly allocated, rotated color image.
1868 *
1869 * ---------------------------------------------------------------------------
1870 */
1871static Blt_ColorImage
1872Rotate270(src)
1873 Blt_ColorImage src;
1874{
1875 int width, height;
1876 Pix32 *srcPtr, *destPtr;
1877 Blt_ColorImage dest;
1878 register int x, y;
1879
1880 height = Blt_ColorImageWidth(src);
1881 width = Blt_ColorImageHeight(src);
1882 dest = Blt_CreateColorImage(width, height);
1883
1884 srcPtr = Blt_ColorImageBits(src);
1885 for (x = width - 1; x >= 0; x--) {
1886 destPtr = Blt_ColorImageBits(dest) + x;
1887 for (y = 0; y < height; y++) {
1888 *destPtr = *srcPtr++;
1889 destPtr += width;
1890 }
1891 }
1892 return dest;
1893}
1894
1895/*
1896 *----------------------------------------------------------------------
1897 *
1898 * Blt_RotateColorImage --
1899 *
1900 * Rotates a color image by a given # of degrees.
1901 *
1902 * Results:
1903 * Returns a newly allocated, rotated color image.
1904 *
1905 *----------------------------------------------------------------------
1906 */
1907Blt_ColorImage
1908Blt_RotateColorImage(src, angle)
1909 Blt_ColorImage src;
1910 double angle;
1911{
1912 Blt_ColorImage dest, tmp;
1913 int quadrant;
1914
1915 tmp = src; /* Suppress compiler warning. */
1916
1917 /* Make the angle positive between 0 and 360 degrees. */
1918 angle = FMOD(angle, 360.0);
1919 if (angle < 0.0) {
1920 angle += 360.0;
1921 }
1922 quadrant = ROTATE_0;
1923 if ((angle > 45.0) && (angle <= 135.0)) {
1924 quadrant = ROTATE_90;
1925 angle -= 90.0;
1926 } else if ((angle > 135.0) && (angle <= 225.0)) {
1927 quadrant = ROTATE_180;
1928 angle -= 180.0;
1929 } else if ((angle > 225.0) && (angle <= 315.0)) {
1930 quadrant = ROTATE_270;
1931 angle -= 270.0;
1932 } else if (angle > 315.0) {
1933 angle -= 360.0;
1934 }
1935 /*
1936 * If necessary, create a temporary image that's been rotated
1937 * by a right-angle. We'll then rotate this color image between
1938 * -45 to 45 degrees to arrive at its final angle.
1939 */
1940 switch (quadrant) {
1941 case ROTATE_270: /* 270 degrees */
1942 tmp = Rotate270(src);
1943 break;
1944
1945 case ROTATE_90: /* 90 degrees */
1946 tmp = Rotate90(src);
1947 break;
1948
1949 case ROTATE_180: /* 180 degrees */
1950 tmp = Rotate180(src);
1951 break;
1952
1953 case ROTATE_0: /* 0 degrees */
1954 if (angle == 0.0) {
1955 tmp = CopyColorImage(src); /* Make a copy of the source. */
1956 }
1957 break;
1958 }
1959
1960 assert((angle >= -45.0) && (angle <= 45.0));
1961
1962 dest = tmp;
1963 if (angle != 0.0) {
1964 double theta;
1965 Pix32 *srcPtr;
1966 Pix32 bgColor;
1967
1968 /* FIXME: pick up background blending color from somewhere */
1969 srcPtr = Blt_ColorImageBits(src);
1970 bgColor = *srcPtr;
1971 bgColor.Red = bgColor.Green = bgColor.Blue = 0xFF;
1972 bgColor.Alpha = 0x00; /* Transparent background */
1973 theta = (angle / 180.0) * M_PI;
1974 dest = Rotate45(tmp, theta, bgColor);
1975 if (tmp != src) {
1976 Blt_FreeColorImage(tmp);
1977 }
1978 }
1979 return dest;
1980}
1981
1982#define NC 256
1983enum ColorIndices { RED, GREEN, BLUE };
1984
1985#define R0 (cubePtr->r0)
1986#define R1 (cubePtr->r1)
1987#define G0 (cubePtr->g0)
1988#define G1 (cubePtr->g1)
1989#define B0 (cubePtr->b0)
1990#define B1 (cubePtr->b1)
1991
1992typedef struct {
1993 int r0, r1; /* min, max values:
1994 * min exclusive max inclusive */
1995 int g0, g1;
1996 int b0, b1;
1997 int vol;
1998} Cube;
1999
2000/*
2001 *----------------------------------------------------------------------
2002 *
2003 * Histogram is in elements 1..HISTSIZE along each axis,
2004 * element 0 is for base or marginal value
2005 * NB: these must start out 0!
2006 *----------------------------------------------------------------------
2007 */
2008typedef struct {
2009 long int wt[33][33][33]; /* # pixels in voxel */
2010 long int mR[33][33][33]; /* Sum over voxel of red pixel values */
2011 long int mG[33][33][33]; /* Sum over voxel of green pixel values */
2012 long int mB[33][33][33]; /* Sum over voxel of blue pixel values */
2013 long int gm2[33][33][33]; /* Variance */
2014} ColorImageStatistics;
2015
2016/*
2017 * Build 3-D color histogram of counts, R/G/B, c^2
2018 */
2019static ColorImageStatistics *
2020GetColorImageStatistics(image)
2021 Blt_ColorImage image;
2022{
2023 register int r, g, b;
2024#define MAX_INTENSITIES 256
2025 unsigned int sqr[MAX_INTENSITIES];
2026 int numPixels;
2027 Pix32 *srcPtr, *endPtr;
2028 register int i;
2029 ColorImageStatistics *s;
2030
2031 s = Blt_Calloc(1, sizeof(ColorImageStatistics));
2032 assert(s);
2033
2034 /* Precompute table of squares. */
2035 for (i = 0; i < MAX_INTENSITIES; i++) {
2036 sqr[i] = i * i;
2037 }
2038 numPixels = Blt_ColorImageWidth(image) * Blt_ColorImageHeight(image);
2039
2040 for (srcPtr = Blt_ColorImageBits(image), endPtr = srcPtr + numPixels;
2041 srcPtr < endPtr; srcPtr++) {
2042 /*
2043 * Reduce the number of bits (5) per color component. This
2044 * will keep the table size (2^15) reasonable without perceptually
2045 * affecting the final image.
2046 */
2047 r = (srcPtr->Red >> 3) + 1;
2048 g = (srcPtr->Green >> 3) + 1;
2049 b = (srcPtr->Blue >> 3) + 1;
2050 s->wt[r][g][b] += 1;
2051 s->mR[r][g][b] += srcPtr->Red;
2052 s->mG[r][g][b] += srcPtr->Green;
2053 s->mB[r][g][b] += srcPtr->Blue;
2054 s->gm2[r][g][b] += sqr[srcPtr->Red] + sqr[srcPtr->Green] +
2055 sqr[srcPtr->Blue];
2056 }
2057 return s;
2058}
2059
2060/*
2061 *----------------------------------------------------------------------
2062 * At conclusion of the histogram step, we can interpret
2063 * wt[r][g][b] = sum over voxel of P(c)
2064 * mR[r][g][b] = sum over voxel of r*P(c) , similarly for mG, mB
2065 * m2[r][g][b] = sum over voxel of c^2*P(c)
2066 * Actually each of these should be divided by 'size' to give the usual
2067 * interpretation of P() as ranging from 0 to 1, but we needn't do that here.
2068 *----------------------------------------------------------------------
2069 */
2070
2071/*
2072 *----------------------------------------------------------------------
2073 We now convert histogram into moments so that we can rapidly calculate
2074 * the sums of the above quantities over any desired box.
2075 *----------------------------------------------------------------------
2076 */
2077
2078static void
2079M3d(s) /* compute cumulative moments. */
2080 ColorImageStatistics *s;
2081{
2082 register unsigned char i, r, g, b, r0;
2083 long int line, rLine, gLine, bLine;
2084 long int area[33], rArea[33], gArea[33], bArea[33];
2085 unsigned int line2, area2[33];
2086
2087 for (r = 1, r0 = 0; r <= 32; r++, r0++) {
2088 for (i = 0; i <= 32; ++i) {
2089 area2[i] = area[i] = rArea[i] = gArea[i] = bArea[i] = 0;
2090 }
2091 for (g = 1; g <= 32; g++) {
2092 line2 = line = rLine = gLine = bLine = 0;
2093 for (b = 1; b <= 32; b++) {
2094 /* ind1 = RGBIndex(r, g, b); */
2095
2096 line += s->wt[r][g][b];
2097 rLine += s->mR[r][g][b];
2098 gLine += s->mG[r][g][b];
2099 bLine += s->mB[r][g][b];
2100 line2 += s->gm2[r][g][b];
2101
2102 area[b] += line;
2103 rArea[b] += rLine;
2104 gArea[b] += gLine;
2105 bArea[b] += bLine;
2106 area2[b] += line2;
2107
2108 /* ind2 = ind1 - 1089; [r0][g][b] */
2109 s->wt[r][g][b] = s->wt[r0][g][b] + area[b];
2110 s->mR[r][g][b] = s->mR[r0][g][b] + rArea[b];
2111 s->mG[r][g][b] = s->mG[r0][g][b] + gArea[b];
2112 s->mB[r][g][b] = s->mB[r0][g][b] + bArea[b];
2113 s->gm2[r][g][b] = s->gm2[r0][g][b] + area2[b];
2114 }
2115 }
2116 }
2117}
2118
2119/*
2120 *----------------------------------------------------------------------
2121 *
2122 * Compute sum over a box of any given statistic
2123 *
2124 *----------------------------------------------------------------------
2125 */
2126static INLINE
2127long int
2128Volume(cubePtr, m)
2129 Cube *cubePtr;
2130 long int m[33][33][33];
2131{
2132 return (m[R1][G1][B1] - m[R1][G1][B0] - m[R1][G0][B1] + m[R1][G0][B0] -
2133 m[R0][G1][B1] + m[R0][G1][B0] + m[R0][G0][B1] - m[R0][G0][B0]);
2134}
2135
2136/*
2137 *----------------------------------------------------------------------
2138 *
2139 * The next two routines allow a slightly more efficient
2140 * calculation of Volume() for a proposed subbox of a given box.
2141 * The sum of Top() and Bottom() is the Volume() of a subbox split
2142 * in the given direction and with the specified new upper
2143 * bound.
2144 *
2145 *----------------------------------------------------------------------
2146 */
2147
2148/* Compute part of Volume(cubePtr, mmt) that doesn't depend on r1, g1, or b1 */
2149/* (depending on dir) */
2150static long int
2151Bottom(cubePtr, dir, m)
2152 Cube *cubePtr;
2153 unsigned char dir;
2154 long int m[33][33][33]; /* Moment */
2155{
2156 switch (dir) {
2157 case RED:
2158 return -m[R0][G1][B1] + m[R0][G1][B0] + m[R0][G0][B1] - m[R0][G0][B0];
2159 case GREEN:
2160 return -m[R1][G0][B1] + m[R1][G0][B0] + m[R0][G0][B1] - m[R0][G0][B0];
2161 case BLUE:
2162 return -m[R1][G1][B0] + m[R1][G0][B0] + m[R0][G1][B0] - m[R0][G0][B0];
2163 }
2164 return 0;
2165}
2166
2167/*
2168 *----------------------------------------------------------------------
2169 *
2170 * Compute remainder of Volume(cubePtr, mmt), substituting pos for
2171 * r1, g1, or b1 (depending on dir)
2172 *
2173 *----------------------------------------------------------------------
2174 */
2175static long int
2176Top(cubePtr, dir, pos, m)
2177 Cube *cubePtr;
2178 unsigned char dir;
2179 int pos;
2180 long int m[33][33][33];
2181{
2182 switch (dir) {
2183 case RED:
2184 return (m[pos][G1][B1] - m[pos][G1][B0] -
2185 m[pos][G0][B1] + m[pos][G0][B0]);
2186
2187 case GREEN:
2188 return (m[R1][pos][B1] - m[R1][pos][B0] -
2189 m[R0][pos][B1] + m[R0][pos][B0]);
2190
2191 case BLUE:
2192 return (m[R1][G1][pos] - m[R1][G0][pos] -
2193 m[R0][G1][pos] + m[R0][G0][pos]);
2194 }
2195 return 0;
2196}
2197
2198/*
2199 *----------------------------------------------------------------------
2200 *
2201 * Compute the weighted variance of a box NB: as with the raw
2202 * statistics, this is really the (variance * size)
2203 *
2204 *----------------------------------------------------------------------
2205 */
2206static double
2207Variance(cubePtr, s)
2208 Cube *cubePtr;
2209 ColorImageStatistics *s;
2210{
2211 double dR, dG, dB, xx;
2212
2213 dR = Volume(cubePtr, s->mR);
2214 dG = Volume(cubePtr, s->mG);
2215 dB = Volume(cubePtr, s->mB);
2216 xx = (s->gm2[R1][G1][B1] - s->gm2[R1][G1][B0] -
2217 s->gm2[R1][G0][B1] + s->gm2[R1][G0][B0] -
2218 s->gm2[R0][G1][B1] + s->gm2[R0][G1][B0] +
2219 s->gm2[R0][G0][B1] - s->gm2[R0][G0][B0]);
2220 return (xx - (dR * dR + dG * dG + dB * dB) / Volume(cubePtr, s->wt));
2221}
2222
2223/*
2224 *----------------------------------------------------------------------
2225 *
2226 * We want to minimize the sum of the variances of two subboxes.
2227 * The sum(c^2) terms can be ignored since their sum over both
2228 * subboxes is the same (the sum for the whole box) no matter
2229 * where we split. The remaining terms have a minus sign in
2230 * the variance formula, so we drop the minus sign and MAXIMIZE
2231 * the sum of the two terms.
2232 *
2233 *----------------------------------------------------------------------
2234 */
2235static double
2236Maximize(cubePtr, dir, first, last, cut, rWhole, gWhole, bWhole, wWhole, s)
2237 Cube *cubePtr;
2238 unsigned char dir;
2239 int first, last, *cut;
2240 long int rWhole, gWhole, bWhole, wWhole;
2241 ColorImageStatistics *s;
2242{
2243 register long int rHalf, gHalf, bHalf, wHalf;
2244 long int rBase, gBase, bBase, wBase;
2245 register int i;
2246 register double temp, max;
2247
2248 rBase = Bottom(cubePtr, dir, s->mR);
2249 gBase = Bottom(cubePtr, dir, s->mG);
2250 bBase = Bottom(cubePtr, dir, s->mB);
2251 wBase = Bottom(cubePtr, dir, s->wt);
2252 max = 0.0;
2253 *cut = -1;
2254 for (i = first; i < last; i++) {
2255 rHalf = rBase + Top(cubePtr, dir, i, s->mR);
2256 gHalf = gBase + Top(cubePtr, dir, i, s->mG);
2257 bHalf = bBase + Top(cubePtr, dir, i, s->mB);
2258 wHalf = wBase + Top(cubePtr, dir, i, s->wt);
2259
2260 /* Now half_x is sum over lower half of box, if split at i */
2261 if (wHalf == 0) { /* subbox could be empty of pixels! */
2262 continue; /* never split into an empty box */
2263 } else {
2264 temp = ((double)rHalf * rHalf + (float)gHalf * gHalf +
2265 (double)bHalf * bHalf) / wHalf;
2266 }
2267 rHalf = rWhole - rHalf;
2268 gHalf = gWhole - gHalf;
2269 bHalf = bWhole - bHalf;
2270 wHalf = wWhole - wHalf;
2271 if (wHalf == 0) { /* Subbox could be empty of pixels! */
2272 continue; /* never split into an empty box */
2273 } else {
2274 temp += ((double)rHalf * rHalf + (float)gHalf * gHalf +
2275 (double)bHalf * bHalf) / wHalf;
2276 }
2277 if (temp > max) {
2278 max = temp;
2279 *cut = i;
2280 }
2281 }
2282 return max;
2283}
2284
2285/*
2286 *----------------------------------------------------------------------
2287 *----------------------------------------------------------------------
2288 */
2289static int
2290Cut(set1, set2, s)
2291 Cube *set1, *set2;
2292 ColorImageStatistics *s;
2293{
2294 unsigned char dir;
2295 int rCut, gCut, bCut;
2296 double rMax, gMax, bMax;
2297 long int rWhole, gWhole, bWhole, wWhole;
2298
2299 rWhole = Volume(set1, s->mR);
2300 gWhole = Volume(set1, s->mG);
2301 bWhole = Volume(set1, s->mB);
2302 wWhole = Volume(set1, s->wt);
2303
2304 rMax = Maximize(set1, RED, set1->r0 + 1, set1->r1, &rCut,
2305 rWhole, gWhole, bWhole, wWhole, s);
2306 gMax = Maximize(set1, GREEN, set1->g0 + 1, set1->g1, &gCut,
2307 rWhole, gWhole, bWhole, wWhole, s);
2308 bMax = Maximize(set1, BLUE, set1->b0 + 1, set1->b1, &bCut,
2309 rWhole, gWhole, bWhole, wWhole, s);
2310
2311 if ((rMax >= gMax) && (rMax >= bMax)) {
2312 dir = RED;
2313 if (rCut < 0) {
2314 return 0; /* can't split the box */
2315 }
2316 } else {
2317 dir = ((gMax >= rMax) && (gMax >= bMax)) ? GREEN : BLUE;
2318 }
2319 set2->r1 = set1->r1;
2320 set2->g1 = set1->g1;
2321 set2->b1 = set1->b1;
2322
2323 switch (dir) {
2324 case RED:
2325 set2->r0 = set1->r1 = rCut;
2326 set2->g0 = set1->g0;
2327 set2->b0 = set1->b0;
2328 break;
2329
2330 case GREEN:
2331 set2->g0 = set1->g1 = gCut;
2332 set2->r0 = set1->r0;
2333 set2->b0 = set1->b0;
2334 break;
2335
2336 case BLUE:
2337 set2->b0 = set1->b1 = bCut;
2338 set2->r0 = set1->r0;
2339 set2->g0 = set1->g0;
2340 break;
2341 }
2342 set1->vol = (set1->r1 - set1->r0) * (set1->g1 - set1->g0) *
2343 (set1->b1 - set1->b0);
2344 set2->vol = (set2->r1 - set2->r0) * (set2->g1 - set2->g0) *
2345 (set2->b1 - set2->b0);
2346 return 1;
2347}
2348
2349
2350static int
2351SplitColorSpace(s, cubes, nColors)
2352 ColorImageStatistics *s;
2353 Cube *cubes;
2354 int nColors;
2355{
2356 double *vv, temp;
2357 register int i;
2358 register int n, k;
2359
2360 vv = Blt_Malloc(sizeof(double) * nColors);
2361 assert(vv);
2362
2363 cubes[0].r0 = cubes[0].g0 = cubes[0].b0 = 0;
2364 cubes[0].r1 = cubes[0].g1 = cubes[0].b1 = 32;
2365 for (i = 1, n = 0; i < nColors; i++) {
2366 if (Cut(cubes + n, cubes + i, s)) {
2367 /*
2368 * Volume test ensures we won't try to cut one-cell box
2369 */
2370 vv[n] = vv[i] = 0.0;
2371 if (cubes[n].vol > 1) {
2372 vv[n] = Variance(cubes + n, s);
2373 }
2374 if (cubes[i].vol > 1) {
2375 vv[i] = Variance(cubes + i, s);
2376 }
2377 } else {
2378 vv[n] = 0.0; /* don't try to split this box again */
2379 i--; /* didn't create box i */
2380 }
2381
2382 n = 0;
2383 temp = vv[0];
2384 for (k = 1; k <= i; k++) {
2385 if (vv[k] > temp) {
2386 temp = vv[k];
2387 n = k;
2388 }
2389 }
2390 if (temp <= 0.0) {
2391 i++;
2392 fprintf(stderr, "Only got %d boxes\n", i);
2393 break;
2394 }
2395 }
2396 Blt_Free(vv);
2397 return i;
2398}
2399
2400/*
2401 *----------------------------------------------------------------------
2402 *--------------------------------------------------------------------
2403 */
2404static void
2405Mark(cubePtr, label, tag)
2406 Cube *cubePtr;
2407 int label;
2408 unsigned int tag[33][33][33];
2409{
2410 register int r, g, b;
2411
2412 for (r = R0 + 1; r <= R1; r++) {
2413 for (g = G0 + 1; g <= G1; g++) {
2414 for (b = B0 + 1; b <= B1; b++) {
2415 tag[r][g][b] = label;
2416 }
2417 }
2418 }
2419}
2420
2421static unsigned int *
2422CreateColorLookupTable(s, cubes, nColors)
2423 ColorImageStatistics *s;
2424 Cube *cubes;
2425 int nColors;
2426{
2427 unsigned int *lut;
2428 Pix32 color;
2429 unsigned int red, green, blue;
2430 unsigned int weight;
2431 register Cube *cubePtr;
2432 register int i;
2433
2434 lut = Blt_Calloc(sizeof(unsigned int), 33 * 33 * 33);
2435 assert(lut);
2436
2437 color.Alpha = (unsigned char)-1;
2438 for (cubePtr = cubes, i = 0; i < nColors; i++, cubePtr++) {
2439 weight = Volume(cubePtr, s->wt);
2440 if (weight) {
2441 red = (Volume(cubePtr, s->mR) / weight) * (NC + 1);
2442 green = (Volume(cubePtr, s->mG) / weight) * (NC + 1);
2443 blue = (Volume(cubePtr, s->mB) / weight) * (NC + 1);
2444 } else {
2445 fprintf(stderr, "bogus box %d\n", i);
2446 red = green = blue = 0;
2447 }
2448 color.Red = red >> 8;
2449 color.Green = green >> 8;
2450 color.Blue = blue >> 8;
2451 Mark(cubePtr, color.value, lut);
2452 }
2453 return lut;
2454}
2455
2456static void
2457MapColors(src, dest, lut)
2458 Blt_ColorImage src, dest;
2459 unsigned int lut[33][33][33];
2460{
2461 /* Apply the color lookup table against the original image */
2462 int width, height;
2463 int count;
2464 Pix32 *srcPtr, *destPtr, *endPtr;
2465 unsigned char alpha;
2466
2467 width = Blt_ColorImageWidth(src);
2468 height = Blt_ColorImageHeight(src);
2469 count = width * height;
2470
2471 srcPtr = Blt_ColorImageBits(src);
2472 destPtr = Blt_ColorImageBits(dest);
2473 for (endPtr = destPtr + count; destPtr < endPtr; srcPtr++, destPtr++) {
2474 alpha = srcPtr->Alpha;
2475 destPtr->value = lut[srcPtr->Red>>3][srcPtr->Green>>3][srcPtr->Blue>>3];
2476 destPtr->Alpha = alpha;
2477 }
2478}
2479
2480/*
2481 *----------------------------------------------------------------------
2482 *
2483 * Blt_QuantizeColorImage --
2484 *
2485 * C Implementation of Wu's Color Quantizer (v. 2) (see Graphics Gems
2486 * vol. II, pp. 126-133)
2487 *
2488 * Author: Xiaolin Wu
2489 * Dept. of Computer Science Univ. of Western
2490 * Ontario London, Ontario
2491 * N6A 5B7
2492 * wu@csd.uwo.ca
2493 *
2494 * Algorithm:
2495 * Greedy orthogonal bipartition of RGB space for variance
2496 * minimization aided by inclusion-exclusion tricks. For
2497 * speed no nearest neighbor search is done. Slightly
2498 * better performance can be expected by more
2499 * sophisticated but more expensive versions.
2500 *
2501 * The author thanks Tom Lane at Tom_Lane@G.GP.CS.CMU.EDU for much of
2502 * additional documentation and a cure to a previous bug.
2503 *
2504 * Free to distribute, comments and suggestions are appreciated.
2505 *
2506 *----------------------------------------------------------------------
2507 */
2508int
2509Blt_QuantizeColorImage(src, dest, reduceColors)
2510 Blt_ColorImage src, dest; /* Source and destination images. */
2511 int reduceColors; /* Reduced number of colors. */
2512{
2513 Cube *cubes;
2514 ColorImageStatistics *statistics;
2515 int nColors;
2516 unsigned int *lut;
2517
2518 /*
2519 * Allocated a structure to hold color statistics.
2520 */
2521 statistics = GetColorImageStatistics(src);
2522 M3d(statistics);
2523
2524 cubes = Blt_Malloc(sizeof(Cube) * reduceColors);
2525 assert(cubes);
2526
2527 nColors = SplitColorSpace(statistics, cubes, reduceColors);
2528 assert(nColors <= reduceColors);
2529
2530 lut = CreateColorLookupTable(statistics, cubes, nColors);
2531 Blt_Free(statistics);
2532 Blt_Free(cubes);
2533 MapColors(src, dest, lut);
2534 Blt_Free(lut);
2535 return TCL_OK;
2536}
2537
2538Region2D *
2539Blt_SetRegion(x, y, width, height, regionPtr)
2540 int x, y, width, height;
2541 Region2D *regionPtr;
2542{
2543 regionPtr->left = x;
2544 regionPtr->top = y;
2545 regionPtr->right = x + width - 1;
2546 regionPtr->bottom = y + height - 1;
2547 return regionPtr;
2548}
2549
2550
2551/*
2552 * Each call to Tk_GetImage returns a pointer to one of the following
2553 * structures, which is used as a token by clients (widgets) that
2554 * display images.
2555 */
2556typedef struct TkImageStruct {
2557 Tk_Window tkwin; /* Window passed to Tk_GetImage (needed to
2558 * "re-get" the image later if the manager
2559 * changes). */
2560 Display *display; /* Display for tkwin. Needed because when
2561 * the image is eventually freed tkwin may
2562 * not exist anymore. */
2563 struct TkImageMasterStruct *masterPtr;
2564 /* Master for this image (identifiers image
2565 * manager, for example). */
2566 ClientData instanceData;
2567 /* One word argument to pass to image manager
2568 * when dealing with this image instance. */
2569 Tk_ImageChangedProc *changeProc;
2570 /* Code in widget to call when image changes
2571 * in a way that affects redisplay. */
2572 ClientData widgetClientData;
2573 /* Argument to pass to changeProc. */
2574 struct Image *nextPtr; /* Next in list of all image instances
2575 * associated with the same name. */
2576
2577} TkImage;
2578
2579/*
2580 * For each image master there is one of the following structures,
2581 * which represents a name in the image table and all of the images
2582 * instantiated from it. Entries in mainPtr->imageTable point to
2583 * these structures.
2584 */
2585typedef struct TkImageMasterStruct {
2586 Tk_ImageType *typePtr; /* Information about image type. NULL means
2587 * that no image manager owns this image: the
2588 * image was deleted. */
2589 ClientData masterData; /* One-word argument to pass to image mgr
2590 * when dealing with the master, as opposed
2591 * to instances. */
2592 int width, height; /* Last known dimensions for image. */
2593 Blt_HashTable *tablePtr; /* Pointer to hash table containing image
2594 * (the imageTable field in some TkMainInfo
2595 * structure). */
2596 Blt_HashEntry *hPtr; /* Hash entry in mainPtr->imageTable for
2597 * this structure (used to delete the hash
2598 * entry). */
2599 TkImage *instancePtr; /* Pointer to first in list of instances
2600 * derived from this name. */
2601} TkImageMaster;
2602
2603
2604typedef struct TkPhotoMasterStruct TkPhotoMaster;
2605typedef struct TkColorTableStruct TkColorTable;
2606
2607typedef struct TkPhotoInstanceStruct {
2608 TkPhotoMaster *masterPtr; /* Pointer to master for image. */
2609 Display *display; /* Display for windows using this instance. */
2610 Colormap colormap; /* The image may only be used in windows with
2611 * this particular colormap. */
2612 struct TkPhotoInstanceStruct *nextPtr;
2613 /* Pointer to the next instance in the list
2614 * of instances associated with this master. */
2615 int refCount; /* Number of instances using this structure. */
2616 Tk_Uid palette; /* Palette for these particular instances. */
2617 double outputGamma; /* Gamma value for these instances. */
2618 Tk_Uid defaultPalette; /* Default palette to use if a palette
2619 * is not specified for the master. */
2620 TkColorTable *colorTablePtr; /* Pointer to information about colors
2621 * allocated for image display in windows
2622 * like this one. */
2623 Pixmap pixels; /* X pixmap containing dithered image. */
2624 int width, height; /* Dimensions of the pixmap. */
2625 char *error; /* Error image, used in dithering. */
2626 XImage *imagePtr; /* Image structure for converted pixels. */
2627 XVisualInfo visualInfo; /* Information about the visual that these
2628 * windows are using. */
2629 GC gc; /* Graphics context for writing images
2630 * to the pixmap. */
2631} TkPhotoInstance;
2632
2633/*
2634 * ----------------------------------------------------------------------
2635 *
2636 * Tk_ImageDeleted --
2637 *
2638 * Is there any other way to determine if an image has been
2639 * deleted?
2640 *
2641 * Results:
2642 * Returns 1 if the image has been deleted, 0 otherwise.
2643 *
2644 * ----------------------------------------------------------------------
2645 */
2646/*LINTLIBRARY*/
2647int
2648Tk_ImageIsDeleted(tkImage)
2649 Tk_Image tkImage; /* Token for image. */
2650{
2651 TkImage *imagePtr = (TkImage *) tkImage;
2652
2653 if (imagePtr->masterPtr == NULL) {
2654 return TRUE;
2655 }
2656 return (imagePtr->masterPtr->typePtr == NULL);
2657}
2658
2659/*LINTLIBRARY*/
2660Tk_ImageMaster
2661Tk_ImageGetMaster(tkImage)
2662 Tk_Image tkImage; /* Token for image. */
2663{
2664 TkImage *imagePtr = (TkImage *)tkImage;
2665
2666 return (Tk_ImageMaster) imagePtr->masterPtr;
2667}
2668
2669/*LINTLIBRARY*/
2670Tk_ImageType *
2671Tk_ImageGetType(tkImage)
2672 Tk_Image tkImage; /* Token for image. */
2673{
2674 TkImage *imagePtr = (TkImage *)tkImage;
2675
2676 return imagePtr->masterPtr->typePtr;
2677}
2678
2679/*LINTLIBRARY*/
2680Pixmap
2681Tk_ImageGetPhotoPixmap(tkImage)
2682 Tk_Image tkImage; /* Token for image. */
2683{
2684 TkImage *imagePtr = (TkImage *)tkImage;
2685
2686 if (strcmp(imagePtr->masterPtr->typePtr->name, "photo") == 0) {
2687 TkPhotoInstance *instPtr = (TkPhotoInstance *)imagePtr->instanceData;
2688 return instPtr->pixels;
2689 }
2690 return None;
2691}
2692
2693/*LINTLIBRARY*/
2694GC
2695Tk_ImageGetPhotoGC(photoImage)
2696 Tk_Image photoImage; /* Token for image. */
2697{
2698 TkImage *imagePtr = (TkImage *) photoImage;
2699 if (strcmp(imagePtr->masterPtr->typePtr->name, "photo") == 0) {
2700 TkPhotoInstance *instPtr = (TkPhotoInstance *)imagePtr->instanceData;
2701 return instPtr->gc;
2702 }
2703 return NULL;
2704}
2705
2706/*
2707 *----------------------------------------------------------------------
2708 *
2709 * TempImageChangedProc
2710 *
2711 * The image is over-written each time it's resized. We always
2712 * resample from the color image we saved when the photo image
2713 * was specified (-image option). So we only worry if the image
2714 * is deleted.
2715 *
2716 * Results:
2717 * None.
2718 *
2719 *----------------------------------------------------------------------
2720 */
2721/* ARGSUSED */
2722static void
2723TempImageChangedProc(clientData, x, y, width, height, imageWidth, imageHeight)
2724 ClientData clientData;
2725 int x, y, width, height; /* Not used. */
2726 int imageWidth, imageHeight;/* Not used. */
2727{
2728#ifdef notdef
2729 fprintf(stderr, "should be redrawing temp image\n");
2730#endif
2731}
2732
2733Tk_Image
2734Blt_CreateTemporaryImage(interp, tkwin, clientData)
2735 Tcl_Interp *interp;
2736 Tk_Window tkwin;
2737 ClientData clientData;
2738{
2739 Tk_Image token;
2740 char *name; /* Contains image name. */
2741
2742 if (Tcl_Eval(interp, "image create photo") != TCL_OK) {
2743 return NULL;
2744 }
2745 name = (char *)Tcl_GetStringResult(interp);
2746 token = Tk_GetImage(interp, tkwin, name, TempImageChangedProc, clientData);
2747 if (token == NULL) {
2748 return NULL;
2749 }
2750 return token;
2751}
2752
2753int
2754Blt_DestroyTemporaryImage(interp, tkImage)
2755 Tcl_Interp *interp;
2756 Tk_Image tkImage;
2757{
2758 if (tkImage != NULL) {
2759 if (Tcl_VarEval(interp, "image delete ", Blt_NameOfImage(tkImage),
2760 (char *)NULL) != TCL_OK) {
2761 return TCL_ERROR;
2762 }
2763 Tk_FreeImage(tkImage);
2764 }
2765 return TCL_OK;
2766}
2767
2768char *
2769Blt_NameOfImage(tkImage)
2770 Tk_Image tkImage;
2771{
2772 Tk_ImageMaster master;
2773
2774 master = Tk_ImageGetMaster(tkImage);
2775 return Tk_NameOfImage(master);
2776}
Note: See TracBrowser for help on using the repository browser.