OSDN Git Service

Please enter the commit message for your changes. Lines starting
[eos/base.git] / util / src / TclTk / blt2.5 / generic / bltImage.c
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
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
85 Blt_FreeColorImage(imagePtr)
86     struct ColorImage *imagePtr;
87 {
88     Blt_Free(imagePtr->bits);
89     Blt_Free(imagePtr);
90 }
91
92 void
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
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
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
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
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
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
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
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
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
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
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
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
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
522 GaussianFilter(x)
523     double x;
524 {
525     return exp(-2.0 * x * x) * SQRT_2PI;
526 }
527
528 static double
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
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 
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
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
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
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
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
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
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
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 *
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
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
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
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
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
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
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
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
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
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 *
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
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
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
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
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
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 *
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
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
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 *
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
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
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
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 
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
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 *
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 }