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