OSDN Git Service

33af404edf434e2ad353171214778c3a90f96666
[eos/base.git] / util / src / TclTk / blt2.5 / generic / bltWinop.c
1 /*
2  * bltWinop.c --
3  *
4  *      This module implements simple window commands for the BLT toolkit.
5  *
6  * Copyright 1991-1998 Lucent Technologies, Inc.
7  *
8  * Permission to use, copy, modify, and distribute this software and
9  * its documentation for any purpose and without fee is hereby
10  * granted, provided that the above copyright notice appear in all
11  * copies and that both that the copyright notice and warranty
12  * disclaimer appear in supporting documentation, and that the names
13  * of Lucent Technologies any of their entities not be used in
14  * advertising or publicity pertaining to distribution of the software
15  * without specific, written prior permission.
16  *
17  * Lucent Technologies disclaims all warranties with regard to this
18  * software, including all implied warranties of merchantability and
19  * fitness.  In no event shall Lucent Technologies be liable for any
20  * special, indirect or consequential damages or any damages
21  * whatsoever resulting from loss of use, data or profits, whether in
22  * an action of contract, negligence or other tortuous action, arising
23  * out of or in connection with the use or performance of this
24  * software.
25  */
26
27 #include "bltInt.h"
28
29 #ifndef NO_WINOP
30
31 #include "bltImage.h"
32 #include <X11/Xutil.h>
33 #ifndef WIN32
34 #include <X11/Xproto.h>
35 #endif
36
37 static Tcl_CmdProc WinopCmd;
38
39 static int
40 GetRealizedWindow(interp, string, tkwinPtr)
41     Tcl_Interp *interp;
42     char *string;
43     Tk_Window *tkwinPtr;
44 {
45     Tk_Window tkwin;
46
47     tkwin = Tk_NameToWindow(interp, string, Tk_MainWindow(interp));
48     if (tkwin == NULL) {
49         return TCL_ERROR;
50     }
51     if (Tk_WindowId(tkwin) == None) {
52         Tk_MakeWindowExist(tkwin);
53     }
54     *tkwinPtr = tkwin;
55     return TCL_OK;
56 }
57
58 static Window
59 StringToWindow(interp, string)
60     Tcl_Interp *interp;
61     char *string;
62 {
63     int xid;
64
65     if (string[0] == '.') {
66         Tk_Window tkwin;
67
68         if (GetRealizedWindow(interp, string, &tkwin) != TCL_OK) {
69             return None;
70         }
71         if (Tk_IsTopLevel(tkwin)) {
72             return Blt_GetRealWindowId(tkwin);
73         } else {
74             return Tk_WindowId(tkwin);
75         }
76     } else if (Tcl_GetInt(interp, string, &xid) == TCL_OK) {
77 #ifdef WIN32
78         static TkWinWindow tkWinWindow;
79
80         tkWinWindow.handle = (HWND)xid;
81         tkWinWindow.winPtr = NULL;
82         tkWinWindow.type = TWD_WINDOW;
83         return (Window)&tkWinWindow;
84 #else
85         return (Window)xid;
86 #endif
87     }
88     return None;
89 }
90
91 #ifdef WIN32
92
93 static int
94 GetWindowSize(
95     Tcl_Interp *interp,
96     Window window,
97     int *widthPtr, 
98     int *heightPtr)
99 {
100     int result;
101     RECT region;
102     TkWinWindow *winPtr = (TkWinWindow *)window;
103
104     result = GetWindowRect(winPtr->handle, &region);
105     if (result) {
106         *widthPtr = region.right - region.left;
107         *heightPtr = region.bottom - region.top;
108         return TCL_OK;
109     }
110     return TCL_ERROR;
111 }
112
113 #else
114
115 /*
116  *----------------------------------------------------------------------
117  *
118  * XGeometryErrorProc --
119  *
120  *      Flags errors generated from XGetGeometry calls to the X server.
121  *
122  * Results:
123  *      Always returns 0.
124  *
125  * Side Effects:
126  *      Sets a flag, indicating an error occurred.
127  *
128  *----------------------------------------------------------------------
129  */
130 /* ARGSUSED */
131 static int
132 XGeometryErrorProc(clientData, errEventPtr)
133     ClientData clientData;
134     XErrorEvent *errEventPtr;
135 {
136     int *errorPtr = clientData;
137
138     *errorPtr = TCL_ERROR;
139     return 0;
140 }
141
142 static int
143 GetWindowSize(interp, window, widthPtr, heightPtr)
144     Tcl_Interp *interp;
145     Window window;
146     int *widthPtr, *heightPtr;
147 {
148     int result;
149     int any = -1;
150     int x, y, borderWidth, depth;
151     Window root;
152     Tk_ErrorHandler handler;
153     Tk_Window tkwin;
154     
155     tkwin = Tk_MainWindow(interp);
156     handler = Tk_CreateErrorHandler(Tk_Display(tkwin), any, X_GetGeometry, 
157             any, XGeometryErrorProc, &result);
158     result = XGetGeometry(Tk_Display(tkwin), window, &root, &x, &y, 
159           (unsigned int *)widthPtr, (unsigned int *)heightPtr,
160           (unsigned int *)&borderWidth, (unsigned int *)&depth);
161     Tk_DeleteErrorHandler(handler);
162     XSync(Tk_Display(tkwin), False);
163     if (result) {
164         return TCL_OK;
165     }
166     return TCL_ERROR;
167 }
168 #endif /*WIN32*/
169
170
171 #ifndef WIN32
172 /*ARGSUSED*/
173 static int
174 ColormapOp(clientData, interp, argc, argv)
175     ClientData clientData;
176     Tcl_Interp *interp;
177     int argc;                   /* Not used. */
178     char **argv;
179 {
180     register int i;
181     Tk_Window tkwin;
182 #define MAXCOLORS 256
183     register XColor *colorPtr;
184     XColor colorArr[MAXCOLORS];
185     unsigned long int pixelValues[MAXCOLORS];
186     int inUse[MAXCOLORS];
187     char string[20];
188     unsigned long int *indexPtr;
189     int nFree;
190
191     if (GetRealizedWindow(interp, argv[2], &tkwin) != TCL_OK) {
192         return TCL_ERROR;
193     }
194     /* Initially, we assume all color cells are allocated. */
195     memset((char *)inUse, 0, sizeof(int) * MAXCOLORS);
196
197     /*
198      * Start allocating color cells.  This will tell us which color cells
199      * haven't already been allocated in the colormap.  We'll release the
200      * cells as soon as we find out how many there are.
201      */
202     nFree = 0;
203     for (indexPtr = pixelValues, i = 0; i < MAXCOLORS; i++, indexPtr++) {
204         if (!XAllocColorCells(Tk_Display(tkwin), Tk_Colormap(tkwin),
205                 False, NULL, 0, indexPtr, 1)) {
206             break;
207         }
208         inUse[*indexPtr] = TRUE;/* Indicate the cell is unallocated */
209         nFree++;
210     }
211     XFreeColors(Tk_Display(tkwin), Tk_Colormap(tkwin), pixelValues, nFree, 0);
212     for (colorPtr = colorArr, i = 0; i < MAXCOLORS; i++, colorPtr++) {
213         colorPtr->pixel = i;
214     }
215     XQueryColors(Tk_Display(tkwin), Tk_Colormap(tkwin), colorArr, MAXCOLORS);
216     for (colorPtr = colorArr, i = 0; i < MAXCOLORS; i++, colorPtr++) {
217         if (!inUse[colorPtr->pixel]) {
218             sprintf(string, "#%02x%02x%02x", (colorPtr->red >> 8),
219                 (colorPtr->green >> 8), (colorPtr->blue >> 8));
220             Tcl_AppendElement(interp, string);
221             sprintf(string, "%ld", colorPtr->pixel);
222             Tcl_AppendElement(interp, string);
223         }
224     }
225     return TCL_OK;
226 }
227
228 #endif
229
230 /*ARGSUSED*/
231 static int
232 LowerOp(clientData, interp, argc, argv)
233     ClientData clientData;
234     Tcl_Interp *interp;
235     int argc;                   /* Not used. */
236     char **argv;
237 {
238     register int i;
239     Window window;
240     Display *display;
241
242     display = Tk_Display(Tk_MainWindow(interp));
243     for (i = 2; i < argc; i++) {
244         window = StringToWindow(interp, argv[i]);
245         if (window == None) {
246             return TCL_ERROR;
247         }
248         XLowerWindow(display, window);
249     }
250     return TCL_OK;
251 }
252
253 /*ARGSUSED*/
254 static int
255 RaiseOp(clientData, interp, argc, argv)
256     ClientData clientData;
257     Tcl_Interp *interp;
258     int argc;                   /* Not used. */
259     char **argv;
260 {
261     register int i;
262     Window window;
263     Display *display;
264
265     display = Tk_Display(Tk_MainWindow(interp));
266     for (i = 2; i < argc; i++) {
267         window = StringToWindow(interp, argv[i]);
268         if (window == None) {
269             return TCL_ERROR;
270         }
271         XRaiseWindow(display, window);
272     }
273     return TCL_OK;
274 }
275
276 /*ARGSUSED*/
277 static int
278 MapOp(clientData, interp, argc, argv)
279     ClientData clientData;
280     Tcl_Interp *interp;
281     int argc;                   /* Not used. */
282     char **argv;
283 {
284     register int i;
285     Window window;
286     Display *display;
287
288     display = Tk_Display(Tk_MainWindow(interp));
289     for (i = 2; i < argc; i++) {
290         if (argv[i][0] == '.') {
291             Tk_Window tkwin;
292             Tk_FakeWin *fakePtr;
293
294             if (GetRealizedWindow(interp, argv[i], &tkwin) != TCL_OK) {
295                 return TCL_ERROR;
296             }
297             fakePtr = (Tk_FakeWin *) tkwin;
298             fakePtr->flags |= TK_MAPPED;
299             window = Tk_WindowId(tkwin);
300         } else {
301             int xid;
302
303             if (Tcl_GetInt(interp, argv[i], &xid) != TCL_OK) {
304                 return TCL_ERROR;
305             }
306             window = (Window)xid;
307         }
308         XMapWindow(display, window);
309     }
310     return TCL_OK;
311 }
312
313 /*ARGSUSED*/
314 static int
315 MoveOp(clientData, interp, argc, argv)
316     ClientData clientData;
317     Tcl_Interp *interp;
318     int argc;                   /* Not Used. */
319     char **argv;
320 {
321     int x, y;
322     Tk_Window tkwin;
323     Window window;
324     Display *display;
325
326     tkwin = Tk_MainWindow(interp);
327     display = Tk_Display(tkwin);
328     window = StringToWindow(interp, argv[2]);
329     if (window == None) {
330         return TCL_ERROR;
331     }
332     if (Tk_GetPixels(interp, tkwin, argv[3], &x) != TCL_OK) {
333         Tcl_AppendResult(interp, ": bad window x-coordinate", (char *)NULL);
334         return TCL_ERROR;
335     }
336     if (Tk_GetPixels(interp, tkwin, argv[4], &y) != TCL_OK) {
337         Tcl_AppendResult(interp, ": bad window y-coordinate", (char *)NULL);
338         return TCL_ERROR;
339     }
340     XMoveWindow(display, window, x, y);
341     return TCL_OK;
342 }
343
344 /*ARGSUSED*/
345 static int
346 UnmapOp(clientData, interp, argc, argv)
347     ClientData clientData;
348     Tcl_Interp *interp;
349     int argc;                   /* Not used. */
350     char **argv;
351 {
352     register int i;
353     Window window;
354     Display *display;
355
356     display = Tk_Display(Tk_MainWindow(interp));
357     for (i = 2; i < argc; i++) {
358         if (argv[i][0] == '.') {
359             Tk_Window tkwin;
360             Tk_FakeWin *fakePtr;
361
362             if (GetRealizedWindow(interp, argv[i], &tkwin) != TCL_OK) {
363                 return TCL_ERROR;
364             }
365             fakePtr = (Tk_FakeWin *) tkwin;
366             fakePtr->flags &= ~TK_MAPPED;
367             window = Tk_WindowId(tkwin);
368         } else {
369             int xid;
370
371             if (Tcl_GetInt(interp, argv[i], &xid) != TCL_OK) {
372                 return TCL_ERROR;
373             }
374             window = (Window)xid;
375         }
376         XMapWindow(display, window);
377     }
378     return TCL_OK;
379 }
380
381 /* ARGSUSED */
382 static int
383 ChangesOp(clientData, interp, argc, argv)
384     ClientData clientData;
385     Tcl_Interp *interp;
386     int argc;                   /* Not used. */
387     char **argv;                /* Not used. */
388 {
389     Tk_Window tkwin;
390
391     if (GetRealizedWindow(interp, argv[2], &tkwin) != TCL_OK) {
392         return TCL_ERROR;
393     }
394     if (Tk_IsTopLevel(tkwin)) {
395         XSetWindowAttributes attrs;
396         Window window;
397         unsigned int mask;
398
399         window = Blt_GetRealWindowId(tkwin);
400         attrs.backing_store = WhenMapped;
401         attrs.save_under = True;
402         mask = CWBackingStore | CWSaveUnder;
403         XChangeWindowAttributes(Tk_Display(tkwin), window, mask, &attrs);
404     }
405     return TCL_OK;
406 }
407
408 /* ARGSUSED */
409 static int
410 ParentOp(clientData, interp, argc, argv)
411 ClientData clientData;
412 Tcl_Interp *interp;
413 int argc;                       /* Not used. */
414 char **argv;            /* Not used. */
415 {
416     Window window;
417     int value;
418     char buf[50];
419
420     if (Tcl_GetInt(interp, argv[2], &value) != TCL_OK) {
421         return TCL_ERROR;
422     }
423     window = Blt_GetParent(Tk_Display(Tk_MainWindow(interp)), (Window)value);
424     if (window) {
425         sprintf(buf, "0x%x", (int)window);    
426         Tcl_AppendResult(interp, buf, 0);
427     }
428     return TCL_OK;
429 }
430
431 /* ARGSUSED */
432 static int
433 QueryOp(clientData, interp, argc, argv)
434     ClientData clientData;
435     Tcl_Interp *interp;
436     int argc;                   /* Not used. */
437     char **argv;                /* Not used. */
438 {
439     int rootX, rootY, childX, childY;
440     Window root, child;
441     unsigned int mask;
442     Tk_Window tkwin = (Tk_Window)clientData;
443
444     /* GetCursorPos */
445     if (XQueryPointer(Tk_Display(tkwin), Tk_WindowId(tkwin), &root,
446             &child, &rootX, &rootY, &childX, &childY, &mask)) {
447         char string[200];
448
449         sprintf(string, "@%d,%d", rootX, rootY);
450         Tcl_SetResult(interp, string, TCL_VOLATILE);
451     }
452     return TCL_OK;
453 }
454
455 /*ARGSUSED*/
456 static int
457 WarpToOp(clientData, interp, argc, argv)
458     ClientData clientData;
459     Tcl_Interp *interp;
460     int argc;                   /* Not used. */
461     char **argv;
462 {
463     Tk_Window tkwin, mainWindow;
464
465     mainWindow = (Tk_Window)clientData;
466     if (argc > 2) {
467         if (argv[2][0] == '@') {
468             int x, y;
469             Window root;
470
471             if (Blt_GetXY(interp, mainWindow, argv[2], &x, &y) != TCL_OK) {
472                 return TCL_ERROR;
473             }
474             root = RootWindow(Tk_Display(mainWindow), 
475                 Tk_ScreenNumber(mainWindow));
476             XWarpPointer(Tk_Display(mainWindow), None, root, 0, 0, 0, 0, x, y);
477         } else {
478             if (GetRealizedWindow(interp, argv[2], &tkwin) != TCL_OK) {
479                 return TCL_ERROR;
480             }
481             if (!Tk_IsMapped(tkwin)) {
482                 Tcl_AppendResult(interp, "can't warp to unmapped window \"",
483                     Tk_PathName(tkwin), "\"", (char *)NULL);
484                 return TCL_ERROR;
485             }
486             XWarpPointer(Tk_Display(tkwin), None, Tk_WindowId(tkwin),
487                 0, 0, 0, 0, Tk_Width(tkwin) / 2, Tk_Height(tkwin) / 2);
488         }
489     }
490     return QueryOp(clientData, interp, 0, (char **)NULL);
491 }
492
493 #ifdef notdef
494 static int
495 ReparentOp(clientData, interp, argc, argv)
496     ClientData clientData;
497     Tcl_Interp *interp;
498     int argc;
499     char **argv;
500 {
501     Tk_Window tkwin;
502
503     if (GetRealizedWindow(interp, argv[2], &tkwin) != TCL_OK) {
504         return TCL_ERROR;
505     }
506     if (argc == 4) {
507         Tk_Window newParent;
508
509         if (GetRealizedWindow(interp, argv[3], &newParent) != TCL_OK) {
510             return TCL_ERROR;
511         }
512         Blt_RelinkWindow2(tkwin, Blt_GetRealWindowId(tkwin), newParent, 0, 0);
513     } else {
514         Blt_UnlinkWindow(tkwin);
515     }
516     return TCL_OK;
517 }
518 #endif
519
520
521 /*
522  * This is a temporary home for these image routines.  They will be
523  * moved when a new image type is created for them.
524  */
525 /*ARGSUSED*/
526 static int
527 ConvolveOp(clientData, interp, argc, argv)
528     ClientData clientData;      /* Not used. */
529     Tcl_Interp *interp;
530     int argc;                   /* Not used. */
531     char **argv;
532 {
533     Tk_PhotoHandle srcPhoto, destPhoto;
534     Blt_ColorImage srcImage, destImage;
535     Filter2D filter;
536     int nValues;
537     char **valueArr;
538     double *kernel;
539     double value, sum;
540     register int i;
541     int dim;
542     int result = TCL_ERROR;
543
544     srcPhoto = Blt_FindPhoto(interp, argv[2]);
545     if (srcPhoto == NULL) {
546         Tcl_AppendResult(interp, "source image \"", argv[2], "\" doesn't",
547             " exist or is not a photo image", (char *)NULL);
548         return TCL_ERROR;
549     }
550     destPhoto = Blt_FindPhoto(interp, argv[3]);
551     if (destPhoto == NULL) {
552         Tcl_AppendResult(interp, "destination image \"", argv[3], "\" doesn't",
553             " exist or is not a photo image", (char *)NULL);
554         return TCL_ERROR;
555     }
556     if (Tcl_SplitList(interp, argv[4], &nValues, &valueArr) != TCL_OK) {
557         return TCL_ERROR;
558     }
559     kernel = NULL;
560     if (nValues == 0) {
561         Tcl_AppendResult(interp, "empty kernel", (char *)NULL);
562         goto error;
563     }
564     dim = (int)sqrt((double)nValues);
565     if ((dim * dim) != nValues) {
566         Tcl_AppendResult(interp, "kernel must be square", (char *)NULL);
567         goto error;
568     }
569     kernel = Blt_Malloc(sizeof(double) * nValues);
570     sum = 0.0;
571     for (i = 0; i < nValues; i++) {
572         if (Tcl_GetDouble(interp, valueArr[i], &value) != TCL_OK) {
573             goto error;
574         }
575         kernel[i] = value;
576         sum += value;
577     }
578     filter.kernel = kernel;
579     filter.support = dim * 0.5;
580     filter.sum = (sum == 0.0) ? 1.0 : sum;
581     filter.scale = 1.0 / nValues;
582
583     srcImage = Blt_PhotoToColorImage(srcPhoto);
584     destImage = Blt_ConvolveColorImage(srcImage, &filter);
585     Blt_FreeColorImage(srcImage);
586     Blt_ColorImageToPhoto(destImage, destPhoto);
587     Blt_FreeColorImage(destImage);
588     result = TCL_OK;
589   error:
590     if (valueArr != NULL) {
591         Blt_Free(valueArr);
592     }
593     if (kernel != NULL) {
594         Blt_Free(kernel);
595     }
596     return result;
597 }
598
599 /*ARGSUSED*/
600 static int
601 QuantizeOp(clientData, interp, argc, argv)
602     ClientData clientData;      /* Not used. */
603     Tcl_Interp *interp;
604     int argc;                   /* Not used. */
605     char **argv;
606 {
607     Tk_PhotoHandle srcPhoto, destPhoto;
608     Tk_PhotoImageBlock src, dest;
609     Blt_ColorImage srcImage, destImage;
610     int nColors = 1;
611     int result;
612
613     srcPhoto = Blt_FindPhoto(interp, argv[2]);
614     if (srcPhoto == NULL) {
615         Tcl_AppendResult(interp, "source image \"", argv[2], "\" doesn't",
616             " exist or is not a photo image", (char *)NULL);
617         return TCL_ERROR;
618     }
619     Tk_PhotoGetImage(srcPhoto, &src);
620     if ((src.width <= 1) || (src.height <= 1)) {
621         Tcl_AppendResult(interp, "source image \"", argv[2], "\" is empty",
622             (char *)NULL);
623         return TCL_ERROR;
624     }
625     destPhoto = Blt_FindPhoto(interp, argv[3]);
626     if (destPhoto == NULL) {
627         Tcl_AppendResult(interp, "destination image \"", argv[3], "\" doesn't",
628             " exist or is not a photo image", (char *)NULL);
629         return TCL_ERROR;
630     }
631     Tk_PhotoGetImage(destPhoto, &dest);
632     if ((dest.width != src.width) || (dest.height != src.height)) {
633         Tk_PhotoSetSize(destPhoto, src.width, src.height);
634     }
635     if (argc>4) {
636        if (Tcl_GetInt(interp, argv[4], &nColors) != TCL_OK) {
637         return TCL_ERROR;
638        }
639     }
640     srcImage = Blt_PhotoToColorImage(srcPhoto);
641     destImage = Blt_PhotoToColorImage(destPhoto);
642     result = Blt_QuantizeColorImage(srcImage, destImage, nColors);
643     if (result == TCL_OK) {
644         Blt_ColorImageToPhoto(destImage, destPhoto);
645     }
646     Blt_FreeColorImage(srcImage);
647     Blt_FreeColorImage(destImage);
648     return result;
649 }
650
651 static int
652 GetColorPix32(Tcl_Interp *interp, Tk_Window tkwin, char *color, Pix32 *colPtr) {
653     XColor *xCol;
654     int red, green, blue;
655     
656     colPtr->Alpha = 255;
657     if (*color == '#' && strlen(color) == 7 && 3 ==
658         sscanf(color+1, "%02x%02x%02x", &red, &green, &blue)) {
659         colPtr->Red = red;
660         colPtr->Green = green;
661         colPtr->Blue = blue;
662         return TCL_OK;
663     }
664     xCol = Tk_GetColor(interp, tkwin, Tk_GetUid(color));
665     if (xCol == NULL) {
666         return TCL_ERROR;
667     }
668     colPtr->Red = (xCol->red >> 8);
669     colPtr->Green = (xCol->green >> 8);
670     colPtr->Blue = (xCol->blue >> 8);
671     return TCL_OK;
672 }
673
674 static int
675 XColorToPix32(XColor *xCol, Pix32 *colPtr) {
676     
677     colPtr->Alpha = 255;
678     colPtr->Red = (xCol->red >> 8);
679     colPtr->Green = (xCol->green >> 8);
680     colPtr->Blue = (xCol->blue >> 8);
681     return TCL_OK;
682 }
683
684 /*ARGSUSED*/
685 static int
686 AlphaOp(clientData, interp, argc, argv)
687     ClientData clientData;      /* Not used. */
688     Tcl_Interp *interp;
689     int argc;                   /* Not used. */
690     char **argv;
691 {
692     Tk_PhotoHandle srcPhoto, destPhoto;
693     Tk_PhotoImageBlock src, dest;
694     Blt_ColorImage srcImage, destImage;
695     int result, alpha, anycolor = 0, withAlpha, hasWith = 0;
696     Tk_Window tkwin = (Tk_Window)clientData;
697     Pix32 oldColor;
698     char *string;
699     int negate = 0, shift = 0;
700
701     alpha = 0;
702     if (!strcmp("-shift", argv[2])) {
703         shift = 1;
704         argc -= 1;
705         argv += 1;
706     }
707     
708     srcPhoto = Blt_FindPhoto(interp, argv[2]);
709     if (srcPhoto == NULL) {
710         Tcl_AppendResult(interp, "source image \"", argv[2], "\" doesn't",
711             " exist or is not a photo image", (char *)NULL);
712         return TCL_ERROR;
713     }
714     Tk_PhotoGetImage(srcPhoto, &src);
715     if ((src.width <= 1) || (src.height <= 1)) {
716         Tcl_AppendResult(interp, "source image \"", argv[2], "\" is empty",
717             (char *)NULL);
718         return TCL_ERROR;
719     }
720     destPhoto = Blt_FindPhoto(interp, argv[3]);
721     if (destPhoto == NULL) {
722         Tcl_AppendResult(interp, "destination image \"", argv[3], "\" doesn't",
723             " exist or is not a photo image", (char *)NULL);
724         return TCL_ERROR;
725     }
726     Tk_PhotoGetImage(destPhoto, &dest);
727     if (0 && srcPhoto == destPhoto) {
728         Tcl_AppendResult(interp, "src and dest images must be different",
729             (char *)NULL);
730         return TCL_ERROR;
731     }
732     string = argv[4];
733     if (string[0] == '!') {
734         negate = 1;
735         string++;
736     }
737     if (!strcmp(string, "*")) {
738         anycolor = 1;
739         if (argc <= 5) {
740             Tcl_AppendResult(interp, "must give an alpha", 0);
741             return TCL_ERROR;
742         }
743             
744     } else {
745         if (GetColorPix32(interp, tkwin, string, &oldColor) != TCL_OK) {
746             return TCL_ERROR;
747         }
748     }
749     if (argc > 5) {
750         if (Tcl_GetInt(interp, argv[5], &alpha) != TCL_OK) {
751             return TCL_ERROR;
752         }
753         if (alpha<0 || alpha > 255) {
754             Tcl_AppendResult(interp, "alpha must be >= 0 and <= 255", argv[3],
755                 (char *)NULL);
756                 return TCL_ERROR;
757         }
758     }
759     if (argc > 6) {
760         if (Tcl_GetInt(interp, argv[6], &withAlpha) != TCL_OK) {
761             return TCL_ERROR;
762         }
763         hasWith = 1;
764         if (withAlpha<0 || withAlpha > 255) {
765             Tcl_AppendResult(interp, "withalpha must be >= 0 and <= 255", argv[3],
766                 (char *)NULL);
767                 return TCL_ERROR;
768         }
769     }
770     if ((dest.width != src.width) || (dest.height != src.height)) {
771         Tk_PhotoSetSize(destPhoto, src.width, src.height);
772     }
773     srcImage = Blt_PhotoToColorImage(srcPhoto);
774     destImage = Blt_PhotoToColorImage(destPhoto);
775     result = TCL_OK;
776     {
777     int width, height;
778     int count, same;
779     Pix32 *srcPtr, *destPtr, *endPtr, *color;
780     unsigned char origAlpha;
781
782     width = Blt_ColorImageWidth(srcImage);
783     height = Blt_ColorImageHeight(srcImage);
784     count = width * height;
785     color = &oldColor;
786     
787     srcPtr = Blt_ColorImageBits(srcImage);
788     destPtr = Blt_ColorImageBits(destImage);
789     if (shift) {
790         for (endPtr = destPtr + count; destPtr < endPtr; srcPtr++, destPtr++) {
791             origAlpha = srcPtr->Alpha;
792             if (origAlpha == 0) {
793                 destPtr->value = srcPtr->value;
794                 continue;
795             }
796             destPtr->value = color->value;
797             destPtr->Alpha = srcPtr->Blue;
798         }
799     } else if (!anycolor) {
800         color = &oldColor;
801         for (endPtr = destPtr + count; destPtr < endPtr; srcPtr++, destPtr++) {
802             origAlpha = srcPtr->Alpha;
803             destPtr->value = srcPtr->value;
804             same = (srcPtr->Red == color->Red && srcPtr->Green == color->Green &&
805             srcPtr->Blue == color->Blue);
806             if (hasWith && origAlpha != withAlpha) {
807                 
808             } else if (negate) {
809                 if ((!same) && (origAlpha != (unsigned char)-1)) {
810                     origAlpha = alpha;
811                 }
812             } else {
813                 if (same) {
814                     origAlpha = alpha;
815                 }
816             }
817             destPtr->Alpha = origAlpha;
818         }
819     } else {
820         for (endPtr = destPtr + count; destPtr < endPtr; srcPtr++, destPtr++) {
821             origAlpha = srcPtr->Alpha;
822             destPtr->value = srcPtr->value;
823             if (hasWith && origAlpha == withAlpha) {
824                 destPtr->Alpha = alpha;
825             } else if (origAlpha == (unsigned char)-1) {
826                 destPtr->Alpha = alpha;
827             }
828         }
829     }
830     }
831
832     if (result == TCL_OK) {
833         Blt_ColorImageToPhoto(destImage, destPhoto);
834     }
835     Blt_FreeColorImage(srcImage);
836     Blt_FreeColorImage(destImage);
837     return result;
838 }
839
840 /*ARGSUSED*/
841 static int
842 RecolorOp(clientData, interp, argc, argv)
843     ClientData clientData;      /* Not used. */
844     Tcl_Interp *interp;
845     int argc;                   /* Not used. */
846     char **argv;
847 {
848     Tk_PhotoHandle srcPhoto, destPhoto;
849     Tk_PhotoImageBlock src, dest;
850     Blt_ColorImage srcImage, destImage;
851     int result, alpha;
852     Tk_Window tkwin = (Tk_Window)clientData;
853     Pix32 oldColor, newColor;
854
855     alpha = -1;
856     srcPhoto = Blt_FindPhoto(interp, argv[2]);
857     if (srcPhoto == NULL) {
858         Tcl_AppendResult(interp, "source image \"", argv[2], "\" doesn't",
859             " exist or is not a photo image", (char *)NULL);
860         return TCL_ERROR;
861     }
862     Tk_PhotoGetImage(srcPhoto, &src);
863     if ((src.width <= 1) || (src.height <= 1)) {
864         Tcl_AppendResult(interp, "source image \"", argv[2], "\" is empty",
865             (char *)NULL);
866         return TCL_ERROR;
867     }
868     destPhoto = Blt_FindPhoto(interp, argv[3]);
869     if (destPhoto == NULL) {
870         Tcl_AppendResult(interp, "destination image \"", argv[3], "\" doesn't",
871             " exist or is not a photo image", (char *)NULL);
872         return TCL_ERROR;
873     }
874     Tk_PhotoGetImage(destPhoto, &dest);
875     if (GetColorPix32(interp, tkwin, argv[4], &oldColor) != TCL_OK) {
876         return TCL_ERROR;
877     }
878     if (GetColorPix32(interp, tkwin, argv[5], &newColor) != TCL_OK) {
879         return TCL_ERROR;
880     }
881     if (argc > 6) {
882         if (Tcl_GetInt(interp, argv[6], &alpha) != TCL_OK) {
883             return TCL_ERROR;
884         }
885         if (alpha<0 || alpha > 255) {
886             Tcl_AppendResult(interp, "alpha must be >= 0 and <= 255", argv[3],
887                 (char *)NULL);
888                 return TCL_ERROR;
889         }
890     }
891     if ((dest.width != src.width) || (dest.height != src.height)) {
892         Tk_PhotoSetSize(destPhoto, src.width, src.height);
893     }
894     srcImage = Blt_PhotoToColorImage(srcPhoto);
895     destImage = Blt_PhotoToColorImage(destPhoto);
896     result = Blt_RecolorImage(srcImage, destImage, &oldColor, &newColor, alpha);
897     if (result == TCL_OK) {
898         Blt_ColorImageToPhoto(destImage, destPhoto);
899     }
900     Blt_FreeColorImage(srcImage);
901     Blt_FreeColorImage(destImage);
902     return result;
903 }
904
905 /*ARGSUSED*/
906 static int
907 ColorsOp(clientData, interp, argc, argv)
908     ClientData clientData;      /* Not used. */
909     Tcl_Interp *interp;
910     int argc;                   /* Not used. */
911     char **argv;
912 {
913     Tk_PhotoHandle srcPhoto;
914     Tk_PhotoImageBlock src;
915     Blt_ColorImage srcImage;
916     int top, x, y, isalph, iscnt, isNew, cnt;
917     int i, rng[4], from = 0;
918     register Pix32 *srcPtr;
919     Tcl_Obj *listPtr;
920     char buf[100];
921     Blt_HashEntry *hPtr;
922     Blt_HashTable hTbl;
923     Blt_HashSearch cursor;
924
925     top = 0;
926     isalph = 0;
927     iscnt = 0;
928     while (argc > 3) {
929         if (!strcmp(argv[2], "-alpha")) {
930             isalph = 1;
931         } else if (!strcmp(argv[2], "-from")) {
932             from = 1;
933             if (argc<7) {
934                 Tcl_AppendResult(interp, "expected 4 args: x1 y1 x2 y2", (char *)NULL);
935                 return TCL_ERROR;
936             }
937             for (i=0; i<4; i++) {
938                 if (Tcl_GetInt(interp, argv[i+3], rng+i)) {
939                     return TCL_ERROR;
940                 }
941             }
942             argc -= 4;
943             argv += 4;
944         } else if (!strcmp(argv[2], "-count")) {
945             iscnt = 1;
946         } else {
947             Tcl_AppendResult(interp, "expected -from, -alpha or -count", (char *)NULL);
948             return TCL_ERROR;
949         }
950         argc--;
951         argv++;
952     }
953     if (argc != 3) {
954         Tcl_AppendResult(interp, "too few arguments", (char *)NULL);
955         return TCL_ERROR;
956     }
957     srcPhoto = Blt_FindPhoto(interp, argv[2]);
958     if (srcPhoto == NULL) {
959         Tcl_AppendResult(interp, "source image \"", argv[2], "\" doesn't",
960             " exist or is not a photo image", (char *)NULL);
961         return TCL_ERROR;
962     }
963     Tk_PhotoGetImage(srcPhoto, &src);
964     if ((src.width < 1) || (src.height < 1)) {
965         return TCL_OK;
966     }
967     srcImage = Blt_PhotoToColorImage(srcPhoto);
968     srcPtr = Blt_ColorImageBits(srcImage);
969
970     Blt_InitHashTable(&hTbl, BLT_STRING_KEYS);
971     for (y = 0; y < src.height; y++) {
972         if (from && (y < rng[1] || y > rng[3])) continue;
973         for (x = 0; x < src.width; x++) {
974             if (from && (x < rng[0] || x > rng[2])) continue;
975             if (!isalph) {
976                 sprintf(buf, "#%02x%02x%02x", srcPtr->Red, srcPtr->Green, srcPtr->Blue);
977             } else {
978                 sprintf(buf, "#%02x%02x%02x:%02x", srcPtr->Red, srcPtr->Green, srcPtr->Blue, srcPtr->Alpha);
979             }
980             hPtr = Blt_CreateHashEntry(&hTbl, buf, &isNew);
981             if (isNew) {
982                 Blt_SetHashValue(hPtr, 1);
983             } else {
984                 cnt = (int)Blt_GetHashValue(hPtr);
985                 cnt++;
986                 Blt_SetHashValue(hPtr, cnt);
987             }
988             srcPtr++;
989         }
990     }
991     listPtr = Tcl_NewListObj(0,0);
992     for (hPtr = Blt_FirstHashEntry(&hTbl, &cursor);
993         hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) {
994             
995         Tcl_Obj *objPtr = Tcl_NewStringObj(Blt_GetHashKey(&hTbl, hPtr), -1);
996         Tcl_ListObjAppendElement(interp, listPtr, objPtr);
997         if (iscnt) {
998             cnt = (int)Blt_GetHashValue(hPtr);
999             sprintf(buf, "%d", cnt);
1000             objPtr = Tcl_NewStringObj(buf, -1);
1001             Tcl_ListObjAppendElement(interp, listPtr, objPtr);
1002         }
1003     }
1004     Tcl_SetObjResult(interp, listPtr);
1005     Blt_DeleteHashTable(&hTbl);
1006     return TCL_OK;
1007 }
1008
1009 /*ARGSUSED*/
1010 static int
1011 TransOp(clientData, interp, argc, argv)
1012     ClientData clientData;      /* Not used. */
1013     Tcl_Interp *interp;
1014     int argc;                   /* Not used. */
1015     char **argv;
1016 {
1017     Tk_PhotoHandle srcPhoto;
1018     Tk_PhotoImageBlock src;
1019     Blt_ColorImage srcImage;
1020     int x, y, alpha,isSet = 0;
1021     register Pix32 *srcPtr;
1022     char buf[100];
1023
1024     if (argc == 6) {
1025         isSet = 1;
1026         if (Tcl_GetInt(interp, argv[5], &alpha) != TCL_OK) {
1027             return TCL_ERROR;
1028         }
1029         if (alpha<0 || alpha > 255) {
1030             Tcl_AppendResult(interp, "alpha must be >= 0 and <= 255", argv[3],
1031                 (char *)NULL);
1032                 return TCL_ERROR;
1033         }
1034     }
1035     if (Tcl_GetInt(interp, argv[3], &x) != TCL_OK) {
1036         return TCL_ERROR;
1037     }
1038     if (Tcl_GetInt(interp, argv[4], &y) != TCL_OK) {
1039         return TCL_ERROR;
1040     }
1041     srcPhoto = Blt_FindPhoto(interp, argv[2]);
1042     if (srcPhoto == NULL) {
1043         Tcl_AppendResult(interp, "source image \"", argv[2], "\" doesn't",
1044             " exist or is not a photo image", (char *)NULL);
1045         return TCL_ERROR;
1046     }
1047     Tk_PhotoGetImage(srcPhoto, &src);
1048     if ((src.width < 1) || (src.height < 1)) {
1049         Tcl_AppendResult(interp, "empty image", (char *)NULL);
1050         return TCL_ERROR;
1051     }
1052     srcImage = Blt_PhotoToColorImage(srcPhoto);
1053     srcPtr = Blt_ColorImageBits(srcImage);
1054     if (y < 0 || y >= src.height || x < 0 || x >= src.width) {
1055         Tcl_AppendResult(interp, "out of range", (char *)NULL);
1056         return TCL_ERROR;
1057     } 
1058     srcPtr = srcPtr + y*src.width + x;
1059     if (isSet) {
1060         srcPtr->Alpha = alpha;
1061         Blt_ColorImageToPhoto(srcImage, srcPhoto);
1062     } else {
1063         sprintf(buf, "%d", srcPtr->Alpha);
1064         Tcl_AppendResult(interp, buf, 0);
1065     }
1066     return TCL_OK;
1067 }
1068
1069 #define PD_SRC_OVER(srcColor,srcAlpha,dstColor,dstAlpha) \
1070         (srcColor*srcAlpha/255) + dstAlpha*(255-srcAlpha)/255*dstColor/255
1071 #define PD_SRC_OVER_ALPHA(srcAlpha,dstAlpha) \
1072         (srcAlpha + (255-srcAlpha)*dstAlpha/255)
1073
1074 static
1075 void PixBlend(
1076     Pix32 *srcPtr, Pix32 *src2Ptr, Pix32 *destPtr,
1077     unsigned char alpha, unsigned char dAlpha
1078 ) {
1079     dAlpha = 255-alpha;
1080     destPtr->Red = PD_SRC_OVER(srcPtr->Red, alpha, src2Ptr->Red, dAlpha);
1081     destPtr->Green = PD_SRC_OVER(srcPtr->Green, alpha, src2Ptr->Green, dAlpha);
1082     destPtr->Blue = PD_SRC_OVER(srcPtr->Blue, alpha, src2Ptr->Blue, dAlpha);
1083     destPtr->Alpha = 255; /* PD_SRC_OVER_ALPHA(alpha, dAlpha); */
1084 }
1085
1086 static
1087 void PixMerged( Pix32 *srcPtr, Pix32 *src2Ptr, Pix32 *destPtr, Pix32 *colorPtr) {
1088     unsigned char alpha;
1089     int isdead;
1090     
1091     alpha = srcPtr->Blue;
1092     isdead = (srcPtr->Red == 0xde && srcPtr->Green == 0xad);
1093     if (alpha == 0 && isdead) { /* "," inner fill */
1094         destPtr->value = src2Ptr->value;
1095     } else if (alpha == 0) {    /* "." none or transparent */
1096         destPtr->value = 0;
1097     } else if (isdead == 0) {   /* solid color with alpha */
1098         destPtr->value = colorPtr->value;
1099         destPtr->Alpha = alpha;
1100     } else {                    /* Blend color with inner fill */
1101         PixBlend( colorPtr, src2Ptr, destPtr, alpha, src2Ptr->Alpha);
1102     }
1103 }
1104
1105
1106 /* For RGB grab alpha from blue and substitute maskcolor for RG="#DEAD"*/
1107 int Blt_ImageMergeInner(Tcl_Interp *interp, char *srcName, char *src2Name,
1108     char * destName, XColor *maskColor, int leaveMsg) {
1109     Tk_PhotoHandle srcPhoto, srcPhoto2, destPhoto;
1110     Tk_PhotoImageBlock src, src2, dest;
1111     Blt_ColorImage srcImage, srcImage2, destImage;
1112     double opacity;
1113     double opacity2;
1114     int result, isWc;
1115     Pix32 withColor;
1116
1117     isWc = 0;
1118     opacity = 0.5;
1119     opacity2 = -1;
1120     srcPhoto = Blt_FindPhoto(interp, srcName);
1121     if (srcPhoto == NULL) {
1122         if (leaveMsg) 
1123             Tcl_AppendResult(interp, "source image \"", srcName, "\" doesn't",
1124             " exist or is not a photo image", (char *)NULL);
1125         return TCL_ERROR;
1126     }
1127     Tk_PhotoGetImage(srcPhoto, &src);
1128     if ((src.width <= 1) || (src.height <= 1)) {
1129         if (leaveMsg) 
1130             Tcl_AppendResult(interp, "source image \"", srcName, "\" is empty",
1131                (char *)NULL);
1132         return TCL_ERROR;
1133     }
1134
1135     srcPhoto2 = Blt_FindPhoto(interp, src2Name);
1136     if (srcPhoto2 == NULL) {
1137         if (leaveMsg) 
1138             Tcl_AppendResult(interp, "source image \"", src2Name, "\" doesn't",
1139                 " exist or is not a photo image", (char *)NULL);
1140         return TCL_ERROR;
1141     }
1142     Tk_PhotoGetImage(srcPhoto2, &src2);
1143     if ((src2.width <= 1) || (src2.height <= 1)) {
1144         if (leaveMsg) 
1145            Tcl_AppendResult(interp, "source image \"", src2Name, "\" is empty",
1146                 (char *)NULL);
1147         return TCL_ERROR;
1148     }
1149     if (maskColor) {
1150         XColorToPix32(maskColor, &withColor);
1151         isWc = 1;
1152         goto domerge;
1153     }
1154     /*
1155     if (argc>5) {
1156         
1157         if (isdigit(argv[5][0]) == 0 && argv[5][0] != '.') {
1158             Tk_Window tkwin;
1159             char *colStr;
1160             
1161             tkwin = Tk_MainWindow(interp);
1162             isWc = 1;
1163             
1164             colStr = argv[5];
1165             if (colStr[0] == '!') {
1166                 colStr++;
1167                 isWc = 2;
1168             }
1169
1170                 return TCL_ERROR;
1171             }
1172             if (src.width < 4 || src.height < 4) {
1173                 Tcl_AppendResult(interp, "src image too small ",  0);
1174                 return TCL_ERROR;
1175             }
1176             if (src2.width < 4 || src2.height < 4) {
1177                 Tcl_AppendResult(interp, "src2 image too small ",  0);
1178                 return TCL_ERROR;
1179             }
1180             if (dest.width < 4 || dest.height < 4) {
1181                 Tcl_AppendResult(interp, "dest image too small ",  0);
1182                 return TCL_ERROR;
1183             }
1184             goto domerge;
1185         }
1186         
1187         if (Tcl_GetDouble(interp, argv[5], &opacity) != TCL_OK) {
1188             return TCL_ERROR;
1189         }
1190         if (opacity < 0.0 || opacity > 1.0) {
1191             Tcl_AppendResult(interp, "opacity must be >= 0.0 and <= 1.0: ", argv[5], (char *)NULL);
1192             return TCL_ERROR;
1193         }
1194     }
1195     if (argc>6) {
1196         if (Tcl_GetDouble(interp, argv[6], &opacity2) != TCL_OK) {
1197             return TCL_ERROR;
1198         }
1199         if (opacity2 < 0.0 || opacity2 > 1.0) {
1200             Tcl_AppendResult(interp, "opacity must be >= 0.0 and <= 1.0: ", argv[6], (char *)NULL);
1201             return TCL_ERROR;
1202         }
1203     }
1204     */
1205     if (isWc == 0 && ((src2.width != src.width) || (src2.height != src.height))) {
1206         int sh, sw;
1207         sw = (src2.width>src.width?src2.width:src.width);
1208         sh = (src2.height>src.height?src2.height:src.height);
1209         Tk_PhotoSetSize(srcPhoto2, sw, sh);
1210         Tk_PhotoGetImage(srcPhoto2, &src2);
1211         if (sw != src.width || sh != src.height) {
1212             Tk_PhotoSetSize(srcPhoto, sw, sh);
1213             Tk_PhotoGetImage(srcPhoto, &src);
1214         }
1215     }
1216
1217     domerge:
1218     destPhoto = Blt_FindPhoto(interp, destName);
1219     if (destPhoto == NULL) {
1220         if (leaveMsg)
1221             Tcl_AppendResult(interp, "destination image \"", destName, "\" doesn't",
1222             " exist or is not a photo image", (char *)NULL);
1223         return TCL_ERROR;
1224     }
1225     Tk_PhotoGetImage(destPhoto, &dest);
1226
1227     if ((dest.width != src.width) || (dest.height != src.height)) {
1228         Tk_PhotoSetSize(destPhoto, src.width, src.height);
1229     }
1230     srcImage = Blt_PhotoToColorImage(srcPhoto);
1231     srcImage2 = Blt_PhotoToColorImage(srcPhoto2);
1232     destImage = Blt_PhotoToColorImage(destPhoto);
1233
1234     Tk_PhotoGetImage(destPhoto, &dest);
1235     if ((dest.width != src.width) || (dest.height != src.height)) {
1236         Tk_PhotoSetSize(destPhoto, src.width, src.height);
1237         destImage = Blt_PhotoToColorImage(destPhoto);
1238     }
1239     if (isWc != 1) {
1240         result = Blt_MergeColorImage(srcImage, srcImage2, destImage, opacity, opacity2,
1241             isWc ? &withColor : NULL);
1242     } else {
1243         int xs1, xs2, xd1, xd2, xsc, xdc;
1244         int ys1, ys2, yd1, yd2, ysc, ydc;
1245         Pix32 *srcPtr, *src2Ptr, *destPtr;
1246
1247         srcPtr = Blt_ColorImageBits(srcImage);
1248         src2Ptr = Blt_ColorImageBits(srcImage2);
1249         destPtr = Blt_ColorImageBits(destImage);
1250
1251         xsc = (src2.width/2);
1252         ysc = (src2.height/2);
1253         xdc = (dest.width/2);
1254         ydc = (dest.height/2);
1255         for (xs1 = xsc-1, xs2=xsc, xd1 = xdc-1, xd2=xd1+1;
1256         xd1>=0; xd1--, xs1--, xd2++, xs2++) {
1257             if (xs1<0) { xs1 = xsc-1; xs2 = xs1+1; }
1258             for (ys1 = ysc-1, ys2 = ysc, yd1 = ydc-1, yd2=yd1+1;
1259             yd1>=0; yd1--, ys1--, yd2++, ys2++) {
1260                 if (ys1<0) { ys1 = ysc-1; ys2 = ys1+1; }
1261                 
1262 #define DDDC_O(ind,ind2) if ( withColor.value == srcPtr[ind].value) destPtr[ind].value =  src2Ptr[ind2].value
1263 #define DDDC(ind,ind2) PixMerged(srcPtr+(ind), src2Ptr+(ind2), destPtr+(ind), &withColor)
1264
1265                 DDDC(yd1*dest.width+xd1, ys1*src2.width+xs1);
1266                 if (ys2>=src2.height) { ys2--; }
1267                 if (xs2>=src2.width) { xs2--; }
1268                 if (yd2<dest.height && xd2<dest.width) {
1269                     DDDC(yd2*dest.width+xd2, ys2*src2.width+xs2);
1270                 }
1271                 if (xd2<dest.width) {
1272                     DDDC(yd1*dest.width+xd2, ys1*src2.width+xs2);
1273                 }
1274                 if (yd2<dest.height) {
1275                     DDDC(yd2*dest.width+xd1, ys2*src2.width+xs1);
1276                 }
1277             }
1278         }
1279         result = TCL_OK;
1280
1281     }
1282     if (result == TCL_OK) {
1283         Blt_ColorImageToPhoto(destImage, destPhoto);
1284     }
1285     Blt_FreeColorImage(srcImage);
1286     Blt_FreeColorImage(srcImage2);
1287     Blt_FreeColorImage(destImage);
1288     return result;
1289 }
1290
1291
1292 /*ARGSUSED*/
1293 static int
1294 MergeOp(clientData, interp, argc, argv)
1295     ClientData clientData;      /* Not used. */
1296     Tcl_Interp *interp;
1297     int argc;                   /* Not used. */
1298     char **argv;
1299 {
1300     Tk_PhotoHandle srcPhoto, srcPhoto2, destPhoto;
1301     Tk_PhotoImageBlock src, src2, dest;
1302     Blt_ColorImage srcImage, srcImage2, destImage;
1303     double opacity;
1304     double opacity2;
1305     int result, isWc;
1306     Pix32 withColor;
1307
1308     isWc = 0;
1309     opacity = 0.5;
1310     opacity2 = -1;
1311     srcPhoto = Blt_FindPhoto(interp, argv[2]);
1312     if (srcPhoto == NULL) {
1313         Tcl_AppendResult(interp, "source image \"", argv[2], "\" doesn't",
1314             " exist or is not a photo image", (char *)NULL);
1315         return TCL_ERROR;
1316     }
1317     Tk_PhotoGetImage(srcPhoto, &src);
1318     if ((src.width <= 1) || (src.height <= 1)) {
1319         Tcl_AppendResult(interp, "source image \"", argv[2], "\" is empty",
1320             (char *)NULL);
1321         return TCL_ERROR;
1322     }
1323
1324     srcPhoto2 = Blt_FindPhoto(interp, argv[3]);
1325     if (srcPhoto2 == NULL) {
1326         Tcl_AppendResult(interp, "source image \"", argv[3], "\" doesn't",
1327             " exist or is not a photo image", (char *)NULL);
1328         return TCL_ERROR;
1329     }
1330     Tk_PhotoGetImage(srcPhoto2, &src2);
1331     if ((src2.width <= 1) || (src2.height <= 1)) {
1332         Tcl_AppendResult(interp, "source image \"", argv[3], "\" is empty",
1333             (char *)NULL);
1334         return TCL_ERROR;
1335     }
1336     if (argc>5) {
1337         
1338         if (isdigit(argv[5][0]) == 0 && argv[5][0] != '.') {
1339             Tk_Window tkwin;
1340             char *colStr;
1341             
1342             tkwin = Tk_MainWindow(interp);
1343             isWc = 1;
1344             
1345             colStr = argv[5];
1346             if (colStr[0] == '!') {
1347                 colStr++;
1348                 isWc = 2;
1349             }
1350
1351             if (GetColorPix32(interp, tkwin, colStr, &withColor) != TCL_OK) {
1352                 return TCL_ERROR;
1353             }
1354             if (src.width < 4 || src.height < 4) {
1355                 Tcl_AppendResult(interp, "src image too small ",  0);
1356                 return TCL_ERROR;
1357             }
1358             if (src2.width < 4 || src2.height < 4) {
1359                 Tcl_AppendResult(interp, "src2 image too small ",  0);
1360                 return TCL_ERROR;
1361             }
1362             goto domerge;
1363         }
1364         
1365         if (Tcl_GetDouble(interp, argv[5], &opacity) != TCL_OK) {
1366             return TCL_ERROR;
1367         }
1368         if (opacity < 0.0 || opacity > 1.0) {
1369             Tcl_AppendResult(interp, "opacity must be >= 0.0 and <= 1.0: ", argv[5], (char *)NULL);
1370             return TCL_ERROR;
1371         }
1372     }
1373     if (argc>6) {
1374         if (Tcl_GetDouble(interp, argv[6], &opacity2) != TCL_OK) {
1375             return TCL_ERROR;
1376         }
1377         if (opacity2 < 0.0 || opacity2 > 1.0) {
1378             Tcl_AppendResult(interp, "opacity must be >= 0.0 and <= 1.0: ", argv[6], (char *)NULL);
1379             return TCL_ERROR;
1380         }
1381     }
1382
1383     if (isWc == 0 && ((src2.width != src.width) || (src2.height != src.height))) {
1384         int sh, sw;
1385         sw = (src2.width>src.width?src2.width:src.width);
1386         sh = (src2.height>src.height?src2.height:src.height);
1387         Tk_PhotoSetSize(srcPhoto2, sw, sh);
1388         Tk_PhotoGetImage(srcPhoto2, &src2);
1389         if (sw != src.width || sh != src.height) {
1390             Tk_PhotoSetSize(srcPhoto, sw, sh);
1391             Tk_PhotoGetImage(srcPhoto, &src);
1392         }
1393     }
1394
1395 domerge:
1396     destPhoto = Blt_FindPhoto(interp, argv[4]);
1397     if (destPhoto == NULL) {
1398         Tcl_AppendResult(interp, "destination image \"", argv[4], "\" doesn't",
1399             " exist or is not a photo image", (char *)NULL);
1400         return TCL_ERROR;
1401     }
1402     Tk_PhotoGetImage(destPhoto, &dest);
1403
1404     srcImage = Blt_PhotoToColorImage(srcPhoto);
1405     srcImage2 = Blt_PhotoToColorImage(srcPhoto2);
1406     destImage = Blt_PhotoToColorImage(destPhoto);
1407
1408     Tk_PhotoGetImage(destPhoto, &dest);
1409     if ((dest.width != src.width) || (dest.height != src.height)) {
1410         Tk_PhotoSetSize(destPhoto, src.width, src.height);
1411         destImage = Blt_PhotoToColorImage(destPhoto);
1412     }
1413     if (isWc != 1) {
1414         result = Blt_MergeColorImage(srcImage, srcImage2, destImage, opacity, opacity2,
1415             isWc ? &withColor : NULL);
1416     } else {
1417         int xs1, xs2, xd1, xd2, xsc, xdc;
1418         int ys1, ys2, yd1, yd2, ysc, ydc;
1419         Pix32 *srcPtr, *src2Ptr, *destPtr;
1420
1421         srcPtr = Blt_ColorImageBits(srcImage);
1422         src2Ptr = Blt_ColorImageBits(srcImage2);
1423         destPtr = Blt_ColorImageBits(destImage);
1424
1425         xsc = (src2.width/2);
1426         ysc = (src2.height/2);
1427         xdc = (dest.width/2);
1428         ydc = (dest.height/2);
1429         for (xs1 = xsc-1, xs2=xs1+1, xd1 = xdc-1, xd2=xdc;
1430         xd1>=0; xd1--, xs1--, xd2++, xs2++) {
1431             if (xs1<0) { xs1 = xsc-1; xs2 = xs1+1; }
1432             for (ys1 = ysc-1, ys2 = ys1+1, yd1 = ydc-1, yd2=yd1+1;
1433             yd1>=0; yd1--, ys1--, yd2++, ys2++) {
1434                 if (ys1<0) { ys1 = ysc-1; ys2 = ys1+1; }
1435                 
1436 #define DDC(ind,ind2) destPtr[ind].value = ( withColor.value == srcPtr[ind].value ? src2Ptr[ind2].value : srcPtr[ind].value)
1437
1438                 DDC(yd1*dest.width+xd1, ys1*src2.width+xs1);
1439                 //destPtr[yd1*dest.width+xd1].value = srcPtr[ys1*src2.width+xs1].value;
1440                 if (ys2>=src2.height) { ys2--; }
1441                 if (xs2>=src2.width) { xs2--; }
1442                 if (yd2<dest.height && xd2<dest.width)
1443                 DDC(yd2*dest.width+xd2, ys2*src2.width+xs2);
1444                 // destPtr[yd2*dest.width+xd2].value = srcPtr[ys2*src2.width+xs2].value;
1445                 if (xd2<dest.width)
1446                 DDC(yd1*dest.width+xd2, ys1*src2.width+xs2);
1447                 //destPtr[yd1*dest.width+xd2].value = srcPtr[ys1*src2.width+xs2].value;
1448                 if (yd2<dest.height)
1449                 DDC(yd2*dest.width+xd1, ys2*src2.width+xs1);
1450                 //destPtr[yd2*dest.width+xd1].value = srcPtr[ys2*src2.width+xs1].value;
1451                 //if (ya<src.height && ya2<dest.height && xa<src.width && xa2<dest.width) {}
1452             }
1453         }
1454         result = TCL_OK;
1455
1456     }
1457     if (result == TCL_OK) {
1458         Blt_ColorImageToPhoto(destImage, destPhoto);
1459     }
1460     Blt_FreeColorImage(srcImage);
1461     Blt_FreeColorImage(srcImage2);
1462     Blt_FreeColorImage(destImage);
1463     return result;
1464 }
1465
1466
1467 /*ARGSUSED*/
1468 static int
1469 ReadJPEGOp(clientData, interp, argc, argv)
1470     ClientData clientData;      /* Not used. */
1471     Tcl_Interp *interp;
1472     int argc;                   /* Not used. */
1473     char **argv;
1474 {
1475 #if HAVE_JPEGLIB_H
1476     int result;
1477     Tcl_DString dString;
1478     char *fileName;
1479     Tk_PhotoHandle photo;       /* The photo image to write into. */
1480
1481     photo = Blt_FindPhoto(interp, argv[3]);
1482     if (photo == NULL) {
1483         Tcl_AppendResult(interp, "image \"", argv[3], "\" doesn't",
1484             " exist or is not a photo image", (char *)NULL);
1485         return TCL_ERROR;
1486     }
1487     Tcl_DStringInit(&dString);
1488     fileName = Tcl_TranslateFileName(interp, argv[2], &dString);
1489     
1490     result = Blt_JPEGToPhoto(interp, fileName, photo);
1491     Tcl_DStringInit(&dString);
1492     return result;
1493 #else
1494     Tcl_AppendResult(interp, "JPEG support not compiled", (char *)NULL);
1495     return TCL_ERROR;
1496 #endif
1497 }
1498
1499 static double Drand( double val) {
1500 #ifdef HAVE_DRAND48
1501     return drand48();
1502 #else
1503     return (double)random()/RAND_MAX;
1504 #endif
1505 }
1506
1507 #define SLANTX(x,y) (doslant==0 || slant == 0.0?x:(((int)(x + (y * slant)))%src.width))
1508 #define ARCX(x,y) (doarc==0 || sineVal == 0.0?x:(((int)(x + (src.width*sqrt(0.5*0.5-((double)y/src.height-0.5)*((double)y/src.height-0.5)) * sineVal)))%src.width))
1509 #define SINEX(x,y) (dosine==0 || sineVal == 0.0?x:(((int)(x + (src.width*(*tfunc)(M_PI *y/src.height) * sineVal)))%src.width))
1510 #ifdef HAVE_DRAND48
1511 #define RANDX(c) (dorand==0 || randVal == 0.0?c:(c+(Drand(0) * randVal - (randVal/2.0))))
1512 #else
1513 #define RANDX(c) c
1514 #endif
1515 #define SKEWX(c) ((doskew==0 || skew == 1.0)?c:(ox>=skew?1.0:c/skew))
1516 #define CLAMP(c)        ((((c) < 0.0) ? 0.0 : ((c) > 1.0) ? 1.0 : (c)))
1517
1518 static int
1519 GradientsOp(clientData, interp, argc, argv)
1520     ClientData clientData;      /* Not used. */
1521     Tcl_Interp *interp;
1522     int argc;                   /* Not used. */
1523     char **argv;
1524 {
1525     double range[3];
1526     double left[3];
1527     int x, y, width;
1528     double t;
1529     XColor C;
1530     XColor *leftPtr, *rightPtr;
1531     Tk_Window tkwin;
1532     
1533     tkwin = Tk_MainWindow(interp);
1534
1535     leftPtr = Tk_GetColor(interp, tkwin, Tk_GetUid(argv[2]));
1536     if (leftPtr == NULL) {
1537         return TCL_ERROR;
1538     }
1539     rightPtr = Tk_GetColor(interp, tkwin, Tk_GetUid(argv[3]));
1540     if (rightPtr == NULL) {
1541         return TCL_ERROR;
1542     }
1543     if (Tcl_GetInt(interp, argv[4], &width) != TCL_OK) {
1544         return TCL_ERROR;
1545     }
1546     if (width<=2) {
1547         Tcl_AppendResult(interp, "width must be > 2", 0);
1548         return TCL_ERROR;
1549     }
1550     left[0] = (double)(leftPtr->red >> 8);
1551     left[1] = (double)(leftPtr->green >> 8);
1552     left[2] = (double)(leftPtr->blue >> 8);
1553     range[0] = (double)((rightPtr->red - leftPtr->red) / 257.0);
1554     range[1] = (double)((rightPtr->green - leftPtr->green) / 257.0);
1555     range[2] = (double)((rightPtr->blue - leftPtr->blue) / 257.0);
1556
1557     y =0;
1558     for (x = 0; x < width; x++) {
1559         char cbuf[100];
1560         t = ((double)( sin(M_PI_2 * (double)x / (double)width)));
1561         t = CLAMP(t);
1562         C.red = (unsigned short)(left[0] + t * range[0]);
1563         C.green = (unsigned short)(left[1] + t * range[1]);
1564         C.blue = (unsigned short)(left[2] + t * range[2]);
1565         sprintf(cbuf, "#%02x%02x%02x", C.red, C.green, C.blue);
1566         if (x) { Tcl_AppendResult(interp, " ", 0); }
1567         Tcl_AppendResult(interp, cbuf, 0);
1568     }
1569     return TCL_OK;
1570 }
1571
1572 int
1573 Blt_GetGradient(Tcl_Interp *interp, Tk_Window tkwin, Gradient *gradPtr) {
1574     XColor *leftPtr, *rightPtr;
1575     double range[3];
1576     double left[3];
1577     int x, y, width;
1578     double t;
1579     XColor **destPtr, C;
1580
1581     leftPtr = gradPtr->color;
1582     rightPtr = gradPtr->color2;
1583     left[0] = (double)(leftPtr->red >> 8);
1584     left[1] = (double)(leftPtr->green >> 8);
1585     left[2] = (double)(leftPtr->blue >> 8);
1586     range[0] = (double)((rightPtr->red - leftPtr->red) / 257.0);
1587     range[1] = (double)((rightPtr->green - leftPtr->green) / 257.0);
1588     range[2] = (double)((rightPtr->blue - leftPtr->blue) / 257.0);
1589
1590     y =0;
1591     width = gradPtr->width;
1592     if (gradPtr->grads) {
1593         Blt_FreeGradient(gradPtr);
1594     }
1595     destPtr = gradPtr->grads = (XColor**)Blt_Calloc(width+1, sizeof(XColor*));
1596     for (x = 0; x < width; x++) {
1597         char cbuf[100];
1598         t = ((double)( sin(M_PI_2 * (double)x / (double)width)));
1599         t = CLAMP(t);
1600         C.red = (unsigned short)(left[0] + t * range[0]);
1601         C.green = (unsigned short)(left[1] + t * range[1]);
1602         C.blue = (unsigned short)(left[2] + t * range[2]);
1603         /**destPtr = Tk_GetColorByValue(tkwin, &C); */
1604         sprintf(cbuf, "#%02x%02x%02x", C.red, C.green, C.blue);
1605         *destPtr = Tk_GetColor(interp, tkwin, Tk_GetUid(cbuf));
1606         if (*destPtr == NULL) break;
1607         destPtr++;
1608     }
1609     gradPtr->origColor = gradPtr->color;
1610     gradPtr->origColor2 = gradPtr->color2;
1611     gradPtr->origWidth = gradPtr->width;
1612     return TCL_OK;
1613 }
1614
1615 int
1616 Blt_FreeGradient(Gradient *gradPtr) {
1617     XColor **destPtr;
1618     if (gradPtr->grads) {
1619         destPtr = gradPtr->grads;
1620         while (*destPtr) {
1621             Tk_FreeColor(*destPtr);
1622             destPtr++;
1623         }
1624         Blt_Free( gradPtr->grads);
1625     }
1626     gradPtr->grads = NULL;
1627     return TCL_OK;
1628
1629 }
1630
1631 /*ARGSUSED*/
1632 static int
1633 GradientOp(clientData, interp, argc, argv)
1634     ClientData clientData;      /* Not used. */
1635     Tcl_Interp *interp;
1636     int argc;                   /* Not used. */
1637     char **argv;
1638 {
1639     Tk_PhotoHandle photo;
1640     Tk_PhotoImageBlock src;
1641     XColor *leftPtr, *rightPtr;
1642     Tk_Window tkwin;
1643     double range[3];
1644     double left[3];
1645     Pix32 *destPtr;
1646     Blt_ColorImage destImage;
1647     double skew, randVal, slant, sineVal;
1648     int dorand, doslant, doskew, doarc, dosine, gtype, result, ox;
1649     int nWidth = 0, nHeight = 0;
1650     Tcl_Obj *objPtr;
1651     static char *types[] = { "linear", "radial", "sine", "halfsine", "rectangular",  "split", "blank", 0 };
1652     enum ITypeIdx {
1653         ILinearIdx, IRadialIdx, ISineIdx, IHalfSineIdx, IRectIdx, ISplitIdx,
1654         IBlankIdx
1655     };
1656     double (*tfunc)(double);
1657     int alpha;
1658     unsigned char aVal;
1659
1660     aVal = 255;
1661     tfunc = &sin;
1662     dorand = 0;
1663     doskew = 0;
1664     doslant = 0;
1665     dosine = 0;
1666     doarc = 0;
1667     skew = 1.0;
1668     gtype = ISineIdx;
1669     tkwin = Tk_MainWindow(interp);
1670     photo = Blt_FindPhoto(interp, argv[2]);
1671     if (photo == NULL) {
1672         Tcl_AppendResult(interp, "source image \"", argv[2], "\" doesn't",
1673             " exist or is not a photo image", (char *)NULL);
1674         return TCL_ERROR;
1675     }
1676     Tk_PhotoGetImage(photo, &src);
1677     leftPtr = Tk_GetColor(interp, tkwin, Tk_GetUid(argv[3]));
1678     if (leftPtr == NULL) {
1679         return TCL_ERROR;
1680     }
1681     rightPtr = Tk_GetColor(interp, tkwin, Tk_GetUid(argv[4]));
1682     if (rightPtr == NULL) {
1683         return TCL_ERROR;
1684     }
1685     while (argc > 5) {
1686         if (argc < 7) {
1687             Tcl_AppendResult(interp, "expected argument", argv[5], (char *)NULL);
1688             return TCL_ERROR;
1689         }
1690         if (!strcmp("-alpha", argv[5])) {
1691             if (Tcl_GetInt(interp, argv[6], &alpha) != TCL_OK) {
1692                 return TCL_ERROR;
1693             }
1694             if (alpha<=0 || alpha > 255) {
1695                 Tcl_AppendResult(interp, "alpha must be > 0 and <= 255", argv[6],
1696                     (char *)NULL);
1697                     return TCL_ERROR;
1698             }
1699             aVal = (unsigned char) alpha;
1700
1701         } else if (!strcmp("-type", argv[5])) {
1702             objPtr = Tcl_NewStringObj(argv[6],-1);
1703             Tcl_IncrRefCount(objPtr);
1704             result = Tcl_GetIndexFromObj(interp, objPtr, types, "type", 0,
1705                 &gtype);
1706             Tcl_DecrRefCount(objPtr);
1707             if (result != TCL_OK) {
1708                 return TCL_ERROR;
1709             }
1710                 
1711         } else if (!strcmp("-skew", argv[5])) {
1712             doskew = 1;
1713             if (Tcl_GetDouble(interp, argv[6], &skew) != TCL_OK) {
1714                 return TCL_ERROR;
1715             }
1716             if (skew<0.0 || skew>1.0) {
1717                 Tcl_AppendResult(interp, "skew must be >=0 && <=1.0: ", argv[6],
1718                     (char *)NULL);
1719                     return TCL_ERROR;
1720             }
1721         } else if (!strcmp("-width", argv[5])) {
1722             if (Tk_GetPixels(interp, tkwin, argv[6], &nWidth) != TCL_OK) {
1723                 return TCL_ERROR;
1724             }
1725             if (nWidth<1 || nWidth>5000) {
1726                 Tcl_AppendResult(interp, "width must be >=1 && <=5000: ", argv[6],
1727                     (char *)NULL);
1728                     return TCL_ERROR;
1729             }
1730         } else if (!strcmp("-height", argv[5])) {
1731             if (Tk_GetPixels(interp, tkwin, argv[6], &nHeight) != TCL_OK) {
1732                 return TCL_ERROR;
1733             }
1734             if (nHeight<1 || nHeight>5000) {
1735                 Tcl_AppendResult(interp, "width must be >=1 && <=5000: ", argv[6],
1736                     (char *)NULL);
1737                     return TCL_ERROR;
1738             }
1739         } else if (!strcmp("-rand", argv[5])) {
1740             dorand = 1;
1741             if (Tcl_GetDouble(interp, argv[6], &randVal) != TCL_OK) {
1742                 return TCL_ERROR;
1743             }
1744             if (randVal<0.0 || randVal>0.1) {
1745                 Tcl_AppendResult(interp, "randVal must be >= 0.0 && <= 0.1: ", argv[6],
1746                     (char *)NULL);
1747                     return TCL_ERROR;
1748             }
1749         } else if (!strcmp("-slant", argv[5])) {
1750             doslant = 1;
1751             if (Tcl_GetDouble(interp, argv[6], &slant) != TCL_OK) {
1752                 return TCL_ERROR;
1753             }
1754             if (slant<-1000.0 || slant>1000.0) {
1755                 Tcl_AppendResult(interp, "slant must be >= -1000.0 && <= 1000.0: ", argv[6],
1756                     (char *)NULL);
1757                     return TCL_ERROR;
1758             }
1759         } else if (!strcmp("-mathval", argv[5])) {
1760             dosine = 1;
1761             if (Tcl_GetDouble(interp, argv[6], &sineVal) != TCL_OK) {
1762                 return TCL_ERROR;
1763             }
1764             if (sineVal<-1000.0 || sineVal>1000.0) {
1765                 Tcl_AppendResult(interp, "mathval must be >= -1000.0 && <= 1000.0: ", argv[6],
1766                     (char *)NULL);
1767                     return TCL_ERROR;
1768             }
1769         } else if (!strcmp("-mathfunc", argv[5])) {
1770             if (!strcmp("circle", argv[6])) {
1771                 dosine = 0;
1772                 doarc = 1;
1773             } else if (!strcmp("sin", argv[6])) {
1774                 tfunc = &sin;
1775             } else if (!strcmp("cos", argv[6])) {
1776                 tfunc = &cos;
1777             } else if (!strcmp("atan", argv[6])) {
1778                 tfunc = &atan;
1779             } else if (!strcmp("acos", argv[6])) {
1780                 tfunc = &acos;
1781             } else if (!strcmp("asin", argv[6])) {
1782                 tfunc = &asin;
1783             } else if (!strcmp("rand", argv[6])) {
1784                 tfunc = &Drand;
1785             } else if (!strcmp("cosh", argv[6])) {
1786                 tfunc = &cosh;
1787             } else if (!strcmp("sinh", argv[6])) {
1788                 tfunc = &sinh;
1789             } else if (!strcmp("tan", argv[6])) {
1790                 tfunc = &tan;
1791             } else if (!strcmp("tanh", argv[6])) {
1792                 tfunc = &tanh;
1793             } else if (!strcmp("log", argv[6])) {
1794                 tfunc = &log;
1795             } else if (!strcmp("log10", argv[6])) {
1796                 tfunc = &log10;
1797             } else if (!strcmp("exp", argv[6])) {
1798                 tfunc = &exp;
1799             } else if (!strcmp("sqrt", argv[6])) {
1800                 tfunc = &sqrt;
1801             } else {
1802                 Tcl_AppendResult(interp, "mathfunc ", argv[6], " not one of: ",
1803                     "sin cos tan sinh cosh tanh asin acos atan log log10 exp sqrt rand circle", (char *)NULL);
1804                 return TCL_ERROR;
1805             }
1806         } else {
1807             Tcl_AppendResult(interp, "argument \"", argv[5], "\" not one of: -type -skew -rand -slant -curve -circle",
1808                 (char *)NULL);
1809                 return TCL_ERROR;
1810         }
1811         argc -= 2;
1812         argv += 2;
1813     }
1814     if ((nWidth>0 || nHeight>0) && ((nWidth != src.width) || (nHeight != src.height))) {
1815         if (nWidth<=0) { nWidth = src.width; }
1816         if (nHeight<=0) { nHeight = src.height; }
1817         Tk_PhotoSetSize(photo, nWidth, nHeight);
1818         Tk_PhotoGetImage(photo, &src);
1819     }
1820     left[0] = (double)(leftPtr->red >> 8);
1821     left[1] = (double)(leftPtr->green >> 8);
1822     left[2] = (double)(leftPtr->blue >> 8);
1823     range[0] = (double)((rightPtr->red - leftPtr->red) / 257.0);
1824     range[1] = (double)((rightPtr->green - leftPtr->green) / 257.0);
1825     range[2] = (double)((rightPtr->blue - leftPtr->blue) / 257.0);
1826
1827     destImage = Blt_CreateColorImage(src.width, src.height);
1828     destPtr = Blt_ColorImageBits(destImage);
1829     
1830     if (gtype == ILinearIdx) {
1831         register int x, y, sx;
1832         double t;
1833
1834         for (y = 0; y < src.height; y++) {
1835             for (x = 0; x < src.width; x++) {
1836                 ox = (double)x / src.width;
1837                 sx = SLANTX(x,y);
1838                 sx = ARCX(sx,y);
1839                 sx = SINEX(sx,y);
1840                 t = (double)sx / src.width;
1841                 t = SKEWX(t);
1842                 t = RANDX(t);
1843                 t = CLAMP(t);
1844                 destPtr->Red = (unsigned char)(left[0] + t * range[0]);
1845                 destPtr->Green = (unsigned char)(left[1] + t * range[1]);
1846                 destPtr->Blue = (unsigned char)(left[2] + t * range[2]);
1847                 destPtr->Alpha = aVal;
1848                 destPtr++;
1849             }
1850         }
1851      } else if (gtype == ISineIdx) {
1852         register int x, y, sx;
1853         double t;
1854
1855         for (y = 0; y < src.height; y++) {
1856             for (x = 0; x < src.width; x++) {
1857                 ox = (double)x / src.width;
1858                 sx = SLANTX(x,y);
1859                 sx = ARCX(sx,y);
1860                 sx = SINEX(sx,y);
1861                 t = ((double)(sin(2*M_PI_2 * (double)sx / (double)src.width)));
1862                 t = SKEWX(t);
1863                 t = RANDX(t);
1864                 t = CLAMP(t);
1865                 destPtr->Red = (unsigned char)(left[0] + t * range[0]);
1866                 destPtr->Green = (unsigned char)(left[1] + t * range[1]);
1867                 destPtr->Blue = (unsigned char)(left[2] + t * range[2]);
1868                 destPtr->Alpha = aVal;
1869                 destPtr++;
1870             }
1871         }
1872     } else if (gtype == IHalfSineIdx) {
1873         register int x, y, sx;
1874         double t;
1875
1876         for (y = 0; y < src.height; y++) {
1877             for (x = 0; x < src.width; x++) {
1878                 ox = (double)x / src.width;
1879                 sx = SLANTX(x,y);
1880                 sx = ARCX(sx,y);
1881                 sx = SINEX(sx,y);
1882                 t = ((double)( sin(M_PI_2 * (double)sx / (double)src.width)));
1883                 t = SKEWX(t);
1884                 t = RANDX(t);
1885                 t = CLAMP(t);
1886                 destPtr->Red = (unsigned char)(left[0] + t * range[0]);
1887                 destPtr->Green = (unsigned char)(left[1] + t * range[1]);
1888                 destPtr->Blue = (unsigned char)(left[2] + t * range[2]);
1889                 destPtr->Alpha = aVal;
1890                 destPtr++;
1891             }
1892         }
1893     } else if (gtype == IRadialIdx) {
1894         register int x, y, sx;
1895         register double dx, dy;
1896         double dy2;
1897         double t;
1898         double midX, midY;
1899
1900         midX = midY = 0.5;
1901         for (y = 0; y < src.height; y++) {
1902             dy = (y / (double)src.height) - midY;
1903             dy2 = dy * dy;
1904             for (x = 0; x < src.width; x++) {
1905                 ox = (double)x / src.width;
1906                 sx = SLANTX(x,y);
1907                 sx = ARCX(sx,y);
1908                 sx = SINEX(sx,y);
1909                 dx = (sx / (double)src.width) - midX;
1910                 t = 1.0  - (double)sqrt(dx * dx + dy2);
1911                 t = SKEWX(t);
1912                 t = RANDX(t);
1913                 t = CLAMP(t);
1914                 destPtr->Red = (unsigned char)(left[0] + t * range[0]);
1915                 destPtr->Green = (unsigned char)(left[1] + t * range[1]);
1916                 destPtr->Blue = (unsigned char)(left[2] + t * range[2]);
1917                 destPtr->Alpha = aVal;
1918                 destPtr++;
1919             }
1920         }
1921   
1922     } else if (gtype == IRectIdx) {
1923         register int x, y, sx;
1924         register double dx, dy;
1925         double t, px, py;
1926         double midX, midY;
1927         double cosTheta, sinTheta;
1928         double angle;
1929
1930         angle = M_PI_2 * -0.3;
1931         cosTheta = cos(angle);
1932         sinTheta = sin(angle);
1933
1934         midX = 0.5, midY = 0.5;
1935         for (y = 0; y < src.height; y++) {
1936             dy = (y / (double)src.height) - midY;
1937             for (x = 0; x < src.width; x++) {
1938                 ox = (double)x / src.width;
1939                 sx = SLANTX(x,y);
1940                 sx = ARCX(sx,y);
1941                 sx = SINEX(sx,y);
1942                 dx = (sx / (double)src.width) - midX;
1943                 px = dx * cosTheta - dy * sinTheta;
1944                 py = dx * sinTheta + dy * cosTheta;
1945                 t = FABS(px) + FABS(py);
1946                 t = SKEWX(t);
1947                 t = RANDX(t);
1948                 t = CLAMP(t);
1949                 destPtr->Red = (unsigned char)(left[0] + t * range[0]);
1950                 destPtr->Green = (unsigned char)(left[1] + t * range[1]);
1951                 destPtr->Blue = (unsigned char)(left[2] + t * range[2]);
1952                 destPtr->Alpha = aVal;
1953                 destPtr++;
1954             }
1955         }
1956     } else if (gtype == ISplitIdx) {
1957         register int x, y, sx, midx;
1958         double t;
1959
1960         midx = src.width/2;
1961         for (y = 0; y < src.height; y++) {
1962             for (x = 0; x < src.width; x++) {
1963                 ox = (double)x / src.width;
1964                 sx = SLANTX(x,y);
1965                 sx = ARCX(sx,y);
1966                 sx = SINEX(sx,y);
1967                 if (x<midx) {
1968                     sx += (0.1 * src.width);
1969                 } else {
1970                     sx -= (0.1 * src.width);
1971                 }
1972                 t = (double)sx / src.width;
1973                 t = SKEWX(t);
1974                 t = RANDX(t);
1975                 t = CLAMP(t);
1976                 destPtr->Red = (unsigned char)(left[0] + t * range[0]);
1977                 destPtr->Green = (unsigned char)(left[1] + t * range[1]);
1978                 destPtr->Blue = (unsigned char)(left[2] + t * range[2]);
1979                 destPtr->Alpha = aVal;
1980                 destPtr++;
1981             }
1982         }
1983     } else if (gtype == IBlankIdx) {
1984         register int x, y;
1985
1986         for (y = 0; y < src.height; y++) {
1987             for (x = 0; x < src.width; x++) {
1988                 destPtr->Red = (unsigned char)0xFF;
1989                 destPtr->Green = (unsigned char)0xFF;
1990                 destPtr->Blue = (unsigned char)0xFF;
1991                 destPtr->Alpha = aVal;
1992                 destPtr++;
1993             }
1994         }
1995     }
1996     Blt_ColorImageToPhoto(destImage, photo);
1997     Blt_FreeColorImage(destImage);
1998     return TCL_OK;
1999 }
2000
2001 /*ARGSUSED*/
2002 static int
2003 ResampleOp(clientData, interp, argc, argv)
2004     ClientData clientData;      /* Not used. */
2005     Tcl_Interp *interp;
2006     int argc;                   /* Not used. */
2007     char **argv;
2008 {
2009     Tk_PhotoHandle srcPhoto, destPhoto;
2010     Tk_PhotoImageBlock src, dest;
2011     ResampleFilter *filterPtr, *vertFilterPtr, *horzFilterPtr;
2012     char *filterName;
2013
2014     srcPhoto = Blt_FindPhoto(interp, argv[2]);
2015     if (srcPhoto == NULL) {
2016         Tcl_AppendResult(interp, "source image \"", argv[2], "\" doesn't",
2017             " exist or is not a photo image", (char *)NULL);
2018         return TCL_ERROR;
2019     }
2020     destPhoto = Blt_FindPhoto(interp, argv[3]);
2021     if (destPhoto == NULL) {
2022         Tcl_AppendResult(interp, "destination image \"", argv[3], "\" doesn't",
2023             " exist or is not a photo image", (char *)NULL);
2024         return TCL_ERROR;
2025     }
2026     filterName = (argc > 4) ? argv[4] : "none";
2027     if (Blt_GetResampleFilter(interp, filterName, &filterPtr) != TCL_OK) {
2028         return TCL_ERROR;
2029     }
2030     vertFilterPtr = horzFilterPtr = filterPtr;
2031     if ((filterPtr != NULL) && (argc > 5)) {
2032         if (Blt_GetResampleFilter(interp, argv[5], &filterPtr) != TCL_OK) {
2033             return TCL_ERROR;
2034         }
2035         vertFilterPtr = filterPtr;
2036     }
2037     Tk_PhotoGetImage(srcPhoto, &src);
2038     if ((src.width <= 1) || (src.height <= 1)) {
2039         Tcl_AppendResult(interp, "source image \"", argv[2], "\" is empty",
2040             (char *)NULL);
2041         return TCL_ERROR;
2042     }
2043     Tk_PhotoGetImage(destPhoto, &dest);
2044     if ((dest.width <= 1) || (dest.height <= 1)) {
2045         Tk_PhotoSetSize(destPhoto, src.width, src.height);
2046         goto copyImage;
2047     }
2048     if ((src.width == dest.width) && (src.height == dest.height)) {
2049       copyImage:
2050         /* Source and destination image sizes are the same. Don't
2051          * resample. Simply make copy of image */
2052         dest.width = src.width;
2053         dest.height = src.height;
2054         dest.pixelPtr = src.pixelPtr;
2055         dest.pixelSize = src.pixelSize;
2056         dest.pitch = src.pitch;
2057         dest.offset[0] = src.offset[0];
2058         dest.offset[1] = src.offset[1];
2059         dest.offset[2] = src.offset[2];
2060         Tk_PhotoPutBlock(destPhoto, &dest, 0, 0, dest.width, dest.height);
2061         return TCL_OK;
2062     }
2063     if (filterPtr == NULL) {
2064         Blt_ResizePhoto(srcPhoto, 0, 0, src.width, src.height, destPhoto);
2065     } else {
2066         Blt_ResamplePhoto(srcPhoto, 0, 0, src.width, src.height, destPhoto,
2067                 horzFilterPtr, vertFilterPtr);
2068     }
2069     return TCL_OK;
2070 }
2071
2072 /*ARGSUSED*/
2073 static int
2074 BlurOp(clientData, interp, argc, argv)
2075     ClientData clientData;      /* Not used. */
2076     Tcl_Interp *interp;
2077     int argc;                   /* Not used. */
2078     char **argv;
2079 {
2080     Tk_PhotoHandle srcPhoto, destPhoto;
2081     Tk_PhotoImageBlock src, dest;
2082     double radius;
2083
2084     radius = 3;
2085     srcPhoto = Blt_FindPhoto(interp, argv[2]);
2086     if (srcPhoto == NULL) {
2087         Tcl_AppendResult(interp, "source image \"", argv[2], "\" doesn't",
2088             " exist or is not a photo image", (char *)NULL);
2089         return TCL_ERROR;
2090     }
2091     destPhoto = Blt_FindPhoto(interp, argv[3]);
2092     if (destPhoto == NULL) {
2093         Tcl_AppendResult(interp, "destination image \"", argv[3], "\" doesn't",
2094             " exist or is not a photo image", (char *)NULL);
2095         return TCL_ERROR;
2096     }
2097     if (argc > 4) {
2098         if (Tcl_GetDouble(interp, argv[4], &radius) != TCL_OK) {
2099             return TCL_ERROR;
2100         }
2101     }
2102     Tk_PhotoGetImage(srcPhoto, &src);
2103     if ((src.width <= 1) || (src.height <= 1)) {
2104         Tcl_AppendResult(interp, "source image \"", argv[2], "\" is empty",
2105             (char *)NULL);
2106         return TCL_ERROR;
2107     }
2108     Tk_PhotoGetImage(destPhoto, &dest);
2109     Tk_PhotoSetSize(destPhoto, src.width, src.height);
2110     return Blt_BlurColorImage(srcPhoto, destPhoto, (int)(radius + 0.5) );
2111 }
2112
2113 /*ARGSUSED*/
2114 static int
2115 RotateOp(clientData, interp, argc, argv)
2116     ClientData clientData;      /* Not used. */
2117     Tcl_Interp *interp;
2118     int argc;                   /* Not used. */
2119     char **argv;
2120 {
2121     Tk_PhotoHandle srcPhoto, destPhoto;
2122     Blt_ColorImage srcImage, destImage;
2123     double theta;
2124
2125     srcPhoto = Blt_FindPhoto(interp, argv[2]);
2126     if (srcPhoto == NULL) {
2127         Tcl_AppendResult(interp, "image \"", argv[2], "\" doesn't",
2128             " exist or is not a photo image", (char *)NULL);
2129         return TCL_ERROR;
2130     }
2131     destPhoto = Blt_FindPhoto(interp, argv[3]);
2132     if (destPhoto == NULL) {
2133         Tcl_AppendResult(interp, "destination image \"", argv[3], "\" doesn't",
2134             " exist or is not a photo image", (char *)NULL);
2135         return TCL_ERROR;
2136     }
2137     if (Tcl_ExprDouble(interp, argv[4], &theta) != TCL_OK) {
2138         return TCL_ERROR;
2139     }
2140     srcImage = Blt_PhotoToColorImage(srcPhoto);
2141     destImage = Blt_RotateColorImage(srcImage, theta);
2142
2143     Blt_ColorImageToPhoto(destImage, destPhoto);
2144     Blt_FreeColorImage(srcImage);
2145     Blt_FreeColorImage(destImage);
2146     return TCL_OK;
2147 }
2148
2149 /*ARGSUSED*/
2150 int
2151 Blt_ImageMirror(Tcl_Interp *interp, char *srcImg, char *dstImg, int flip, int flags) {
2152     Tk_PhotoHandle srcPhoto, destPhoto;
2153     Blt_ColorImage srcImage, destImage;
2154     int x, y, x1, x2, y2;
2155     Tk_PhotoImageBlock src, dest;
2156     Pix32 *destPtr, *srcPtr;
2157
2158     srcPhoto = Blt_FindPhoto(interp, srcImg);
2159     if (srcPhoto == NULL) {
2160         Tcl_AppendResult(interp, "image \"", srcImg, "\" doesn't",
2161             " exist or is not a photo image", (char *)NULL);
2162         return TCL_ERROR;
2163     }
2164     Tk_PhotoGetImage(srcPhoto, &src);
2165     destPhoto = Blt_FindPhoto(interp, dstImg);
2166     if (destPhoto == NULL) {
2167         Tcl_AppendResult(interp, "destination image \"", dstImg, "\" doesn't",
2168             " exist or is not a photo image", (char *)NULL);
2169         return TCL_ERROR;
2170     }
2171
2172
2173     if ((flip == MIRROR_TILE || flip == MIRROR_INNER || flip == MIRROR_OUTER ) && srcPhoto == destPhoto) {
2174         Tcl_AppendResult(interp, "image must be different", (char *)NULL);
2175         return TCL_ERROR;
2176     }
2177     Tk_PhotoGetImage(destPhoto, &dest);
2178     if (src.width <= 0 || src.height <= 0) {
2179         Tcl_AppendResult(interp, "src image empty ",  0);
2180         return TCL_ERROR;
2181     }
2182
2183     if (flip == MIRROR_TILE) {
2184         if ((dest.width != (src.width *2)) || (dest.height <= (src.height*2))) {
2185             Tk_PhotoSetSize(destPhoto, 2*src.width, 2*src.height);
2186             Tk_PhotoGetImage(destPhoto, &dest);
2187         }
2188     } else if (flip != MIRROR_OUTER && flip != MIRROR_INNER) {
2189         if ((dest.width != src.width) || (dest.height <= src.height)) {
2190             Tk_PhotoSetSize(destPhoto, src.width, src.height);
2191             Tk_PhotoGetImage(destPhoto, &dest);
2192         }
2193     }
2194
2195     srcImage = Blt_PhotoToColorImage(srcPhoto);
2196     destImage = Blt_PhotoToColorImage(destPhoto);
2197     destPtr = Blt_ColorImageBits(destImage);
2198     srcPtr = Blt_ColorImageBits(srcImage);
2199
2200     if (flip == MIRROR_INNER) {
2201         /* Center  */
2202         int xs1, xs2, xd1, xd2, xsc, xdc;
2203         int ys1, ys2, yd1, yd2, ysc, ydc;
2204         
2205         if (src.width < 4 || src.height < 4) {
2206             Tcl_AppendResult(interp, "src image too small ",  0);
2207             return TCL_ERROR;
2208         }
2209         if (dest.width < 4 || dest.height < 4) {
2210             Tcl_AppendResult(interp, "dest image too small ",  0);
2211             return TCL_ERROR;
2212         }
2213         xsc = (src.width/2);
2214         ysc = (src.height/2);
2215         xdc = (dest.width/2);
2216         ydc = (dest.height/2);
2217         for (xs1 = xsc-1, xs2=xs1+1, xd1 = xdc-1, xd2=xd1+1;
2218              xd1>=0; xd1--, xs1--, xd2++, xs2++) {
2219             if (xs1<0) { xs1 = xsc-1; xs2 = xs1+1; }
2220             for (ys1 = ysc-1, ys2 = ys1+1, yd1 = ydc-1, yd2=yd1+1;
2221                  yd1>=0; yd1--, ys1--, yd2++, ys2++) {
2222                 if (ys1<0) { ys1 = ysc-1; ys2 = ys1+1; }
2223                 destPtr[yd1*dest.width+xd1].value = srcPtr[ys1*src.width+xs1].value;
2224                 if (ys2>=src.height) { ys2--; }
2225                 if (xs2>=src.width) { xs2--; }
2226                 if (yd2<dest.height && xd2<dest.width)
2227                     destPtr[yd2*dest.width+xd2].value = srcPtr[ys2*src.width+xs2].value;
2228                 if (xd2<dest.width)
2229                     destPtr[yd1*dest.width+xd2].value = srcPtr[ys1*src.width+xs2].value;
2230                 if (yd2<dest.height)
2231                     destPtr[yd2*dest.width+xd1].value = srcPtr[ys2*src.width+xs1].value;
2232                 //if (ya<src.height && ya2<dest.height && xa<src.width && xa2<dest.width) {}
2233             }
2234         }
2235     }
2236     if (flip == MIRROR_X) {
2237         /* Flip X */
2238         for (y = 0; y < src.height; y++) {
2239             for (x = 0, x1 = src.width*y, x2 = src.width*(y+1)-1;
2240             x < src.width; 
2241             x++, x1++, x2--) {
2242                 destPtr[x2].value = srcPtr[x1].value;
2243             }
2244         }
2245     }
2246     if (flip == MIRROR_Y) {
2247         /* Flip Y */
2248         for (x = 0; x < src.width; x++) {
2249             for (y = 0, y2 = src.height-1; y < src.height; y++, y2--) {
2250                 destPtr[y2*dest.width+x].value = srcPtr[y*src.width+x].value;
2251             }
2252         }
2253     }
2254     if (flip == MIRROR_XY) {
2255         /* Flip X and Y */
2256         for (x = 0, x2 = src.width-1; x < src.width; x++, x2--) {
2257             for (y = 0, y2 = src.height-1; y < src.height; y++, y2--) {
2258                 destPtr[y2*dest.width+x2].value = srcPtr[y*src.width+x].value;
2259             }
2260         }
2261     }
2262
2263     if (flip == MIRROR_TILE) {
2264         for (y = 0; y < src.height; y++) {
2265             for (x = 0; x < src.width; x++) {
2266                 destPtr[y*dest.width+x].value = srcPtr[y*src.width+x].value;
2267             }
2268         }
2269         /* Flip X */
2270         for (y = 0; y < src.height; y++) {
2271             for (x = 0, x1 = src.width*y, x2 = 2*src.width*(y+1)-1;
2272                  x < src.width; 
2273                  x++, x1++, x2--) {
2274                 destPtr[x2].value = srcPtr[x1].value;
2275             }
2276         }
2277         /* Flip Y */
2278         for (x = 0; x < src.width; x++) {
2279             for (y = 0, y2 = 2*src.height-1; y < src.height; y++, y2--) {
2280                 destPtr[y2*dest.width+x].value = srcPtr[y*src.width+x].value;
2281             }
2282         }
2283         /* Flip X and Y */
2284         for (x = 0, x2 = 2*src.width-1; x < src.width; x++, x2--) {
2285             for (y = 0, y2 = 2*src.height-1; y < src.height; y++, y2--) {
2286                 destPtr[y2*dest.width+x2].value = srcPtr[y*src.width+x].value;
2287             }
2288         }
2289     }
2290     
2291     if (flip == MIRROR_OUTER) {
2292         int split = (flags&1);
2293         int sx1, sx2, sy1, sy2,
2294             smx = (src.width/2), smy=(src.height/2),
2295             dmx = (dest.width/2), dmy=(dest.height/2);
2296
2297         /* Initialize whole background to center pixel. */
2298         int sind = (src.height/2)*src.width+src.width/2;
2299         for (x = 0; x < dest.width; x++) {
2300             for (y = 0; y < dest.height; y++) {
2301                 destPtr[y*dest.width+x].value =
2302                 srcPtr[sind].value;
2303             }
2304         }
2305
2306         /* Copy top & bottom pixels. */        
2307         for (y = 0, y2 = dest.height-1, sy1 = 0, sy2 = src.height-1;
2308             y < dmy;
2309             y++, y2--, sy1++, sy2--) {
2310             if (sy1 >= smy) { if (split) { sy1--; sy2++; } else { sy1 = sy2 = smy; }}
2311             for (x = 0, x2 = dest.width-1, sx1 = 0, sx2 = src.width-1;
2312                 x < dmx; x++, x2--, sx1++, sx2--) {
2313                 if (sx1 >= smx) { if (split) { sx1--; sx2++; } else { sx1 = sx2 = smx; }}
2314                 /* Top - left & right */
2315                 destPtr[y*dest.width+x].value = srcPtr[sy1*src.width+sx1].value;
2316                 destPtr[y*dest.width+x2].value = srcPtr[sy1*src.width+sx2].value;
2317                 /* Bottom - left & right */
2318                 destPtr[y2*dest.width+x].value = srcPtr[sy2*src.width+sx1].value;
2319                 destPtr[y2*dest.width+x2].value = srcPtr[sy2*src.width+sx2].value;
2320             }
2321         }
2322         /* Copy left & right pixels. */
2323         for (x = 0, x2 = dest.width-1, sx1 = 0, sx2 = src.width-1;
2324             x < smx && x < dmx;
2325             x++, x2--, sx1++, sx2--) {
2326             if (sx1 >= smx) { if (split) { sx1--; sx2++; } else { sx1 = sx2 = smx; }}
2327             for (y = 0, y2 = dest.height-1, sy1 = 0, sy2 = src.height-1;
2328                 y < dmy; y++, y2--, sy1++, sy2--) {
2329                 if (sy1 >= smy) { if (split) { sy1--; sy2++; } else { sy1 = sy2 = smy; }}
2330                 /* Left - top & bottom */
2331                 destPtr[y*dest.width+x].value = srcPtr[sy1*src.width+sx1].value;
2332                 destPtr[y*dest.width+x2].value = srcPtr[sy1*src.width+sx2].value;
2333                 /* Right - top & bottom */
2334                 destPtr[y2*dest.width+x].value = srcPtr[sy2*src.width+sx1].value;
2335                 destPtr[y2*dest.width+x2].value = srcPtr[sy2*src.width+sx2].value;
2336             }
2337         }
2338     }
2339
2340     Blt_ColorImageToPhoto(destImage, destPhoto);
2341     Blt_FreeColorImage(srcImage);
2342     Blt_FreeColorImage(destImage);
2343     return TCL_OK;
2344 }
2345
2346
2347 /*ARGSUSED*/
2348 static int
2349 MirrorOp(clientData, interp, argc, argv)
2350     ClientData clientData;      /* Not used. */
2351     Tcl_Interp *interp;
2352     int argc;                   /* Not used. */
2353     char **argv;
2354 {
2355     Tk_PhotoHandle srcPhoto, destPhoto;
2356     int flip, halo;
2357
2358     flip = 3;
2359     halo = 0;
2360     srcPhoto = Blt_FindPhoto(interp, argv[2]);
2361     if (srcPhoto == NULL) {
2362         Tcl_AppendResult(interp, "image \"", argv[2], "\" doesn't",
2363             " exist or is not a photo image", (char *)NULL);
2364         return TCL_ERROR;
2365     }
2366     destPhoto = Blt_FindPhoto(interp, argv[3]);
2367     if (destPhoto == NULL) {
2368         Tcl_AppendResult(interp, "destination image \"", argv[3], "\" doesn't",
2369             " exist or is not a photo image", (char *)NULL);
2370         return TCL_ERROR;
2371     }
2372     if (argc>4) {
2373         if (!strcmp(argv[4],"x")) {
2374             flip = MIRROR_X; /* 1 */
2375         } else if (!strcmp(argv[4],"y")) {
2376             flip = MIRROR_Y; /* 2 */
2377         } else if (!strcmp(argv[4],"xy")) {
2378             flip = MIRROR_XY; /* 3 */
2379         } else if (!strcmp(argv[4],"tile")) {
2380             flip = MIRROR_TILE; /* 4 */
2381         } else if (!strcmp(argv[4],"outer")) {
2382             flip = MIRROR_OUTER; /* 5 */
2383         } else if (!strcmp(argv[4],"inner")) {
2384             flip = MIRROR_INNER; /* 6 */
2385         } else {
2386             Tcl_AppendResult(interp, "direction ", argv[4],
2387                 " must be \"x\", \"y\", \"xy\",\"tile\", \"inner\", or  \"outer\"", (char *)NULL);
2388             return TCL_ERROR;
2389         }
2390     }
2391     if (argc>5) {
2392         if (flip != MIRROR_OUTER) {
2393             Tcl_AppendResult(interp, "halo is for outer only", 0);
2394             return TCL_ERROR;
2395         }
2396         if (Tcl_GetInt(interp, argv[5], &halo) != TCL_OK) {
2397             return TCL_ERROR;
2398         }
2399     }
2400     return Blt_ImageMirror(interp, argv[2], argv[3], flip, halo);
2401 }
2402     
2403
2404 /*
2405  * --------------------------------------------------------------------------
2406  *
2407  * SnapOp --
2408  *
2409  *      Snaps a picture of a window and stores it in a designated
2410  *      photo image.  The window must be completely visible or
2411  *      the snap will fail.
2412  *
2413  * Results:
2414  *      Returns a standard Tcl result.  interp->result contains
2415  *      the list of the graph coordinates. If an error occurred
2416  *      while parsing the window positions, TCL_ERROR is returned,
2417  *      then interp->result will contain an error message.
2418  *
2419  * -------------------------------------------------------------------------
2420  */
2421 /*ARGSUSED*/
2422 static int
2423 SnapOp(clientData, interp, argc, argv)
2424     ClientData clientData;
2425     Tcl_Interp *interp;
2426     int argc;                   /* Not used. */
2427     char **argv;
2428 {
2429     Tk_Window tkwin;
2430     int width, height, destWidth, destHeight;
2431     Window window;
2432
2433     tkwin = Tk_MainWindow(interp);
2434     window = StringToWindow(interp, argv[2]);
2435     if (window == None) {
2436         return TCL_ERROR;
2437     }
2438     if (GetWindowSize(interp, window, &width, &height) != TCL_OK) {
2439         Tcl_AppendResult(interp, "can't get window geometry of \"", argv[2],
2440                  "\"", (char *)NULL);
2441         return TCL_ERROR;
2442     }
2443     destWidth = width, destHeight = height;
2444     if ((argc > 4) && (Blt_GetPixels(interp, tkwin, argv[4], PIXELS_POSITIVE,
2445                 &destWidth) != TCL_OK)) {
2446         return TCL_ERROR;
2447     }
2448     if ((argc > 5) && (Blt_GetPixels(interp, tkwin, argv[5], PIXELS_POSITIVE,
2449                 &destHeight) != TCL_OK)) {
2450         return TCL_ERROR;
2451     }
2452     return Blt_SnapPhoto(interp, tkwin, window, 0, 0, width, height, destWidth,
2453         destHeight, argv[3], GAMMA);
2454 }
2455
2456 /*ARGSUSED*/
2457 static int
2458 SubsampleOp(clientData, interp, argc, argv)
2459     ClientData clientData;      /* Main window of the interpreter. */
2460     Tcl_Interp *interp;
2461     int argc;                   /* Not used. */
2462     char **argv;
2463 {
2464     Tk_Window tkwin;
2465     Tk_PhotoHandle srcPhoto, destPhoto;
2466     Tk_PhotoImageBlock src, dest;
2467     ResampleFilter *filterPtr, *vertFilterPtr, *horzFilterPtr;
2468     char *filterName;
2469     int flag;
2470     int x, y;
2471     int width, height;
2472
2473     srcPhoto = Blt_FindPhoto(interp, argv[2]);
2474     if (srcPhoto == NULL) {
2475         Tcl_AppendResult(interp, "source image \"", argv[2], "\" doesn't",
2476             " exist or is not a photo image", (char *)NULL);
2477         return TCL_ERROR;
2478     }
2479     destPhoto = Blt_FindPhoto(interp, argv[3]);
2480     if (destPhoto == NULL) {
2481         Tcl_AppendResult(interp, "destination image \"", argv[3], "\" doesn't",
2482             " exist or is not a photo image", (char *)NULL);
2483         return TCL_ERROR;
2484     }
2485     tkwin = (Tk_Window)clientData;
2486     flag = PIXELS_NONNEGATIVE;
2487     if (Blt_GetPixels(interp, tkwin, argv[4], flag, &x) != TCL_OK) {
2488         return TCL_ERROR;
2489     }
2490     if (Blt_GetPixels(interp, tkwin, argv[5], flag, &y) != TCL_OK) {
2491         return TCL_ERROR;
2492     }
2493     flag = PIXELS_POSITIVE;
2494     if (Blt_GetPixels(interp, tkwin, argv[6], flag, &width) != TCL_OK) {
2495         return TCL_ERROR;
2496     }
2497     if (Blt_GetPixels(interp, tkwin, argv[7], flag, &height) != TCL_OK) {
2498         return TCL_ERROR;
2499     }
2500     filterName = (argc > 8) ? argv[8] : "none";
2501     if (Blt_GetResampleFilter(interp, filterName, &filterPtr) != TCL_OK) {
2502         return TCL_ERROR;
2503     }
2504     vertFilterPtr = horzFilterPtr = filterPtr;
2505     if ((filterPtr != NULL) && (argc > 9)) {
2506         if (Blt_GetResampleFilter(interp, argv[9], &filterPtr) != TCL_OK) {
2507             return TCL_ERROR;
2508         }
2509         vertFilterPtr = filterPtr;
2510     }
2511     Tk_PhotoGetImage(srcPhoto, &src);
2512     Tk_PhotoGetImage(destPhoto, &dest);
2513     if ((src.width <= 1) || (src.height <= 1)) {
2514         Tcl_AppendResult(interp, "source image \"", argv[2], "\" is empty",
2515             (char *)NULL);
2516         return TCL_ERROR;
2517     }
2518     if (((x + width) > src.width) || ((y + height) > src.height)) {
2519         Tcl_AppendResult(interp, "nonsensical dimensions for subregion: x=",
2520             argv[4], " y=", argv[5], " width=", argv[6], " height=",
2521             argv[7], (char *)NULL);
2522         return TCL_ERROR;
2523     }
2524     if ((dest.width <= 1) || (dest.height <= 1)) {
2525         Tk_PhotoSetSize(destPhoto, width, height);
2526     }
2527     if (filterPtr == NULL) {
2528         Blt_ResizePhoto(srcPhoto, x, y, width, height, destPhoto);
2529     } else {
2530         Blt_ResamplePhoto(srcPhoto, x, y, width, height, destPhoto, 
2531                 horzFilterPtr, vertFilterPtr);
2532     }
2533     return TCL_OK;
2534 }
2535
2536 static Blt_OpSpec imageOps[] =
2537 {
2538     {"alpha", 2, (Blt_Op)AlphaOp, 6, 10, "?-shift? srcPhoto destPhoto Color ?alpha? ?withalpha?",},
2539     {"blur", 2, (Blt_Op)BlurOp, 5, 6, "srcPhoto destPhoto ?radius?",},
2540     {"colors", 3, (Blt_Op)ColorsOp, 4, 0, "?-alpha? ?-count? ?-from x1 y1 x2 y2? srcPhoto",},
2541     {"convolve", 3, (Blt_Op)ConvolveOp, 6, 6, "srcPhoto destPhoto filter",},
2542     {"gradient", 1, (Blt_Op)GradientOp, 6, 0, "photo left right ?-type lines|normal|radial|rectangular|linear|sine|halfsine? ?-skew val? ?-slant val? ?-rand val? ?-mathval val? ?-mathfunc circle|sin|cos|tan|asin|acos|atan|sinh|cosh|tanh|exp|sqrt|log|log10|rand?",},
2543     {"merge", 2, (Blt_Op)MergeOp, 6, 7, "srcPhoto1 srcPhoto2 destPhoto ?opacity? ?opacity2?",},
2544     {"mirror", 3, (Blt_Op)MirrorOp, 5, 7, "srcPhoto destPhoto ?x|y|xy|tile|outer|innert? ?halo?",},
2545     {"quantize", 2, (Blt_Op)QuantizeOp, 4, 5, "srcPhoto destPhoto ?nColors?",},
2546     {"readjpeg", 3, (Blt_Op)ReadJPEGOp, 5, 5, "fileName photoName",},
2547     {"recolor", 3, (Blt_Op)RecolorOp, 7, 8, "srcPhoto destPhoto oldColor newColor ?alpha?",},
2548     {"resample", 3, (Blt_Op)ResampleOp, 5, 7, 
2549         "srcPhoto destPhoto ?horzFilter vertFilter?",},
2550     {"rotate", 2, (Blt_Op)RotateOp, 6, 6, "srcPhoto destPhoto angle",},
2551     {"subsample", 2, (Blt_Op)SubsampleOp, 9, 11,
2552         "srcPhoto destPhoto x y width height ?horzFilter? ?vertFilter?",},
2553     {"trans", 2, (Blt_Op)TransOp, 6, 7, "image x y ?alpha?",},
2554 };
2555
2556 static int nImageOps = sizeof(imageOps) / sizeof(Blt_OpSpec);
2557
2558 /* ARGSUSED */
2559 static int
2560 ImageOp(clientData, interp, argc, argv)
2561     ClientData clientData;      /* Main window of interpreter. */
2562     Tcl_Interp *interp;         /* Current interpreter. */
2563     int argc;                   /* Number of arguments. */
2564     char **argv;                /* Argument strings. */
2565 {
2566     Blt_Op proc;
2567     int result;
2568
2569     proc = Blt_GetOp(interp, nImageOps, imageOps, BLT_OP_ARG2, argc, argv, 0);
2570     if (proc == NULL) {
2571         return TCL_ERROR;
2572     }
2573     clientData = (ClientData)Tk_MainWindow(interp);
2574     result = (*proc) (clientData, interp, argc - 1, argv + 1);
2575     return result;
2576 }
2577
2578 static Blt_OpSpec winOps[] =
2579 {
2580     {"changes", 3, (Blt_Op)ChangesOp, 3, 3, "window",},
2581 #ifndef WIN32
2582     {"colormap", 3, (Blt_Op)ColormapOp, 3, 3, "window",},
2583 #endif
2584     {"gradients", 1, (Blt_Op)GradientsOp, 5, 5, "color1 color2 width",},
2585     {"image", 1, (Blt_Op)ImageOp, 2, 0, "args",},
2586     {"lower", 1, (Blt_Op)LowerOp, 2, 0, "window ?window?...",},
2587     {"map", 2, (Blt_Op)MapOp, 2, 0, "window ?window?...",},
2588     {"move", 2, (Blt_Op)MoveOp, 5, 5, "window x y",},
2589     {"parent", 3, (Blt_Op)ParentOp, 3, 3, "window",},
2590     {"query", 3, (Blt_Op)QueryOp, 2, 2, "",},
2591     {"raise", 2, (Blt_Op)RaiseOp, 2, 0, "window ?window?...",},
2592 #ifdef notdef
2593     {"reparent", 3, (Blt_Op)ReparentOp, 3, 4, "window ?parent?",},
2594 #endif
2595     {"snap", 2, (Blt_Op)SnapOp, 4, 8, "window photoName ?width height?",},
2596     {"unmap", 1, (Blt_Op)UnmapOp, 2, 0, "window ?window?...",},
2597     {"warpto", 1, (Blt_Op)WarpToOp, 2, 5, "?window?",},
2598 };
2599
2600 static int nWinOps = sizeof(winOps) / sizeof(Blt_OpSpec);
2601
2602 /* ARGSUSED */
2603 static int
2604 WinopCmd(clientData, interp, argc, argv)
2605     ClientData clientData;      /* Main window of interpreter. */
2606     Tcl_Interp *interp;         /* Current interpreter. */
2607     int argc;                   /* Number of arguments. */
2608     char **argv;                /* Argument strings. */
2609 {
2610     Blt_Op proc;
2611     int result;
2612
2613     proc = Blt_GetOp(interp, nWinOps, winOps, BLT_OP_ARG1,  argc, argv, 0);
2614     if (proc == NULL) {
2615         return TCL_ERROR;
2616     }
2617     clientData = (ClientData)Tk_MainWindow(interp);
2618     result = (*proc) (clientData, interp, argc, argv);
2619     return result;
2620 }
2621
2622 int
2623 Blt_WinopInit(interp)
2624     Tcl_Interp *interp;
2625 {
2626     static Blt_CmdSpec cmdSpec = {"winop", WinopCmd,};
2627
2628     if (Blt_InitCmd(interp, "blt", &cmdSpec) == NULL) {
2629         return TCL_ERROR;
2630     }
2631     return TCL_OK;
2632 }
2633
2634 #endif /* NO_WINOP */