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