/[dtapublic]/projs/trunk/shared_source/c_tk_base_7_5_w_mods/tkimgphoto.c
ViewVC logotype

Annotation of /projs/trunk/shared_source/c_tk_base_7_5_w_mods/tkimgphoto.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 25 - (hide annotations) (download)
Sat Oct 8 06:43:03 2016 UTC (8 years, 1 month ago) by dashley
Original Path: sf_code/esrgpcpj/shared/tk_base/tkimgphoto.c
File MIME type: text/plain
File size: 154352 byte(s)
Initial commit.
1 dashley 25 /* $Header: /cvsroot/esrg/sfesrg/esrgpcpj/shared/tk_base/tkimgphoto.c,v 1.1.1.1 2001/06/13 05:03:26 dtashley Exp $ */
2    
3     /*
4     * tkImgPhoto.c --
5     *
6     * Implements images of type "photo" for Tk. Photo images are
7     * stored in full color (32 bits per pixel) and displayed using
8     * dithering if necessary.
9     *
10     * Copyright (c) 1994 The Australian National University.
11     * Copyright (c) 1994-1997 Sun Microsystems, Inc.
12     *
13     * See the file "license.terms" for information on usage and redistribution
14     * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
15     *
16     * Author: Paul Mackerras (paulus@cs.anu.edu.au),
17     * Department of Computer Science,
18     * Australian National University.
19     *
20     * RCS: @(#) $Id: tkimgphoto.c,v 1.1.1.1 2001/06/13 05:03:26 dtashley Exp $
21     */
22    
23     #include "tkInt.h"
24     #include "tkPort.h"
25     #include "tclMath.h"
26     #include <ctype.h>
27    
28     #ifdef __WIN32__
29     #include "tkWinInt.h"
30     #endif
31    
32     /*
33     * Declaration for internal Xlib function used here:
34     */
35    
36     extern int _XInitImageFuncPtrs _ANSI_ARGS_((XImage *image));
37    
38     /*
39     * A signed 8-bit integral type. If chars are unsigned and the compiler
40     * isn't an ANSI one, then we have to use short instead (which wastes
41     * space) to get signed behavior.
42     */
43    
44     #if defined(__STDC__) || defined(_AIX)
45     typedef signed char schar;
46     #else
47     # ifndef __CHAR_UNSIGNED__
48     typedef char schar;
49     # else
50     typedef short schar;
51     # endif
52     #endif
53    
54     /*
55     * An unsigned 32-bit integral type, used for pixel values.
56     * We use int rather than long here to accommodate those systems
57     * where longs are 64 bits.
58     */
59    
60     typedef unsigned int pixel;
61    
62     /*
63     * The maximum number of pixels to transmit to the server in a
64     * single XPutImage call.
65     */
66    
67     #define MAX_PIXELS 65536
68    
69     /*
70     * The set of colors required to display a photo image in a window depends on:
71     * - the visual used by the window
72     * - the palette, which specifies how many levels of each primary
73     * color to use, and
74     * - the gamma value for the image.
75     *
76     * Pixel values allocated for specific colors are valid only for the
77     * colormap in which they were allocated. Sets of pixel values
78     * allocated for displaying photos are re-used in other windows if
79     * possible, that is, if the display, colormap, palette and gamma
80     * values match. A hash table is used to locate these sets of pixel
81     * values, using the following data structure as key:
82     */
83    
84     typedef struct {
85     Display *display; /* Qualifies the colormap resource ID */
86     Colormap colormap; /* Colormap that the windows are using. */
87     double gamma; /* Gamma exponent value for images. */
88     Tk_Uid palette; /* Specifies how many shades of each primary
89     * we want to allocate. */
90     } ColorTableId;
91    
92     /*
93     * For a particular (display, colormap, palette, gamma) combination,
94     * a data structure of the following type is used to store the allocated
95     * pixel values and other information:
96     */
97    
98     typedef struct ColorTable {
99     ColorTableId id; /* Information used in selecting this
100     * color table. */
101     int flags; /* See below. */
102     int refCount; /* Number of instances using this map. */
103     int liveRefCount; /* Number of instances which are actually
104     * in use, using this map. */
105     int numColors; /* Number of colors allocated for this map. */
106    
107     XVisualInfo visualInfo; /* Information about the visual for windows
108     * using this color table. */
109    
110     pixel redValues[256]; /* Maps 8-bit values of red intensity
111     * to a pixel value or index in pixelMap. */
112     pixel greenValues[256]; /* Ditto for green intensity */
113     pixel blueValues[256]; /* Ditto for blue intensity */
114     unsigned long *pixelMap; /* Actual pixel values allocated. */
115    
116     unsigned char colorQuant[3][256];
117     /* Maps 8-bit intensities to quantized
118     * intensities. The first index is 0 for
119     * red, 1 for green, 2 for blue. */
120     } ColorTable;
121    
122     /*
123     * Bit definitions for the flags field of a ColorTable.
124     * BLACK_AND_WHITE: 1 means only black and white colors are
125     * available.
126     * COLOR_WINDOW: 1 means a full 3-D color cube has been
127     * allocated.
128     * DISPOSE_PENDING: 1 means a call to DisposeColorTable has
129     * been scheduled as an idle handler, but it
130     * hasn't been invoked yet.
131     * MAP_COLORS: 1 means pixel values should be mapped
132     * through pixelMap.
133     */
134     #ifdef COLOR_WINDOW
135     #undef COLOR_WINDOW
136     #endif
137    
138     #define BLACK_AND_WHITE 1
139     #define COLOR_WINDOW 2
140     #define DISPOSE_PENDING 4
141     #define MAP_COLORS 8
142    
143     /*
144     * Definition of the data associated with each photo image master.
145     */
146    
147     typedef struct PhotoMaster {
148     Tk_ImageMaster tkMaster; /* Tk's token for image master. NULL means
149     * the image is being deleted. */
150     Tcl_Interp *interp; /* Interpreter associated with the
151     * application using this image. */
152     Tcl_Command imageCmd; /* Token for image command (used to delete
153     * it when the image goes away). NULL means
154     * the image command has already been
155     * deleted. */
156     int flags; /* Sundry flags, defined below. */
157     int width, height; /* Dimensions of image. */
158     int userWidth, userHeight; /* User-declared image dimensions. */
159     Tk_Uid palette; /* User-specified default palette for
160     * instances of this image. */
161     double gamma; /* Display gamma value to correct for. */
162     char *fileString; /* Name of file to read into image. */
163     Tcl_Obj *dataString; /* Object to use as contents of image. */
164     Tcl_Obj *format; /* User-specified format of data in image
165     * file or string value. */
166     unsigned char *pix24; /* Local storage for 24-bit image. */
167     int ditherX, ditherY; /* Location of first incorrectly
168     * dithered pixel in image. */
169     TkRegion validRegion; /* Tk region indicating which parts of
170     * the image have valid image data. */
171     struct PhotoInstance *instancePtr;
172     /* First in the list of instances
173     * associated with this master. */
174     } PhotoMaster;
175    
176     /*
177     * Bit definitions for the flags field of a PhotoMaster.
178     * COLOR_IMAGE: 1 means that the image has different color
179     * components.
180     * IMAGE_CHANGED: 1 means that the instances of this image
181     * need to be redithered.
182     */
183    
184     #define COLOR_IMAGE 1
185     #define IMAGE_CHANGED 2
186    
187     /*
188     * The following data structure represents all of the instances of
189     * a photo image in windows on a given screen that are using the
190     * same colormap.
191     */
192    
193     typedef struct PhotoInstance {
194     PhotoMaster *masterPtr; /* Pointer to master for image. */
195     Display *display; /* Display for windows using this instance. */
196     Colormap colormap; /* The image may only be used in windows with
197     * this particular colormap. */
198     struct PhotoInstance *nextPtr;
199     /* Pointer to the next instance in the list
200     * of instances associated with this master. */
201     int refCount; /* Number of instances using this structure. */
202     Tk_Uid palette; /* Palette for these particular instances. */
203     double gamma; /* Gamma value for these instances. */
204     Tk_Uid defaultPalette; /* Default palette to use if a palette
205     * is not specified for the master. */
206     ColorTable *colorTablePtr; /* Pointer to information about colors
207     * allocated for image display in windows
208     * like this one. */
209     Pixmap pixels; /* X pixmap containing dithered image. */
210     int width, height; /* Dimensions of the pixmap. */
211     schar *error; /* Error image, used in dithering. */
212     XImage *imagePtr; /* Image structure for converted pixels. */
213     XVisualInfo visualInfo; /* Information about the visual that these
214     * windows are using. */
215     GC gc; /* Graphics context for writing images
216     * to the pixmap. */
217     } PhotoInstance;
218    
219     /*
220     * The following data structure is used to return information
221     * from ParseSubcommandOptions:
222     */
223    
224     struct SubcommandOptions {
225     int options; /* Individual bits indicate which
226     * options were specified - see below. */
227     Tcl_Obj *name; /* Name specified without an option. */
228     int fromX, fromY; /* Values specified for -from option. */
229     int fromX2, fromY2; /* Second coordinate pair for -from option. */
230     int toX, toY; /* Values specified for -to option. */
231     int toX2, toY2; /* Second coordinate pair for -to option. */
232     int zoomX, zoomY; /* Values specified for -zoom option. */
233     int subsampleX, subsampleY; /* Values specified for -subsample option. */
234     Tcl_Obj *format; /* Value specified for -format option. */
235     XColor *background; /* Value specified for -background option. */
236     };
237    
238     /*
239     * Bit definitions for use with ParseSubcommandOptions:
240     * Each bit is set in the allowedOptions parameter on a call to
241     * ParseSubcommandOptions if that option is allowed for the current
242     * photo image subcommand. On return, the bit is set in the options
243     * field of the SubcommandOptions structure if that option was specified.
244     *
245     * OPT_BACKGROUND: Set if -format option allowed/specified.
246     * OPT_FORMAT: Set if -format option allowed/specified.
247     * OPT_FROM: Set if -from option allowed/specified.
248     * OPT_GRAYSCALE: Set if -grayscale option allowed/specified.
249     * OPT_SHRINK: Set if -shrink option allowed/specified.
250     * OPT_SUBSAMPLE: Set if -subsample option allowed/spec'd.
251     * OPT_TO: Set if -to option allowed/specified.
252     * OPT_ZOOM: Set if -zoom option allowed/specified.
253     */
254    
255     #define OPT_BACKGROUND 1
256     #define OPT_FORMAT 2
257     #define OPT_FROM 4
258     #define OPT_GRAYSCALE 8
259     #define OPT_SHRINK 0x10
260     #define OPT_SUBSAMPLE 0x20
261     #define OPT_TO 0x40
262     #define OPT_ZOOM 0x80
263    
264     /*
265     * List of option names. The order here must match the order of
266     * declarations of the OPT_* constants above.
267     */
268    
269     static char *optionNames[] = {
270     "-background",
271     "-format",
272     "-from",
273     "-grayscale",
274     "-shrink",
275     "-subsample",
276     "-to",
277     "-zoom",
278     (char *) NULL
279     };
280    
281     /*
282     * The type record for photo images:
283     */
284    
285     static int ImgPhotoCreate _ANSI_ARGS_((Tcl_Interp *interp,
286     char *name, int objc, Tcl_Obj *CONST objv[],
287     Tk_ImageType *typePtr, Tk_ImageMaster master,
288     ClientData *clientDataPtr));
289     static ClientData ImgPhotoGet _ANSI_ARGS_((Tk_Window tkwin,
290     ClientData clientData));
291     static void ImgPhotoDisplay _ANSI_ARGS_((ClientData clientData,
292     Display *display, Drawable drawable,
293     int imageX, int imageY, int width, int height,
294     int drawableX, int drawableY));
295     static void ImgPhotoFree _ANSI_ARGS_((ClientData clientData,
296     Display *display));
297     static void ImgPhotoDelete _ANSI_ARGS_((ClientData clientData));
298     static int ImgPhotoPostscript _ANSI_ARGS_((ClientData clientData,
299     Tcl_Interp *interp, Tk_Window tkwin,
300     Tk_PostscriptInfo psInfo, int x, int y, int width,
301     int height, int prepass));
302    
303     Tk_ImageType tkPhotoImageType = {
304     "photo", /* name */
305     ImgPhotoCreate, /* createProc */
306     ImgPhotoGet, /* getProc */
307     ImgPhotoDisplay, /* displayProc */
308     ImgPhotoFree, /* freeProc */
309     ImgPhotoDelete, /* deleteProc */
310     ImgPhotoPostscript, /* postscriptProc */
311     (Tk_ImageType *) NULL /* nextPtr */
312     };
313    
314     typedef struct ThreadSpecificData {
315     Tk_PhotoImageFormat *formatList; /* Pointer to the first in the
316     * list of known photo image formats.*/
317     Tk_PhotoImageFormat *oldFormatList; /* Pointer to the first in the
318     * list of known photo image formats.*/
319     } ThreadSpecificData;
320     static Tcl_ThreadDataKey dataKey;
321    
322     /*
323     * Default configuration
324     */
325    
326     #define DEF_PHOTO_GAMMA "1"
327     #define DEF_PHOTO_HEIGHT "0"
328     #define DEF_PHOTO_PALETTE ""
329     #define DEF_PHOTO_WIDTH "0"
330    
331     /*
332     * Information used for parsing configuration specifications:
333     */
334     static Tk_ConfigSpec configSpecs[] = {
335     {TK_CONFIG_STRING, "-file", (char *) NULL, (char *) NULL,
336     (char *) NULL, Tk_Offset(PhotoMaster, fileString), TK_CONFIG_NULL_OK},
337     {TK_CONFIG_DOUBLE, "-gamma", (char *) NULL, (char *) NULL,
338     DEF_PHOTO_GAMMA, Tk_Offset(PhotoMaster, gamma), 0},
339     {TK_CONFIG_INT, "-height", (char *) NULL, (char *) NULL,
340     DEF_PHOTO_HEIGHT, Tk_Offset(PhotoMaster, userHeight), 0},
341     {TK_CONFIG_UID, "-palette", (char *) NULL, (char *) NULL,
342     DEF_PHOTO_PALETTE, Tk_Offset(PhotoMaster, palette), 0},
343     {TK_CONFIG_INT, "-width", (char *) NULL, (char *) NULL,
344     DEF_PHOTO_WIDTH, Tk_Offset(PhotoMaster, userWidth), 0},
345     {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,
346     (char *) NULL, 0, 0}
347     };
348    
349     /*
350     * Hash table used to hash from (display, colormap, palette, gamma)
351     * to ColorTable address.
352     */
353    
354     static Tcl_HashTable imgPhotoColorHash;
355     static int imgPhotoColorHashInitialized;
356     #define N_COLOR_HASH (sizeof(ColorTableId) / sizeof(int))
357    
358     /*
359     * Forward declarations
360     */
361    
362     static int ImgPhotoCmd _ANSI_ARGS_((ClientData clientData,
363     Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]));
364     static int ParseSubcommandOptions _ANSI_ARGS_((
365     struct SubcommandOptions *optPtr,
366     Tcl_Interp *interp, int allowedOptions,
367     int *indexPtr, int objc, Tcl_Obj *CONST objv[]));
368     static void ImgPhotoCmdDeletedProc _ANSI_ARGS_((
369     ClientData clientData));
370     static int ImgPhotoConfigureMaster _ANSI_ARGS_((
371     Tcl_Interp *interp, PhotoMaster *masterPtr,
372     int objc, Tcl_Obj *CONST objv[], int flags));
373     static void ImgPhotoConfigureInstance _ANSI_ARGS_((
374     PhotoInstance *instancePtr));
375     static void ImgPhotoSetSize _ANSI_ARGS_((PhotoMaster *masterPtr,
376     int width, int height));
377     static void ImgPhotoInstanceSetSize _ANSI_ARGS_((
378     PhotoInstance *instancePtr));
379     static int ImgStringWrite _ANSI_ARGS_((Tcl_Interp *interp,
380     Tcl_Obj *formatString,
381     Tk_PhotoImageBlock *blockPtr));
382     static char * ImgGetPhoto _ANSI_ARGS_((PhotoMaster *masterPtr,
383     Tk_PhotoImageBlock *blockPtr,
384     struct SubcommandOptions *optPtr));
385     static int IsValidPalette _ANSI_ARGS_((PhotoInstance *instancePtr,
386     char *palette));
387     static int CountBits _ANSI_ARGS_((pixel mask));
388     static void GetColorTable _ANSI_ARGS_((PhotoInstance *instancePtr));
389     static void FreeColorTable _ANSI_ARGS_((ColorTable *colorPtr,
390     int force));
391     static void AllocateColors _ANSI_ARGS_((ColorTable *colorPtr));
392     static void DisposeColorTable _ANSI_ARGS_((ClientData clientData));
393     static void DisposeInstance _ANSI_ARGS_((ClientData clientData));
394     static int ReclaimColors _ANSI_ARGS_((ColorTableId *id,
395     int numColors));
396     static int MatchFileFormat _ANSI_ARGS_((Tcl_Interp *interp,
397     Tcl_Channel chan, char *fileName, Tcl_Obj *formatString,
398     Tk_PhotoImageFormat **imageFormatPtr,
399     int *widthPtr, int *heightPtr, int *oldformat));
400     static int MatchStringFormat _ANSI_ARGS_((Tcl_Interp *interp,
401     Tcl_Obj *data, Tcl_Obj *formatString,
402     Tk_PhotoImageFormat **imageFormatPtr,
403     int *widthPtr, int *heightPtr, int *oldformat));
404     static Tcl_ObjCmdProc * PhotoOptionFind _ANSI_ARGS_((Tcl_Interp * interp,
405     Tcl_Obj *obj));
406     static void DitherInstance _ANSI_ARGS_((PhotoInstance *instancePtr,
407     int x, int y, int width, int height));
408     static void PhotoOptionCleanupProc _ANSI_ARGS_((
409     ClientData clientData, Tcl_Interp *interp));
410    
411     #undef MIN
412     #define MIN(a, b) ((a) < (b)? (a): (b))
413     #undef MAX
414     #define MAX(a, b) ((a) > (b)? (a): (b))
415    
416     /*
417     *----------------------------------------------------------------------
418     *
419     * Tk_CreateOldPhotoImageFormat, Tk_CreatePhotoImageFormat --
420     *
421     * This procedure is invoked by an image file handler to register
422     * a new photo image format and the procedures that handle the
423     * new format. The procedure is typically invoked during
424     * Tcl_AppInit.
425     *
426     * Results:
427     * None.
428     *
429     * Side effects:
430     * The new image file format is entered into a table used in the
431     * photo image "read" and "write" subcommands.
432     *
433     *----------------------------------------------------------------------
434     */
435     void
436     Tk_CreateOldPhotoImageFormat(formatPtr)
437     Tk_PhotoImageFormat *formatPtr;
438     /* Structure describing the format. All of
439     * the fields except "nextPtr" must be filled
440     * in by caller. Must not have been passed
441     * to Tk_CreatePhotoImageFormat previously. */
442     {
443     Tk_PhotoImageFormat *copyPtr;
444     ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
445     Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
446    
447     copyPtr = (Tk_PhotoImageFormat *) ckalloc(sizeof(Tk_PhotoImageFormat));
448     *copyPtr = *formatPtr;
449     copyPtr->name = (char *) ckalloc((unsigned) (strlen(formatPtr->name) + 1));
450     strcpy(copyPtr->name, formatPtr->name);
451     copyPtr->nextPtr = tsdPtr->oldFormatList;
452     tsdPtr->oldFormatList = copyPtr;
453     }
454    
455     void
456     Tk_CreatePhotoImageFormat(formatPtr)
457     Tk_PhotoImageFormat *formatPtr;
458     /* Structure describing the format. All of
459     * the fields except "nextPtr" must be filled
460     * in by caller. Must not have been passed
461     * to Tk_CreatePhotoImageFormat previously. */
462     {
463     Tk_PhotoImageFormat *copyPtr;
464     ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
465     Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
466    
467     copyPtr = (Tk_PhotoImageFormat *) ckalloc(sizeof(Tk_PhotoImageFormat));
468     *copyPtr = *formatPtr;
469     copyPtr->name = (char *) ckalloc((unsigned) (strlen(formatPtr->name) + 1));
470     strcpy(copyPtr->name, formatPtr->name);
471     if (isupper((unsigned char) *formatPtr->name)) {
472     copyPtr->nextPtr = tsdPtr->oldFormatList;
473     tsdPtr->oldFormatList = copyPtr;
474     } else {
475     copyPtr->nextPtr = tsdPtr->formatList;
476     tsdPtr->formatList = copyPtr;
477     }
478     }
479    
480     /*
481     *----------------------------------------------------------------------
482     *
483     * ImgPhotoCreate --
484     *
485     * This procedure is called by the Tk image code to create
486     * a new photo image.
487     *
488     * Results:
489     * A standard Tcl result.
490     *
491     * Side effects:
492     * The data structure for a new photo image is allocated and
493     * initialized.
494     *
495     *----------------------------------------------------------------------
496     */
497    
498     static int
499     ImgPhotoCreate(interp, name, objc, objv, typePtr, master, clientDataPtr)
500     Tcl_Interp *interp; /* Interpreter for application containing
501     * image. */
502     char *name; /* Name to use for image. */
503     int objc; /* Number of arguments. */
504     Tcl_Obj *CONST objv[]; /* Argument objects for options (doesn't
505     * include image name or type). */
506     Tk_ImageType *typePtr; /* Pointer to our type record (not used). */
507     Tk_ImageMaster master; /* Token for image, to be used by us in
508     * later callbacks. */
509     ClientData *clientDataPtr; /* Store manager's token for image here;
510     * it will be returned in later callbacks. */
511     {
512     PhotoMaster *masterPtr;
513    
514     /*
515     * Allocate and initialize the photo image master record.
516     */
517    
518     masterPtr = (PhotoMaster *) ckalloc(sizeof(PhotoMaster));
519     memset((void *) masterPtr, 0, sizeof(PhotoMaster));
520     masterPtr->tkMaster = master;
521     masterPtr->interp = interp;
522     masterPtr->imageCmd = Tcl_CreateObjCommand(interp, name, ImgPhotoCmd,
523     (ClientData) masterPtr, ImgPhotoCmdDeletedProc);
524     masterPtr->palette = NULL;
525     masterPtr->pix24 = NULL;
526     masterPtr->instancePtr = NULL;
527     masterPtr->validRegion = TkCreateRegion();
528    
529     /*
530     * Process configuration options given in the image create command.
531     */
532    
533     if (ImgPhotoConfigureMaster(interp, masterPtr, objc, objv, 0) != TCL_OK) {
534     ImgPhotoDelete((ClientData) masterPtr);
535     return TCL_ERROR;
536     }
537    
538     *clientDataPtr = (ClientData) masterPtr;
539     return TCL_OK;
540     }
541    
542     /*
543     *----------------------------------------------------------------------
544     *
545     * ImgPhotoCmd --
546     *
547     * This procedure is invoked to process the Tcl command that
548     * corresponds to a photo image. See the user documentation
549     * for details on what it does.
550     *
551     * Results:
552     * A standard Tcl result.
553     *
554     * Side effects:
555     * See the user documentation.
556     *
557     *----------------------------------------------------------------------
558     */
559    
560     static int
561     ImgPhotoCmd(clientData, interp, objc, objv)
562     ClientData clientData; /* Information about photo master. */
563     Tcl_Interp *interp; /* Current interpreter. */
564     int objc; /* Number of arguments. */
565     Tcl_Obj *CONST objv[]; /* Argument objects. */
566     {
567     int oldformat = 0;
568     static char *photoOptions[] = {
569     "blank", "cget", "configure", "copy", "data", "get", "put",
570     "read", "redither", "write", (char *) NULL
571     };
572     enum options {
573     PHOTO_BLANK, PHOTO_CGET, PHOTO_CONFIGURE, PHOTO_COPY, PHOTO_DATA,
574     PHOTO_GET, PHOTO_PUT, PHOTO_READ, PHOTO_REDITHER, PHOTO_WRITE
575     };
576    
577     PhotoMaster *masterPtr = (PhotoMaster *) clientData;
578     int result, index;
579     int x, y, width, height;
580     int dataWidth, dataHeight;
581     struct SubcommandOptions options;
582     int listArgc;
583     char **listArgv;
584     char **srcArgv;
585     unsigned char *pixelPtr;
586     Tk_PhotoImageBlock block;
587     Tk_Window tkwin;
588     XColor color;
589     Tk_PhotoImageFormat *imageFormat;
590     int imageWidth, imageHeight;
591     int matched;
592     Tcl_Channel chan;
593     Tk_PhotoHandle srcHandle;
594     size_t length;
595     ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
596     Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
597    
598     if (objc < 2) {
599     Tcl_WrongNumArgs(interp, 1, objv, "option ?arg arg ...?");
600     return TCL_ERROR;
601     }
602    
603     if (Tcl_GetIndexFromObj(interp, objv[1], photoOptions, "option", 0,
604     &index) != TCL_OK) {
605     Tcl_ObjCmdProc *proc;
606     proc = PhotoOptionFind(interp, objv[1]);
607     if (proc == (Tcl_ObjCmdProc *) NULL) {
608     return TCL_ERROR;
609     }
610     return proc(clientData, interp, objc, objv);
611     }
612     switch ((enum options) index) {
613     case PHOTO_BLANK: {
614     /*
615     * photo blank command - just call Tk_PhotoBlank.
616     */
617    
618     if (objc == 2) {
619     Tk_PhotoBlank(masterPtr);
620     } else {
621     Tcl_WrongNumArgs(interp, 2, objv, (char *) NULL);
622     return TCL_ERROR;
623     }
624     break;
625     }
626     case PHOTO_CGET: {
627     char *arg;
628     if (objc != 3) {
629     Tcl_WrongNumArgs(interp, 2, objv, "option");
630     return TCL_ERROR;
631     }
632     arg = Tcl_GetStringFromObj(objv[2], (int *) &length);
633     if (strncmp(arg,"-data", length) == 0) {
634     if (masterPtr->dataString) {
635     Tcl_SetObjResult(interp, masterPtr->dataString);
636     }
637     return TCL_OK;
638     }
639     if (strncmp(arg,"-format", length) == 0) {
640     if (masterPtr->format) {
641     Tcl_SetObjResult(interp, masterPtr->format);
642     }
643     return TCL_OK;
644     }
645     Tk_ConfigureValue(interp, Tk_MainWindow(interp), configSpecs,
646     (char *) masterPtr, Tcl_GetString(objv[2]), 0);
647     break;
648     }
649     case PHOTO_CONFIGURE: {
650     /*
651     * photo configure command - handle this in the standard way.
652     */
653    
654     if (objc == 2) {
655     Tcl_Obj *obj, *subobj;
656     result = Tk_ConfigureInfo(interp, Tk_MainWindow(interp),
657     configSpecs, (char *) masterPtr, (char *) NULL, 0);
658     if (result != TCL_OK) {
659     return result;
660     }
661     obj = Tcl_NewObj();
662     subobj = Tcl_NewStringObj("-data {} {} {}", 14);
663     if (masterPtr->dataString) {
664     Tcl_ListObjAppendElement(interp, subobj, masterPtr->dataString);
665     } else {
666     Tcl_AppendStringsToObj(subobj, " {}", (char *) NULL);
667     }
668     Tcl_ListObjAppendElement(interp, obj, subobj);
669     subobj = Tcl_NewStringObj("-format {} {} {}", 16);
670     if (masterPtr->format) {
671     Tcl_ListObjAppendElement(interp, subobj, masterPtr->format);
672     } else {
673     Tcl_AppendStringsToObj(subobj, " {}", (char *) NULL);
674     }
675     Tcl_ListObjAppendElement(interp, obj, subobj);
676     Tcl_ListObjAppendList(interp, obj, Tcl_GetObjResult(interp));
677     Tcl_SetObjResult(interp, obj);
678     return TCL_OK;
679     }
680     if (objc == 3) {
681     char *arg = Tcl_GetStringFromObj(objv[2], (int *) &length);
682     if (!strncmp(arg, "-data", length)) {
683     Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
684     "-data {} {} {}", (char *) NULL);
685     if (masterPtr->dataString) {
686     Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp),
687     masterPtr->dataString);
688     } else {
689     Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
690     " {}", (char *) NULL);
691     }
692     return TCL_OK;
693     } else if (!strncmp(arg, "-format", length)) {
694     Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
695     "-format {} {} {}", (char *) NULL);
696     if (masterPtr->format) {
697     Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp),
698     masterPtr->format);
699     } else {
700     Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
701     " {}", (char *) NULL);
702     }
703     return TCL_OK;
704     } else {
705     return Tk_ConfigureInfo(interp, Tk_MainWindow(interp),
706     configSpecs, (char *) masterPtr, arg, 0);
707     }
708     }
709     return ImgPhotoConfigureMaster(interp, masterPtr, objc-2, objv+2,
710     TK_CONFIG_ARGV_ONLY);
711     break;
712     }
713     case PHOTO_COPY: {
714     /*
715     * photo copy command - first parse options.
716     */
717    
718     index = 2;
719     memset((VOID *) &options, 0, sizeof(options));
720     options.zoomX = options.zoomY = 1;
721     options.subsampleX = options.subsampleY = 1;
722     options.name = NULL;
723     if (ParseSubcommandOptions(&options, interp,
724     OPT_FROM | OPT_TO | OPT_ZOOM | OPT_SUBSAMPLE | OPT_SHRINK,
725     &index, objc, objv) != TCL_OK) {
726     return TCL_ERROR;
727     }
728     if (options.name == NULL || index < objc) {
729     Tcl_WrongNumArgs(interp, 2, objv,
730     "source-image ?-from x1 y1 x2 y2? ?-to x1 y1 x2 y2? ?-zoom x y? ?-subsample x y?");
731     return TCL_ERROR;
732     }
733    
734     /*
735     * Look for the source image and get a pointer to its image data.
736     * Check the values given for the -from option.
737     */
738    
739     if ((srcHandle = Tk_FindPhoto(interp, Tcl_GetString(options.name))) == NULL) {
740     Tcl_AppendResult(interp, "image \"",
741     Tcl_GetString(options.name), "\" doesn't",
742     " exist or is not a photo image", (char *) NULL);
743     return TCL_ERROR;
744     }
745     Tk_PhotoGetImage(srcHandle, &block);
746     if ((options.fromX2 > block.width) || (options.fromY2 > block.height)
747     || (options.fromX2 > block.width)
748     || (options.fromY2 > block.height)) {
749     Tcl_AppendResult(interp, "coordinates for -from option extend ",
750     "outside source image", (char *) NULL);
751     return TCL_ERROR;
752     }
753    
754     /*
755     * Fill in default values for unspecified parameters.
756     */
757    
758     if (((options.options & OPT_FROM) == 0) || (options.fromX2 < 0)) {
759     options.fromX2 = block.width;
760     options.fromY2 = block.height;
761     }
762     if (((options.options & OPT_TO) == 0) || (options.toX2 < 0)) {
763     width = options.fromX2 - options.fromX;
764     if (options.subsampleX > 0) {
765     width = (width + options.subsampleX - 1) / options.subsampleX;
766     } else if (options.subsampleX == 0) {
767     width = 0;
768     } else {
769     width = (width - options.subsampleX - 1) / -options.subsampleX;
770     }
771     options.toX2 = options.toX + width * options.zoomX;
772    
773     height = options.fromY2 - options.fromY;
774     if (options.subsampleY > 0) {
775     height = (height + options.subsampleY - 1)
776     / options.subsampleY;
777     } else if (options.subsampleY == 0) {
778     height = 0;
779     } else {
780     height = (height - options.subsampleY - 1)
781     / -options.subsampleY;
782     }
783     options.toY2 = options.toY + height * options.zoomY;
784     }
785    
786     /*
787     * Set the destination image size if the -shrink option was specified.
788     */
789    
790     if (options.options & OPT_SHRINK) {
791     ImgPhotoSetSize(masterPtr, options.toX2, options.toY2);
792     }
793    
794     /*
795     * Copy the image data over using Tk_PhotoPutZoomedBlock.
796     */
797    
798     block.pixelPtr += options.fromX * block.pixelSize
799     + options.fromY * block.pitch;
800     block.width = options.fromX2 - options.fromX;
801     block.height = options.fromY2 - options.fromY;
802     Tk_PhotoPutZoomedBlock((Tk_PhotoHandle) masterPtr, &block,
803     options.toX, options.toY, options.toX2 - options.toX,
804     options.toY2 - options.toY, options.zoomX, options.zoomY,
805     options.subsampleX, options.subsampleY);
806    
807     break;
808     }
809     case PHOTO_DATA: {
810     char *data;
811    
812     /*
813     * photo data command - first parse and check any options given.
814     */
815     Tk_ImageStringWriteProc *stringWriteProc = NULL;
816    
817     index = 2;
818     memset((VOID *) &options, 0, sizeof(options));
819     options.name = NULL;
820     options.format = NULL;
821     options.fromX = 0;
822     options.fromY = 0;
823     if (ParseSubcommandOptions(&options, interp,
824     OPT_FORMAT | OPT_FROM | OPT_GRAYSCALE | OPT_BACKGROUND,
825     &index, objc, objv) != TCL_OK) {
826     return TCL_ERROR;
827     }
828     if ((options.name != NULL) || (index < objc)) {
829     Tcl_WrongNumArgs(interp, 2, objv, "?options?");
830     return TCL_ERROR;
831     }
832     if ((options.fromX > masterPtr->width)
833     || (options.fromY > masterPtr->height)
834     || (options.fromX2 > masterPtr->width)
835     || (options.fromY2 > masterPtr->height)) {
836     Tcl_AppendResult(interp, "coordinates for -from option extend ",
837     "outside image", (char *) NULL);
838     return TCL_ERROR;
839     }
840    
841     /*
842     * Fill in default values for unspecified parameters.
843     */
844    
845     if (((options.options & OPT_FROM) == 0) || (options.fromX2 < 0)) {
846     options.fromX2 = masterPtr->width;
847     options.fromY2 = masterPtr->height;
848     }
849    
850     /*
851     * Search for an appropriate image string format handler.
852     */
853    
854     if (options.options & OPT_FORMAT) {
855     for (imageFormat = tsdPtr->formatList; imageFormat != NULL;
856     imageFormat = imageFormat->nextPtr) {
857     if ((strncasecmp(Tcl_GetString(options.format),
858     imageFormat->name, strlen(imageFormat->name)) == 0)) {
859     if (imageFormat->stringWriteProc != NULL) {
860     stringWriteProc = imageFormat->stringWriteProc;
861     break;
862     }
863     }
864     }
865     if (stringWriteProc == NULL) {
866     Tcl_AppendResult(interp, "image string format \"",
867     Tcl_GetString(options.format),
868     "\" is not supported", (char *) NULL);
869     return TCL_ERROR;
870     }
871     } else {
872     stringWriteProc = ImgStringWrite;
873     }
874    
875     /*
876     * Call the handler's string write procedure to write out
877     * the image.
878     */
879    
880     data = ImgGetPhoto(masterPtr, &block, &options);
881    
882     result = ((int (*) _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *formatString,
883     Tk_PhotoImageBlock *blockPtr, VOID *dummy))) stringWriteProc)
884     (interp, options.format, &block, (VOID *) NULL);
885     if (options.background) {
886     Tk_FreeColor(options.background);
887     }
888     if (data) {
889     ckfree(data);
890     }
891     return result;
892     break;
893     }
894     case PHOTO_GET: {
895     /*
896     * photo get command - first parse and check parameters.
897     */
898    
899     char string[TCL_INTEGER_SPACE * 3];
900    
901     if (objc != 4) {
902     Tcl_WrongNumArgs(interp, 2, objv, "x y");
903     return TCL_ERROR;
904     }
905     if ((Tcl_GetIntFromObj(interp, objv[2], &x) != TCL_OK)
906     || (Tcl_GetIntFromObj(interp, objv[3], &y) != TCL_OK)) {
907     return TCL_ERROR;
908     }
909     if ((x < 0) || (x >= masterPtr->width)
910     || (y < 0) || (y >= masterPtr->height)) {
911     Tcl_AppendResult(interp, Tcl_GetString(objv[0]), " get: ",
912     "coordinates out of range", (char *) NULL);
913     return TCL_ERROR;
914     }
915    
916     /*
917     * Extract the value of the desired pixel and format it as a string.
918     */
919    
920     pixelPtr = masterPtr->pix24 + (y * masterPtr->width + x) * 4;
921     sprintf(string, "%d %d %d", pixelPtr[0], pixelPtr[1],
922     pixelPtr[2]);
923     Tcl_AppendResult(interp, string, (char *) NULL);
924     break;
925     }
926     case PHOTO_PUT: {
927     /*
928     * photo put command - first parse the options and colors specified.
929     */
930    
931     index = 2;
932     memset((VOID *) &options, 0, sizeof(options));
933     options.name = NULL;
934     if (ParseSubcommandOptions(&options, interp, OPT_TO|OPT_FORMAT,
935     &index, objc, objv) != TCL_OK) {
936     return TCL_ERROR;
937     }
938     if ((options.name == NULL) || (index < objc)) {
939     Tcl_WrongNumArgs(interp, 2, objv, "data ?options?");
940     return TCL_ERROR;
941     }
942    
943     if (MatchStringFormat(interp, options.name ? objv[2]:NULL,
944     options.format, &imageFormat, &imageWidth,
945     &imageHeight, &oldformat) == TCL_OK) {
946     Tcl_Obj *format;
947     Tcl_Obj *data;
948     if (((options.options & OPT_TO) == 0) || (options.toX2 < 0)) {
949     options.toX2 = options.toX + imageWidth;
950     options.toY2 = options.toY + imageHeight;
951     }
952     if (imageWidth > options.toX2 - options.toX) {
953     imageWidth = options.toX2 - options.toX;
954     }
955     if (imageHeight > options.toY2 - options.toY) {
956     imageHeight = options.toY2 - options.toY;
957     }
958     format = options.format;
959     data = objv[2];
960     if (oldformat) {
961     if (format) {
962     format = (Tcl_Obj *) Tcl_GetString(format);
963     }
964     data = (Tcl_Obj *) Tcl_GetString(data);
965     }
966     if ((*imageFormat->stringReadProc)(interp, data,
967     format, (Tk_PhotoHandle) masterPtr,
968     0, 0, imageWidth, imageHeight, options.toX, options.toY)
969     != TCL_OK) {
970     return TCL_ERROR;
971     }
972     masterPtr->flags |= IMAGE_CHANGED;
973     return TCL_OK;
974     }
975     if (options.options & OPT_FORMAT) {
976     return TCL_ERROR;
977     }
978     Tcl_ResetResult(interp);
979     if (Tcl_SplitList(interp, Tcl_GetString(options.name),
980     &dataHeight, &srcArgv)
981     != TCL_OK) {
982     return TCL_ERROR;
983     }
984     tkwin = Tk_MainWindow(interp);
985     block.pixelPtr = NULL;
986     dataWidth = 0;
987     pixelPtr = NULL;
988     for (y = 0; y < dataHeight; ++y) {
989     if (Tcl_SplitList(interp, srcArgv[y], &listArgc, &listArgv)
990     != TCL_OK) {
991     break;
992     }
993     if (y == 0) {
994     dataWidth = listArgc;
995     pixelPtr = (unsigned char *) ckalloc((unsigned)
996     dataWidth * dataHeight * 3);
997     block.pixelPtr = pixelPtr;
998     } else {
999     if (listArgc != dataWidth) {
1000     Tcl_AppendResult(interp, "all elements of color list must",
1001     " have the same number of elements",
1002     (char *) NULL);
1003     ckfree((char *) listArgv);
1004     break;
1005     }
1006     }
1007     for (x = 0; x < dataWidth; ++x) {
1008     if (!XParseColor(Tk_Display(tkwin), Tk_Colormap(tkwin),
1009     listArgv[x], &color)) {
1010     Tcl_AppendResult(interp, "can't parse color \"",
1011     listArgv[x], "\"", (char *) NULL);
1012     break;
1013     }
1014     *pixelPtr++ = color.red >> 8;
1015     *pixelPtr++ = color.green >> 8;
1016     *pixelPtr++ = color.blue >> 8;
1017     }
1018     ckfree((char *) listArgv);
1019     if (x < dataWidth)
1020     break;
1021     }
1022     ckfree((char *) srcArgv);
1023     if (y < dataHeight || dataHeight == 0 || dataWidth == 0) {
1024     if (block.pixelPtr != NULL) {
1025     ckfree((char *) block.pixelPtr);
1026     }
1027     if (y < dataHeight) {
1028     return TCL_ERROR;
1029     }
1030     return TCL_OK;
1031     }
1032    
1033     /*
1034     * Fill in default values for the -to option, then
1035     * copy the block in using Tk_PhotoPutBlock.
1036     */
1037    
1038     if (((options.options & OPT_TO) == 0) || (options.toX2 < 0)) {
1039     options.toX2 = options.toX + dataWidth;
1040     options.toY2 = options.toY + dataHeight;
1041     }
1042     block.width = dataWidth;
1043     block.height = dataHeight;
1044     block.pitch = dataWidth * 3;
1045     block.pixelSize = 3;
1046     block.offset[0] = 0;
1047     block.offset[1] = 1;
1048     block.offset[2] = 2;
1049     block.offset[3] = 0;
1050     Tk_PhotoPutBlock((ClientData)masterPtr, &block,
1051     options.toX, options.toY, options.toX2 - options.toX,
1052     options.toY2 - options.toY);
1053     ckfree((char *) block.pixelPtr);
1054     break;
1055     }
1056     case PHOTO_READ: {
1057     /*
1058     * photo read command - first parse the options specified.
1059     */
1060    
1061     Tcl_Obj *format;
1062     index = 2;
1063     memset((VOID *) &options, 0, sizeof(options));
1064     options.name = NULL;
1065     options.format = NULL;
1066     if (ParseSubcommandOptions(&options, interp,
1067     OPT_FORMAT | OPT_FROM | OPT_TO | OPT_SHRINK,
1068     &index, objc, objv) != TCL_OK) {
1069     return TCL_ERROR;
1070     }
1071     if ((options.name == NULL) || (index < objc)) {
1072     Tcl_WrongNumArgs(interp, 2, objv,
1073     "fileName ?options?");
1074     return TCL_ERROR;
1075     }
1076    
1077     /*
1078     * Prevent file system access in safe interpreters.
1079     */
1080    
1081     if (Tcl_IsSafe(interp)) {
1082     Tcl_AppendResult(interp, "can't get image from a file in a",
1083     " safe interpreter", (char *) NULL);
1084     return TCL_ERROR;
1085     }
1086    
1087     /*
1088     * Open the image file and look for a handler for it.
1089     */
1090    
1091     chan = Tcl_OpenFileChannel(interp,
1092     Tcl_GetString(options.name), "r", 0);
1093     if (chan == NULL) {
1094     return TCL_ERROR;
1095     }
1096     if (Tcl_SetChannelOption(interp, chan, "-translation", "binary")
1097     != TCL_OK) {
1098     return TCL_ERROR;
1099     }
1100     if (Tcl_SetChannelOption(interp, chan, "-encoding", "binary")
1101     != TCL_OK) {
1102     return TCL_ERROR;
1103     }
1104    
1105     if (MatchFileFormat(interp, chan,
1106     Tcl_GetString(options.name), options.format,
1107     &imageFormat, &imageWidth, &imageHeight, &oldformat) != TCL_OK) {
1108     Tcl_Close(NULL, chan);
1109     return TCL_ERROR;
1110     }
1111    
1112     /*
1113     * Check the values given for the -from option.
1114     */
1115    
1116     if ((options.fromX > imageWidth) || (options.fromY > imageHeight)
1117     || (options.fromX2 > imageWidth)
1118     || (options.fromY2 > imageHeight)) {
1119     Tcl_AppendResult(interp, "coordinates for -from option extend ",
1120     "outside source image", (char *) NULL);
1121     Tcl_Close(NULL, chan);
1122     return TCL_ERROR;
1123     }
1124     if (((options.options & OPT_FROM) == 0) || (options.fromX2 < 0)) {
1125     width = imageWidth - options.fromX;
1126     height = imageHeight - options.fromY;
1127     } else {
1128     width = options.fromX2 - options.fromX;
1129     height = options.fromY2 - options.fromY;
1130     }
1131    
1132     /*
1133     * If the -shrink option was specified, set the size of the image.
1134     */
1135    
1136     if (options.options & OPT_SHRINK) {
1137     ImgPhotoSetSize(masterPtr, options.toX + width,
1138     options.toY + height);
1139     }
1140    
1141     /*
1142     * Call the handler's file read procedure to read the data
1143     * into the image.
1144     */
1145    
1146     format = options.format;
1147     if (oldformat && format) {
1148     format = (Tcl_Obj *) Tcl_GetString(format);
1149     }
1150     result = (*imageFormat->fileReadProc)(interp, chan,
1151     Tcl_GetString(options.name),
1152     format, (Tk_PhotoHandle) masterPtr, options.toX,
1153     options.toY, width, height, options.fromX, options.fromY);
1154     if (chan != NULL) {
1155     Tcl_Close(NULL, chan);
1156     }
1157     return result;
1158     break;
1159     }
1160     case PHOTO_REDITHER: {
1161     if (objc == 2) {
1162     /*
1163     * Call Dither if any part of the image is not correctly
1164     * dithered at present.
1165     */
1166    
1167     x = masterPtr->ditherX;
1168     y = masterPtr->ditherY;
1169     if (masterPtr->ditherX != 0) {
1170     Tk_DitherPhoto((Tk_PhotoHandle) masterPtr, x, y, masterPtr->width - x, 1);
1171     }
1172     if (masterPtr->ditherY < masterPtr->height) {
1173     x = 0;
1174     Tk_DitherPhoto((Tk_PhotoHandle)masterPtr, 0, masterPtr->ditherY, masterPtr->width,
1175     masterPtr->height - masterPtr->ditherY);
1176     }
1177    
1178     if (y < masterPtr->height) {
1179     /*
1180     * Tell the core image code that part of the image has changed.
1181     */
1182    
1183     Tk_ImageChanged(masterPtr->tkMaster, x, y,
1184     (masterPtr->width - x), (masterPtr->height - y),
1185     masterPtr->width, masterPtr->height);
1186     }
1187    
1188     } else {
1189     Tcl_WrongNumArgs(interp, 2, objv, (char *) NULL);
1190     return TCL_ERROR;
1191     }
1192     break;
1193     }
1194     case PHOTO_WRITE: {
1195     char *data;
1196     Tcl_Obj *format;
1197    
1198     /*
1199     * Prevent file system access in safe interpreters.
1200     */
1201    
1202     if (Tcl_IsSafe(interp)) {
1203     Tcl_AppendResult(interp, "can't write image to a file in a",
1204     " safe interpreter", (char *) NULL);
1205     return TCL_ERROR;
1206     }
1207    
1208     /*
1209     * photo write command - first parse and check any options given.
1210     */
1211    
1212     index = 2;
1213     memset((VOID *) &options, 0, sizeof(options));
1214     options.name = NULL;
1215     options.format = NULL;
1216     if (ParseSubcommandOptions(&options, interp,
1217     OPT_FORMAT | OPT_FROM | OPT_GRAYSCALE | OPT_BACKGROUND,
1218     &index, objc, objv) != TCL_OK) {
1219     return TCL_ERROR;
1220     }
1221     if ((options.name == NULL) || (index < objc)) {
1222     Tcl_WrongNumArgs(interp, 2, objv, "fileName ?options?");
1223     return TCL_ERROR;
1224     }
1225     if ((options.fromX > masterPtr->width)
1226     || (options.fromY > masterPtr->height)
1227     || (options.fromX2 > masterPtr->width)
1228     || (options.fromY2 > masterPtr->height)) {
1229     Tcl_AppendResult(interp, "coordinates for -from option extend ",
1230     "outside image", (char *) NULL);
1231     return TCL_ERROR;
1232     }
1233    
1234     /*
1235     * Fill in default values for unspecified parameters.
1236     */
1237    
1238     if (((options.options & OPT_FROM) == 0) || (options.fromX2 < 0)) {
1239     options.fromX2 = masterPtr->width;
1240     options.fromY2 = masterPtr->height;
1241     }
1242    
1243     /*
1244     * Search for an appropriate image file format handler,
1245     * and give an error if none is found.
1246     */
1247    
1248     matched = 0;
1249     for (imageFormat = tsdPtr->formatList; imageFormat != NULL;
1250     imageFormat = imageFormat->nextPtr) {
1251     if ((options.format == NULL)
1252     || (strncasecmp(Tcl_GetString(options.format),
1253     imageFormat->name, strlen(imageFormat->name)) == 0)) {
1254     matched = 1;
1255     if (imageFormat->fileWriteProc != NULL) {
1256     break;
1257     }
1258     }
1259     }
1260     if (imageFormat == NULL) {
1261     oldformat = 1;
1262     for (imageFormat = tsdPtr->oldFormatList; imageFormat != NULL;
1263     imageFormat = imageFormat->nextPtr) {
1264     if ((options.format == NULL)
1265     || (strncasecmp(Tcl_GetString(options.format),
1266     imageFormat->name, strlen(imageFormat->name)) == 0)) {
1267     matched = 1;
1268     if (imageFormat->fileWriteProc != NULL) {
1269     break;
1270     }
1271     }
1272     }
1273     }
1274     if (imageFormat == NULL) {
1275     if (options.format == NULL) {
1276     Tcl_AppendResult(interp, "no available image file format ",
1277     "has file writing capability", (char *) NULL);
1278     } else if (!matched) {
1279     Tcl_AppendResult(interp, "image file format \"",
1280     Tcl_GetString(options.format),
1281     "\" is unknown", (char *) NULL);
1282     } else {
1283     Tcl_AppendResult(interp, "image file format \"",
1284     Tcl_GetString(options.format),
1285     "\" has no file writing capability",
1286     (char *) NULL);
1287     }
1288     return TCL_ERROR;
1289     }
1290    
1291     /*
1292     * Call the handler's file write procedure to write out
1293     * the image.
1294     */
1295    
1296     data = ImgGetPhoto(masterPtr, &block, &options);
1297     format = options.format;
1298     if (oldformat && format) {
1299     format = (Tcl_Obj *) Tcl_GetString(options.format);
1300     }
1301     result = (*imageFormat->fileWriteProc)(interp,
1302     Tcl_GetString(options.name),
1303     format, &block);
1304     if (options.background) {
1305     Tk_FreeColor(options.background);
1306     }
1307     if (data) {
1308     ckfree(data);
1309     }
1310     return result;
1311     break;
1312     }
1313     }
1314    
1315     return TCL_OK;
1316     }
1317    
1318     /*
1319     *----------------------------------------------------------------------
1320     *
1321     * ParseSubcommandOptions --
1322     *
1323     * This procedure is invoked to process one of the options
1324     * which may be specified for the photo image subcommands,
1325     * namely, -from, -to, -zoom, -subsample, -format, and -shrink.
1326     *
1327     * Results:
1328     * A standard Tcl result.
1329     *
1330     * Side effects:
1331     * Fields in *optPtr get filled in.
1332     *
1333     *----------------------------------------------------------------------
1334     */
1335    
1336     static int
1337     ParseSubcommandOptions(optPtr, interp, allowedOptions, optIndexPtr, objc, objv)
1338     struct SubcommandOptions *optPtr;
1339     /* Information about the options specified
1340     * and the values given is returned here. */
1341     Tcl_Interp *interp; /* Interpreter to use for reporting errors. */
1342     int allowedOptions; /* Indicates which options are valid for
1343     * the current command. */
1344     int *optIndexPtr; /* Points to a variable containing the
1345     * current index in objv; this variable is
1346     * updated by this procedure. */
1347     int objc; /* Number of arguments in objv[]. */
1348     Tcl_Obj *CONST objv[]; /* Arguments to be parsed. */
1349     {
1350     int index, c, bit, currentBit;
1351     int length;
1352     char *option, **listPtr;
1353     int values[4];
1354     int numValues, maxValues, argIndex;
1355    
1356     for (index = *optIndexPtr; index < objc; *optIndexPtr = ++index) {
1357     /*
1358     * We can have one value specified without an option;
1359     * it goes into optPtr->name.
1360     */
1361    
1362     option = Tcl_GetStringFromObj(objv[index], &length);
1363     if (option[0] != '-') {
1364     if (optPtr->name == NULL) {
1365     optPtr->name = objv[index];
1366     continue;
1367     }
1368     break;
1369     }
1370    
1371     /*
1372     * Work out which option this is.
1373     */
1374    
1375     c = option[0];
1376     bit = 0;
1377     currentBit = 1;
1378     for (listPtr = optionNames; *listPtr != NULL; ++listPtr) {
1379     if ((c == *listPtr[0])
1380     && (strncmp(option, *listPtr, (size_t) length) == 0)) {
1381     if (bit != 0) {
1382     bit = 0; /* An ambiguous option. */
1383     break;
1384     }
1385     bit = currentBit;
1386     }
1387     currentBit <<= 1;
1388     }
1389    
1390     /*
1391     * If this option is not recognized and allowed, put
1392     * an error message in the interpreter and return.
1393     */
1394    
1395     if ((allowedOptions & bit) == 0) {
1396     Tcl_AppendResult(interp, "unrecognized option \"",
1397     Tcl_GetString(objv[index]),
1398     "\": must be ", (char *)NULL);
1399     bit = 1;
1400     for (listPtr = optionNames; *listPtr != NULL; ++listPtr) {
1401     if ((allowedOptions & bit) != 0) {
1402     if ((allowedOptions & (bit - 1)) != 0) {
1403     Tcl_AppendResult(interp, ", ", (char *) NULL);
1404     if ((allowedOptions & ~((bit << 1) - 1)) == 0) {
1405     Tcl_AppendResult(interp, "or ", (char *) NULL);
1406     }
1407     }
1408     Tcl_AppendResult(interp, *listPtr, (char *) NULL);
1409     }
1410     bit <<= 1;
1411     }
1412     return TCL_ERROR;
1413     }
1414    
1415     /*
1416     * For the -from, -to, -zoom and -subsample options,
1417     * parse the values given. Report an error if too few
1418     * or too many values are given.
1419     */
1420    
1421     if (bit == OPT_BACKGROUND) {
1422     /*
1423     * The -background option takes a single XColor value.
1424     */
1425    
1426     if (index + 1 < objc) {
1427     *optIndexPtr = ++index;
1428     optPtr->background = Tk_GetColor(interp, Tk_MainWindow(interp),
1429     Tk_GetUid(Tcl_GetString(objv[index])));
1430     if (!optPtr->background) {
1431     return TCL_ERROR;
1432     }
1433     } else {
1434     Tcl_AppendResult(interp, "the \"-background\" option ",
1435     "requires a value", (char *) NULL);
1436     return TCL_ERROR;
1437     }
1438     } else if (bit == OPT_FORMAT) {
1439     /*
1440     * The -format option takes a single string value.
1441     */
1442    
1443     if (index + 1 < objc) {
1444     *optIndexPtr = ++index;
1445     optPtr->format = objv[index];
1446     } else {
1447     Tcl_AppendResult(interp, "the \"-format\" option ",
1448     "requires a value", (char *) NULL);
1449     return TCL_ERROR;
1450     }
1451     } else if ((bit != OPT_SHRINK) && (bit != OPT_GRAYSCALE)) {
1452     char *val;
1453     maxValues = ((bit == OPT_FROM) || (bit == OPT_TO))? 4: 2;
1454     argIndex = index + 1;
1455     for (numValues = 0; numValues < maxValues; ++numValues) {
1456     if (argIndex >= objc) {
1457     break;
1458     }
1459     val = Tcl_GetString(objv[argIndex]);
1460     if ((argIndex < objc) && (isdigit(UCHAR(val[0]))
1461     || ((val[0] == '-') && isdigit(UCHAR(val[1]))))) {
1462     if (Tcl_GetInt(interp, val, &values[numValues])
1463     != TCL_OK) {
1464     return TCL_ERROR;
1465     }
1466     } else {
1467     break;
1468     }
1469     ++argIndex;
1470     }
1471    
1472     if (numValues == 0) {
1473     Tcl_AppendResult(interp, "the \"", option, "\" option ",
1474     "requires one ", maxValues == 2? "or two": "to four",
1475     " integer values", (char *) NULL);
1476     return TCL_ERROR;
1477     }
1478     *optIndexPtr = (index += numValues);
1479    
1480     /*
1481     * Y values default to the corresponding X value if not specified.
1482     */
1483    
1484     if (numValues == 1) {
1485     values[1] = values[0];
1486     }
1487     if (numValues == 3) {
1488     values[3] = values[2];
1489     }
1490    
1491     /*
1492     * Check the values given and put them in the appropriate
1493     * field of the SubcommandOptions structure.
1494     */
1495    
1496     switch (bit) {
1497     case OPT_FROM:
1498     if ((values[0] < 0) || (values[1] < 0) || ((numValues > 2)
1499     && ((values[2] < 0) || (values[3] < 0)))) {
1500     Tcl_AppendResult(interp, "value(s) for the -from",
1501     " option must be non-negative", (char *) NULL);
1502     return TCL_ERROR;
1503     }
1504     if (numValues <= 2) {
1505     optPtr->fromX = values[0];
1506     optPtr->fromY = values[1];
1507     optPtr->fromX2 = -1;
1508     optPtr->fromY2 = -1;
1509     } else {
1510     optPtr->fromX = MIN(values[0], values[2]);
1511     optPtr->fromY = MIN(values[1], values[3]);
1512     optPtr->fromX2 = MAX(values[0], values[2]);
1513     optPtr->fromY2 = MAX(values[1], values[3]);
1514     }
1515     break;
1516     case OPT_SUBSAMPLE:
1517     optPtr->subsampleX = values[0];
1518     optPtr->subsampleY = values[1];
1519     break;
1520     case OPT_TO:
1521     if ((values[0] < 0) || (values[1] < 0) || ((numValues > 2)
1522     && ((values[2] < 0) || (values[3] < 0)))) {
1523     Tcl_AppendResult(interp, "value(s) for the -to",
1524     " option must be non-negative", (char *) NULL);
1525     return TCL_ERROR;
1526     }
1527     if (numValues <= 2) {
1528     optPtr->toX = values[0];
1529     optPtr->toY = values[1];
1530     optPtr->toX2 = -1;
1531     optPtr->toY2 = -1;
1532     } else {
1533     optPtr->toX = MIN(values[0], values[2]);
1534     optPtr->toY = MIN(values[1], values[3]);
1535     optPtr->toX2 = MAX(values[0], values[2]);
1536     optPtr->toY2 = MAX(values[1], values[3]);
1537     }
1538     break;
1539     case OPT_ZOOM:
1540     if ((values[0] <= 0) || (values[1] <= 0)) {
1541     Tcl_AppendResult(interp, "value(s) for the -zoom",
1542     " option must be positive", (char *) NULL);
1543     return TCL_ERROR;
1544     }
1545     optPtr->zoomX = values[0];
1546     optPtr->zoomY = values[1];
1547     break;
1548     }
1549     }
1550    
1551     /*
1552     * Remember that we saw this option.
1553     */
1554    
1555     optPtr->options |= bit;
1556     }
1557    
1558     return TCL_OK;
1559     }
1560    
1561     /*
1562     *----------------------------------------------------------------------
1563     *
1564     * ImgPhotoConfigureMaster --
1565     *
1566     * This procedure is called when a photo image is created or
1567     * reconfigured. It processes configuration options and resets
1568     * any instances of the image.
1569     *
1570     * Results:
1571     * A standard Tcl return value. If TCL_ERROR is returned then
1572     * an error message is left in the masterPtr->interp's result.
1573     *
1574     * Side effects:
1575     * Existing instances of the image will be redisplayed to match
1576     * the new configuration options.
1577     *
1578     *----------------------------------------------------------------------
1579     */
1580    
1581     static int
1582     ImgPhotoConfigureMaster(interp, masterPtr, objc, objv, flags)
1583     Tcl_Interp *interp; /* Interpreter to use for reporting errors. */
1584     PhotoMaster *masterPtr; /* Pointer to data structure describing
1585     * overall photo image to (re)configure. */
1586     int objc; /* Number of entries in objv. */
1587     Tcl_Obj *CONST objv[]; /* Pairs of configuration options for image. */
1588     int flags; /* Flags to pass to Tk_ConfigureWidget,
1589     * such as TK_CONFIG_ARGV_ONLY. */
1590     {
1591     PhotoInstance *instancePtr;
1592     char *oldFileString, *oldPaletteString;
1593     Tcl_Obj *oldData, *data = NULL, *oldFormat, *format = NULL;
1594     int length, i, j;
1595     double oldGamma;
1596     int result;
1597     Tcl_Channel chan;
1598     Tk_PhotoImageFormat *imageFormat;
1599     int imageWidth, imageHeight;
1600     char **args;
1601     int oldformat;
1602     Tcl_Obj *tempdata, *tempformat;
1603    
1604     args = (char **) ckalloc((objc + 1) * sizeof(char *));
1605     for (i = 0, j = 0; i < objc; i++,j++) {
1606     args[j] = Tcl_GetStringFromObj(objv[i], &length);
1607     if ((length > 1) && (args[j][0] == '-')) {
1608     if ((args[j][1] == 'd') &&
1609     !strncmp(args[j],"-data", (size_t) length)) {
1610     if (i < objc) {
1611     data = objv[++i];
1612     j--;
1613     }
1614     } else if ((args[j][1] == 'f') &&
1615     !strncmp(args[j],"-format", (size_t) length)) {
1616     if (i < objc) {
1617     format = objv[++i];
1618     j--;
1619     }
1620     }
1621     }
1622     }
1623    
1624     /*
1625     * Save the current values for fileString and dataString, so we
1626     * can tell if the user specifies them anew.
1627     * IMPORTANT: if the format changes we have to interpret
1628     * "-file" and "-data" again as well!!!!!!! It might be
1629     * that the format string influences how "-data" or "-file"
1630     * is interpreted.
1631     */
1632    
1633     oldFileString = masterPtr->fileString;
1634     oldData = (oldFileString == NULL) ? masterPtr->dataString: NULL;
1635     oldFormat = masterPtr->format;
1636     oldPaletteString = masterPtr->palette;
1637     oldGamma = masterPtr->gamma;
1638    
1639     /*
1640     * Process the configuration options specified.
1641     */
1642    
1643     if (Tk_ConfigureWidget(interp, Tk_MainWindow(interp), configSpecs,
1644     j, args, (char *) masterPtr, flags) != TCL_OK) {
1645     ckfree((char *) args);
1646     return TCL_ERROR;
1647     }
1648     ckfree((char *) args);
1649    
1650     /*
1651     * Regard the empty string for -file, -data or -format as the null
1652     * value.
1653     */
1654    
1655     if ((masterPtr->fileString != NULL) && (masterPtr->fileString[0] == 0)) {
1656     ckfree(masterPtr->fileString);
1657     masterPtr->fileString = NULL;
1658     }
1659     if (data) {
1660     if (data->length
1661     || (data->typePtr == Tcl_GetObjType("bytearray")
1662     && data->internalRep.otherValuePtr != NULL)) {
1663     Tcl_IncrRefCount(data);
1664     } else {
1665     data = NULL;
1666     }
1667     if (masterPtr->dataString) {
1668     Tcl_DecrRefCount(masterPtr->dataString);
1669     }
1670     masterPtr->dataString = data;
1671     }
1672     if (format) {
1673     if (format->length) {
1674     Tcl_IncrRefCount(format);
1675     } else {
1676     format = NULL;
1677     }
1678     if (masterPtr->format) {
1679     Tcl_DecrRefCount(masterPtr->format);
1680     }
1681     masterPtr->format = format;
1682     }
1683     /*
1684     * Set the image to the user-requested size, if any,
1685     * and make sure storage is correctly allocated for this image.
1686     */
1687    
1688     ImgPhotoSetSize(masterPtr, masterPtr->width, masterPtr->height);
1689    
1690     /*
1691     * Read in the image from the file or string if the user has
1692     * specified the -file or -data option.
1693     */
1694    
1695     if ((masterPtr->fileString != NULL)
1696     && ((masterPtr->fileString != oldFileString)
1697     || (masterPtr->format != oldFormat))) {
1698    
1699     /*
1700     * Prevent file system access in a safe interpreter.
1701     */
1702    
1703     if (Tcl_IsSafe(interp)) {
1704     Tcl_AppendResult(interp, "can't get image from a file in a",
1705     " safe interpreter", (char *) NULL);
1706     return TCL_ERROR;
1707     }
1708    
1709     chan = Tcl_OpenFileChannel(interp, masterPtr->fileString, "r", 0);
1710     if (chan == NULL) {
1711     return TCL_ERROR;
1712     }
1713     if (Tcl_SetChannelOption(interp, chan, "-translation", "binary")
1714     != TCL_OK) {
1715     return TCL_ERROR;
1716     }
1717     if (Tcl_SetChannelOption(interp, chan, "-encoding", "binary")
1718     != TCL_OK) {
1719     return TCL_ERROR;
1720     }
1721     if (MatchFileFormat(interp, chan, masterPtr->fileString,
1722     masterPtr->format, &imageFormat, &imageWidth,
1723     &imageHeight, &oldformat) != TCL_OK) {
1724     Tcl_Close(NULL, chan);
1725     return TCL_ERROR;
1726     }
1727     ImgPhotoSetSize(masterPtr, imageWidth, imageHeight);
1728     tempformat = masterPtr->format;
1729     if (oldformat && tempformat) {
1730     tempformat = (Tcl_Obj *) Tcl_GetString(tempformat);
1731     }
1732     result = (*imageFormat->fileReadProc)(interp, chan,
1733     masterPtr->fileString, tempformat,
1734     (Tk_PhotoHandle) masterPtr, 0, 0,
1735     imageWidth, imageHeight, 0, 0);
1736     Tcl_Close(NULL, chan);
1737     if (result != TCL_OK) {
1738     return TCL_ERROR;
1739     }
1740    
1741     Tcl_ResetResult(interp);
1742     masterPtr->flags |= IMAGE_CHANGED;
1743     }
1744    
1745     if ((masterPtr->fileString == NULL) && (masterPtr->dataString != NULL)
1746     && ((masterPtr->dataString != oldData)
1747     || (masterPtr->format != oldFormat))) {
1748    
1749     if (MatchStringFormat(interp, masterPtr->dataString,
1750     masterPtr->format, &imageFormat, &imageWidth,
1751     &imageHeight, &oldformat) != TCL_OK) {
1752     return TCL_ERROR;
1753     }
1754     ImgPhotoSetSize(masterPtr, imageWidth, imageHeight);
1755     tempformat = masterPtr->format;
1756     tempdata = masterPtr->dataString;
1757     if (oldformat) {
1758     if (tempformat) {
1759     tempformat = (Tcl_Obj *) Tcl_GetString(tempformat);
1760     }
1761     tempdata = (Tcl_Obj *) Tcl_GetString(tempdata);
1762     }
1763     if ((*imageFormat->stringReadProc)(interp, tempdata,
1764     tempformat, (Tk_PhotoHandle) masterPtr,
1765     0, 0, imageWidth, imageHeight, 0, 0) != TCL_OK) {
1766     return TCL_ERROR;
1767     }
1768    
1769     Tcl_ResetResult(interp);
1770     masterPtr->flags |= IMAGE_CHANGED;
1771     }
1772    
1773     /*
1774     * Enforce a reasonable value for gamma.
1775     */
1776    
1777     if (masterPtr->gamma <= 0) {
1778     masterPtr->gamma = 1.0;
1779     }
1780    
1781     if ((masterPtr->gamma != oldGamma)
1782     || (masterPtr->palette != oldPaletteString)) {
1783     masterPtr->flags |= IMAGE_CHANGED;
1784     }
1785    
1786     /*
1787     * Cycle through all of the instances of this image, regenerating
1788     * the information for each instance. Then force the image to be
1789     * redisplayed everywhere that it is used.
1790     */
1791    
1792     for (instancePtr = masterPtr->instancePtr; instancePtr != NULL;
1793     instancePtr = instancePtr->nextPtr) {
1794     ImgPhotoConfigureInstance(instancePtr);
1795     }
1796    
1797     /*
1798     * Inform the generic image code that the image
1799     * has (potentially) changed.
1800     */
1801    
1802     Tk_ImageChanged(masterPtr->tkMaster, 0, 0, masterPtr->width,
1803     masterPtr->height, masterPtr->width, masterPtr->height);
1804     masterPtr->flags &= ~IMAGE_CHANGED;
1805    
1806     return TCL_OK;
1807     }
1808    
1809     /*
1810     *----------------------------------------------------------------------
1811     *
1812     * ImgPhotoConfigureInstance --
1813     *
1814     * This procedure is called to create displaying information for
1815     * a photo image instance based on the configuration information
1816     * in the master. It is invoked both when new instances are
1817     * created and when the master is reconfigured.
1818     *
1819     * Results:
1820     * None.
1821     *
1822     * Side effects:
1823     * Generates errors via Tcl_BackgroundError if there are problems
1824     * in setting up the instance.
1825     *
1826     *----------------------------------------------------------------------
1827     */
1828    
1829     static void
1830     ImgPhotoConfigureInstance(instancePtr)
1831     PhotoInstance *instancePtr; /* Instance to reconfigure. */
1832     {
1833     PhotoMaster *masterPtr = instancePtr->masterPtr;
1834     XImage *imagePtr;
1835     int bitsPerPixel;
1836     ColorTable *colorTablePtr;
1837     XRectangle validBox;
1838    
1839     /*
1840     * If the -palette configuration option has been set for the master,
1841     * use the value specified for our palette, but only if it is
1842     * a valid palette for our windows. Use the gamma value specified
1843     * the master.
1844     */
1845    
1846     if ((masterPtr->palette && masterPtr->palette[0])
1847     && IsValidPalette(instancePtr, masterPtr->palette)) {
1848     instancePtr->palette = masterPtr->palette;
1849     } else {
1850     instancePtr->palette = instancePtr->defaultPalette;
1851     }
1852     instancePtr->gamma = masterPtr->gamma;
1853    
1854     /*
1855     * If we don't currently have a color table, or if the one we
1856     * have no longer applies (e.g. because our palette or gamma
1857     * has changed), get a new one.
1858     */
1859    
1860     colorTablePtr = instancePtr->colorTablePtr;
1861     if ((colorTablePtr == NULL)
1862     || (instancePtr->colormap != colorTablePtr->id.colormap)
1863     || (instancePtr->palette != colorTablePtr->id.palette)
1864     || (instancePtr->gamma != colorTablePtr->id.gamma)) {
1865     /*
1866     * Free up our old color table, and get a new one.
1867     */
1868    
1869     if (colorTablePtr != NULL) {
1870     colorTablePtr->liveRefCount -= 1;
1871     FreeColorTable(colorTablePtr, 0);
1872     }
1873     GetColorTable(instancePtr);
1874    
1875     /*
1876     * Create a new XImage structure for sending data to
1877     * the X server, if necessary.
1878     */
1879    
1880     if (instancePtr->colorTablePtr->flags & BLACK_AND_WHITE) {
1881     bitsPerPixel = 1;
1882     } else {
1883     bitsPerPixel = instancePtr->visualInfo.depth;
1884     }
1885    
1886     if ((instancePtr->imagePtr == NULL)
1887     || (instancePtr->imagePtr->bits_per_pixel != bitsPerPixel)) {
1888     if (instancePtr->imagePtr != NULL) {
1889     XFree((char *) instancePtr->imagePtr);
1890     }
1891     imagePtr = XCreateImage(instancePtr->display,
1892     instancePtr->visualInfo.visual, (unsigned) bitsPerPixel,
1893     (bitsPerPixel > 1? ZPixmap: XYBitmap), 0, (char *) NULL,
1894     1, 1, 32, 0);
1895     instancePtr->imagePtr = imagePtr;
1896    
1897     /*
1898     * Determine the endianness of this machine.
1899     * We create images using the local host's endianness, rather
1900     * than the endianness of the server; otherwise we would have
1901     * to byte-swap any 16 or 32 bit values that we store in the
1902     * image in those situations where the server's endianness
1903     * is different from ours.
1904     */
1905    
1906     if (imagePtr != NULL) {
1907     union {
1908     int i;
1909     char c[sizeof(int)];
1910     } kludge;
1911    
1912     imagePtr->bitmap_unit = sizeof(pixel) * NBBY;
1913     kludge.i = 0;
1914     kludge.c[0] = 1;
1915     imagePtr->byte_order = (kludge.i == 1) ? LSBFirst : MSBFirst;
1916     _XInitImageFuncPtrs(imagePtr);
1917     }
1918     }
1919     }
1920    
1921     /*
1922     * If the user has specified a width and/or height for the master
1923     * which is different from our current width/height, set the size
1924     * to the values specified by the user. If we have no pixmap, we
1925     * do this also, since it has the side effect of allocating a
1926     * pixmap for us.
1927     */
1928    
1929     if ((instancePtr->pixels == None) || (instancePtr->error == NULL)
1930     || (instancePtr->width != masterPtr->width)
1931     || (instancePtr->height != masterPtr->height)) {
1932     ImgPhotoInstanceSetSize(instancePtr);
1933     }
1934    
1935     /*
1936     * Redither this instance if necessary.
1937     */
1938    
1939     if ((masterPtr->flags & IMAGE_CHANGED)
1940     || (instancePtr->colorTablePtr != colorTablePtr)) {
1941     TkClipBox(masterPtr->validRegion, &validBox);
1942     if ((validBox.width > 0) && (validBox.height > 0)) {
1943     DitherInstance(instancePtr, validBox.x, validBox.y,
1944     validBox.width, validBox.height);
1945     }
1946     }
1947    
1948     }
1949    
1950     /*
1951     *----------------------------------------------------------------------
1952     *
1953     * ImgPhotoGet --
1954     *
1955     * This procedure is called for each use of a photo image in a
1956     * widget.
1957     *
1958     * Results:
1959     * The return value is a token for the instance, which is passed
1960     * back to us in calls to ImgPhotoDisplay and ImgPhotoFree.
1961     *
1962     * Side effects:
1963     * A data structure is set up for the instance (or, an existing
1964     * instance is re-used for the new one).
1965     *
1966     *----------------------------------------------------------------------
1967     */
1968    
1969     static ClientData
1970     ImgPhotoGet(tkwin, masterData)
1971     Tk_Window tkwin; /* Window in which the instance will be
1972     * used. */
1973     ClientData masterData; /* Pointer to our master structure for the
1974     * image. */
1975     {
1976     PhotoMaster *masterPtr = (PhotoMaster *) masterData;
1977     PhotoInstance *instancePtr;
1978     Colormap colormap;
1979     int mono, nRed, nGreen, nBlue;
1980     XVisualInfo visualInfo, *visInfoPtr;
1981     XRectangle validBox;
1982     char buf[TCL_INTEGER_SPACE * 3];
1983     int numVisuals;
1984     XColor *white, *black;
1985     XGCValues gcValues;
1986    
1987     /*
1988     * Table of "best" choices for palette for PseudoColor displays
1989     * with between 3 and 15 bits/pixel.
1990     */
1991    
1992     static int paletteChoice[13][3] = {
1993     /* #red, #green, #blue */
1994     {2, 2, 2, /* 3 bits, 8 colors */},
1995     {2, 3, 2, /* 4 bits, 12 colors */},
1996     {3, 4, 2, /* 5 bits, 24 colors */},
1997     {4, 5, 3, /* 6 bits, 60 colors */},
1998     {5, 6, 4, /* 7 bits, 120 colors */},
1999     {7, 7, 4, /* 8 bits, 198 colors */},
2000     {8, 10, 6, /* 9 bits, 480 colors */},
2001     {10, 12, 8, /* 10 bits, 960 colors */},
2002     {14, 15, 9, /* 11 bits, 1890 colors */},
2003     {16, 20, 12, /* 12 bits, 3840 colors */},
2004     {20, 24, 16, /* 13 bits, 7680 colors */},
2005     {26, 30, 20, /* 14 bits, 15600 colors */},
2006     {32, 32, 30, /* 15 bits, 30720 colors */}
2007     };
2008    
2009     /*
2010     * See if there is already an instance for windows using
2011     * the same colormap. If so then just re-use it.
2012     */
2013    
2014     colormap = Tk_Colormap(tkwin);
2015     for (instancePtr = masterPtr->instancePtr; instancePtr != NULL;
2016     instancePtr = instancePtr->nextPtr) {
2017     if ((colormap == instancePtr->colormap)
2018     && (Tk_Display(tkwin) == instancePtr->display)) {
2019    
2020     /*
2021     * Re-use this instance.
2022     */
2023    
2024     if (instancePtr->refCount == 0) {
2025     /*
2026     * We are resurrecting this instance.
2027     */
2028    
2029     Tcl_CancelIdleCall(DisposeInstance, (ClientData) instancePtr);
2030     if (instancePtr->colorTablePtr != NULL) {
2031     FreeColorTable(instancePtr->colorTablePtr, 0);
2032     }
2033     GetColorTable(instancePtr);
2034     }
2035     instancePtr->refCount++;
2036     return (ClientData) instancePtr;
2037     }
2038     }
2039    
2040     /*
2041     * The image isn't already in use in a window with the same colormap.
2042     * Make a new instance of the image.
2043     */
2044    
2045     instancePtr = (PhotoInstance *) ckalloc(sizeof(PhotoInstance));
2046     instancePtr->masterPtr = masterPtr;
2047     instancePtr->display = Tk_Display(tkwin);
2048     instancePtr->colormap = Tk_Colormap(tkwin);
2049     Tk_PreserveColormap(instancePtr->display, instancePtr->colormap);
2050     instancePtr->refCount = 1;
2051     instancePtr->colorTablePtr = NULL;
2052     instancePtr->pixels = None;
2053     instancePtr->error = NULL;
2054     instancePtr->width = 0;
2055     instancePtr->height = 0;
2056     instancePtr->imagePtr = 0;
2057     instancePtr->nextPtr = masterPtr->instancePtr;
2058     masterPtr->instancePtr = instancePtr;
2059    
2060     /*
2061     * Obtain information about the visual and decide on the
2062     * default palette.
2063     */
2064    
2065     visualInfo.screen = Tk_ScreenNumber(tkwin);
2066     visualInfo.visualid = XVisualIDFromVisual(Tk_Visual(tkwin));
2067     visInfoPtr = XGetVisualInfo(Tk_Display(tkwin),
2068     VisualScreenMask | VisualIDMask, &visualInfo, &numVisuals);
2069     nRed = 2;
2070     nGreen = nBlue = 0;
2071     mono = 1;
2072     if (visInfoPtr != NULL) {
2073     instancePtr->visualInfo = *visInfoPtr;
2074     switch (visInfoPtr->class) {
2075     case DirectColor:
2076     case TrueColor:
2077     nRed = 1 << CountBits(visInfoPtr->red_mask);
2078     nGreen = 1 << CountBits(visInfoPtr->green_mask);
2079     nBlue = 1 << CountBits(visInfoPtr->blue_mask);
2080     mono = 0;
2081     break;
2082     case PseudoColor:
2083     case StaticColor:
2084     if (visInfoPtr->depth > 15) {
2085     nRed = 32;
2086     nGreen = 32;
2087     nBlue = 32;
2088     mono = 0;
2089     } else if (visInfoPtr->depth >= 3) {
2090     int *ip = paletteChoice[visInfoPtr->depth - 3];
2091    
2092     nRed = ip[0];
2093     nGreen = ip[1];
2094     nBlue = ip[2];
2095     mono = 0;
2096     }
2097     break;
2098     case GrayScale:
2099     case StaticGray:
2100     nRed = 1 << visInfoPtr->depth;
2101     break;
2102     }
2103     XFree((char *) visInfoPtr);
2104    
2105     } else {
2106     panic("ImgPhotoGet couldn't find visual for window");
2107     }
2108    
2109     sprintf(buf, ((mono) ? "%d": "%d/%d/%d"), nRed, nGreen, nBlue);
2110     instancePtr->defaultPalette = Tk_GetUid(buf);
2111    
2112     /*
2113     * Make a GC with background = black and foreground = white.
2114     */
2115    
2116     white = Tk_GetColor(masterPtr->interp, tkwin, "white");
2117     black = Tk_GetColor(masterPtr->interp, tkwin, "black");
2118     gcValues.foreground = (white != NULL)? white->pixel:
2119     WhitePixelOfScreen(Tk_Screen(tkwin));
2120     gcValues.background = (black != NULL)? black->pixel:
2121     BlackPixelOfScreen(Tk_Screen(tkwin));
2122     gcValues.graphics_exposures = False;
2123     instancePtr->gc = Tk_GetGC(tkwin,
2124     GCForeground|GCBackground|GCGraphicsExposures, &gcValues);
2125    
2126     /*
2127     * Set configuration options and finish the initialization of the instance.
2128     */
2129    
2130     ImgPhotoConfigureInstance(instancePtr);
2131    
2132     /*
2133     * If this is the first instance, must set the size of the image.
2134     */
2135    
2136     if (instancePtr->nextPtr == NULL) {
2137     Tk_ImageChanged(masterPtr->tkMaster, 0, 0, 0, 0,
2138     masterPtr->width, masterPtr->height);
2139     }
2140    
2141     /*
2142     * Dither the image to fill in this instance's pixmap.
2143     */
2144    
2145     TkClipBox(masterPtr->validRegion, &validBox);
2146     if ((validBox.width > 0) && (validBox.height > 0)) {
2147     DitherInstance(instancePtr, validBox.x, validBox.y, validBox.width,
2148     validBox.height);
2149     }
2150    
2151     return (ClientData) instancePtr;
2152     }
2153    
2154     /*
2155     *----------------------------------------------------------------------
2156     *
2157     * ImgPhotoDisplay --
2158     *
2159     * This procedure is invoked to draw a photo image.
2160     *
2161     * Results:
2162     * None.
2163     *
2164     * Side effects:
2165     * A portion of the image gets rendered in a pixmap or window.
2166     *
2167     *----------------------------------------------------------------------
2168     */
2169    
2170     static void
2171     ImgPhotoDisplay(clientData, display, drawable, imageX, imageY, width,
2172     height, drawableX, drawableY)
2173     ClientData clientData; /* Pointer to PhotoInstance structure for
2174     * for instance to be displayed. */
2175     Display *display; /* Display on which to draw image. */
2176     Drawable drawable; /* Pixmap or window in which to draw image. */
2177     int imageX, imageY; /* Upper-left corner of region within image
2178     * to draw. */
2179     int width, height; /* Dimensions of region within image to draw. */
2180     int drawableX, drawableY; /* Coordinates within drawable that
2181     * correspond to imageX and imageY. */
2182     {
2183     PhotoInstance *instancePtr = (PhotoInstance *) clientData;
2184    
2185     /*
2186     * If there's no pixmap, it means that an error occurred
2187     * while creating the image instance so it can't be displayed.
2188     */
2189    
2190     if (instancePtr->pixels == None) {
2191     return;
2192     }
2193    
2194     /*
2195     * masterPtr->region describes which parts of the image contain
2196     * valid data. We set this region as the clip mask for the gc,
2197     * setting its origin appropriately, and use it when drawing the
2198     * image.
2199     */
2200    
2201     TkSetRegion(display, instancePtr->gc, instancePtr->masterPtr->validRegion);
2202     XSetClipOrigin(display, instancePtr->gc, drawableX - imageX,
2203     drawableY - imageY);
2204     XCopyArea(display, instancePtr->pixels, drawable, instancePtr->gc,
2205     imageX, imageY, (unsigned) width, (unsigned) height,
2206     drawableX, drawableY);
2207     XSetClipMask(display, instancePtr->gc, None);
2208     XSetClipOrigin(display, instancePtr->gc, 0, 0);
2209     }
2210    
2211     /*
2212     *----------------------------------------------------------------------
2213     *
2214     * ImgPhotoFree --
2215     *
2216     * This procedure is called when a widget ceases to use a
2217     * particular instance of an image. We don't actually get
2218     * rid of the instance until later because we may be about
2219     * to get this instance again.
2220     *
2221     * Results:
2222     * None.
2223     *
2224     * Side effects:
2225     * Internal data structures get cleaned up, later.
2226     *
2227     *----------------------------------------------------------------------
2228     */
2229    
2230     static void
2231     ImgPhotoFree(clientData, display)
2232     ClientData clientData; /* Pointer to PhotoInstance structure for
2233     * for instance to be displayed. */
2234     Display *display; /* Display containing window that used image. */
2235     {
2236     PhotoInstance *instancePtr = (PhotoInstance *) clientData;
2237     ColorTable *colorPtr;
2238    
2239     instancePtr->refCount -= 1;
2240     if (instancePtr->refCount > 0) {
2241     return;
2242     }
2243    
2244     /*
2245     * There are no more uses of the image within this widget.
2246     * Decrement the count of live uses of its color table, so
2247     * that its colors can be reclaimed if necessary, and
2248     * set up an idle call to free the instance structure.
2249     */
2250    
2251     colorPtr = instancePtr->colorTablePtr;
2252     if (colorPtr != NULL) {
2253     colorPtr->liveRefCount -= 1;
2254     }
2255    
2256     Tcl_DoWhenIdle(DisposeInstance, (ClientData) instancePtr);
2257     }
2258    
2259     /*
2260     *----------------------------------------------------------------------
2261     *
2262     * ImgPhotoDelete --
2263     *
2264     * This procedure is called by the image code to delete the
2265     * master structure for an image.
2266     *
2267     * Results:
2268     * None.
2269     *
2270     * Side effects:
2271     * Resources associated with the image get freed.
2272     *
2273     *----------------------------------------------------------------------
2274     */
2275    
2276     static void
2277     ImgPhotoDelete(masterData)
2278     ClientData masterData; /* Pointer to PhotoMaster structure for
2279     * image. Must not have any more instances. */
2280     {
2281     PhotoMaster *masterPtr = (PhotoMaster *) masterData;
2282     PhotoInstance *instancePtr;
2283    
2284     while ((instancePtr = masterPtr->instancePtr) != NULL) {
2285     if (instancePtr->refCount > 0) {
2286     panic("tried to delete photo image when instances still exist");
2287     }
2288     Tcl_CancelIdleCall(DisposeInstance, (ClientData) instancePtr);
2289     DisposeInstance((ClientData) instancePtr);
2290     }
2291     masterPtr->tkMaster = NULL;
2292     if (masterPtr->imageCmd != NULL) {
2293     Tcl_DeleteCommandFromToken(masterPtr->interp, masterPtr->imageCmd);
2294     }
2295     if (masterPtr->pix24 != NULL) {
2296     ckfree((char *) masterPtr->pix24);
2297     }
2298     if (masterPtr->validRegion != NULL) {
2299     TkDestroyRegion(masterPtr->validRegion);
2300     }
2301     if (masterPtr->dataString != NULL) {
2302     Tcl_DecrRefCount(masterPtr->dataString);
2303     }
2304     if (masterPtr->format != NULL) {
2305     Tcl_DecrRefCount(masterPtr->format);
2306     }
2307     Tk_FreeOptions(configSpecs, (char *) masterPtr, (Display *) NULL, 0);
2308     ckfree((char *) masterPtr);
2309     }
2310    
2311     /*
2312     *----------------------------------------------------------------------
2313     *
2314     * ImgPhotoCmdDeletedProc --
2315     *
2316     * This procedure is invoked when the image command for an image
2317     * is deleted. It deletes the image.
2318     *
2319     * Results:
2320     * None.
2321     *
2322     * Side effects:
2323     * The image is deleted.
2324     *
2325     *----------------------------------------------------------------------
2326     */
2327    
2328     static void
2329     ImgPhotoCmdDeletedProc(clientData)
2330     ClientData clientData; /* Pointer to PhotoMaster structure for
2331     * image. */
2332     {
2333     PhotoMaster *masterPtr = (PhotoMaster *) clientData;
2334    
2335     masterPtr->imageCmd = NULL;
2336     if (masterPtr->tkMaster != NULL) {
2337     Tk_DeleteImage(masterPtr->interp, Tk_NameOfImage(masterPtr->tkMaster));
2338     }
2339     }
2340    
2341     /*
2342     *----------------------------------------------------------------------
2343     *
2344     * ImgPhotoSetSize --
2345     *
2346     * This procedure reallocates the image storage and instance
2347     * pixmaps for a photo image, as necessary, to change the
2348     * image's size to `width' x `height' pixels.
2349     *
2350     * Results:
2351     * None.
2352     *
2353     * Side effects:
2354     * Storage gets reallocated, for the master and all its instances.
2355     *
2356     *----------------------------------------------------------------------
2357     */
2358    
2359     static void
2360     ImgPhotoSetSize(masterPtr, width, height)
2361     PhotoMaster *masterPtr;
2362     int width, height;
2363     {
2364     unsigned char *newPix24;
2365     int h, offset, pitch;
2366     unsigned char *srcPtr, *destPtr;
2367     XRectangle validBox, clipBox;
2368     TkRegion clipRegion;
2369     PhotoInstance *instancePtr;
2370    
2371     if (masterPtr->userWidth > 0) {
2372     width = masterPtr->userWidth;
2373     }
2374     if (masterPtr->userHeight > 0) {
2375     height = masterPtr->userHeight;
2376     }
2377    
2378     /*
2379     * We have to trim the valid region if it is currently
2380     * larger than the new image size.
2381     */
2382    
2383     TkClipBox(masterPtr->validRegion, &validBox);
2384     if ((validBox.x + validBox.width > width)
2385     || (validBox.y + validBox.height > height)) {
2386     clipBox.x = 0;
2387     clipBox.y = 0;
2388     clipBox.width = width;
2389     clipBox.height = height;
2390     clipRegion = TkCreateRegion();
2391     TkUnionRectWithRegion(&clipBox, clipRegion, clipRegion);
2392     TkIntersectRegion(masterPtr->validRegion, clipRegion,
2393     masterPtr->validRegion);
2394     TkDestroyRegion(clipRegion);
2395     TkClipBox(masterPtr->validRegion, &validBox);
2396     }
2397    
2398     if ((width != masterPtr->width) || (height != masterPtr->height)
2399     || (masterPtr->pix24 == NULL)) {
2400    
2401     /*
2402     * Reallocate storage for the 24-bit image and copy
2403     * over valid regions.
2404     */
2405    
2406     pitch = width * 4;
2407     newPix24 = (unsigned char *) ckalloc((unsigned) (height * pitch));
2408    
2409     /*
2410     * Zero the new array. The dithering code shouldn't read the
2411     * areas outside validBox, but they might be copied to another
2412     * photo image or written to a file.
2413     */
2414    
2415     if ((masterPtr->pix24 != NULL)
2416     && ((width == masterPtr->width) || (width == validBox.width))) {
2417     if (validBox.y > 0) {
2418     memset((VOID *) newPix24, 0, (size_t) (validBox.y * pitch));
2419     }
2420     h = validBox.y + validBox.height;
2421     if (h < height) {
2422     memset((VOID *) (newPix24 + h * pitch), 0,
2423     (size_t) ((height - h) * pitch));
2424     }
2425     } else {
2426     memset((VOID *) newPix24, 0, (size_t) (height * pitch));
2427     }
2428    
2429     if (masterPtr->pix24 != NULL) {
2430    
2431     /*
2432     * Copy the common area over to the new array array and
2433     * free the old array.
2434     */
2435    
2436     if (width == masterPtr->width) {
2437    
2438     /*
2439     * The region to be copied is contiguous.
2440     */
2441    
2442     offset = validBox.y * pitch;
2443     memcpy((VOID *) (newPix24 + offset),
2444     (VOID *) (masterPtr->pix24 + offset),
2445     (size_t) (validBox.height * pitch));
2446    
2447     } else if ((validBox.width > 0) && (validBox.height > 0)) {
2448    
2449     /*
2450     * Area to be copied is not contiguous - copy line by line.
2451     */
2452    
2453     destPtr = newPix24 + (validBox.y * width + validBox.x) * 4;
2454     srcPtr = masterPtr->pix24 + (validBox.y * masterPtr->width
2455     + validBox.x) * 4;
2456     for (h = validBox.height; h > 0; h--) {
2457     memcpy((VOID *) destPtr, (VOID *) srcPtr,
2458     (size_t) (validBox.width * 4));
2459     destPtr += width * 4;
2460     srcPtr += masterPtr->width * 4;
2461     }
2462     }
2463    
2464     ckfree((char *) masterPtr->pix24);
2465     }
2466    
2467     masterPtr->pix24 = newPix24;
2468     masterPtr->width = width;
2469     masterPtr->height = height;
2470    
2471     /*
2472     * Dithering will be correct up to the end of the last
2473     * pre-existing complete scanline.
2474     */
2475    
2476     if ((validBox.x > 0) || (validBox.y > 0)) {
2477     masterPtr->ditherX = 0;
2478     masterPtr->ditherY = 0;
2479     } else if (validBox.width == width) {
2480     if ((int) validBox.height < masterPtr->ditherY) {
2481     masterPtr->ditherX = 0;
2482     masterPtr->ditherY = validBox.height;
2483     }
2484     } else {
2485     if ((masterPtr->ditherY > 0)
2486     || ((int) validBox.width < masterPtr->ditherX)) {
2487     masterPtr->ditherX = validBox.width;
2488     masterPtr->ditherY = 0;
2489     }
2490     }
2491     }
2492    
2493     /*
2494     * Now adjust the sizes of the pixmaps for all of the instances.
2495     */
2496    
2497     for (instancePtr = masterPtr->instancePtr; instancePtr != NULL;
2498     instancePtr = instancePtr->nextPtr) {
2499     ImgPhotoInstanceSetSize(instancePtr);
2500     }
2501     }
2502    
2503     /*
2504     *----------------------------------------------------------------------
2505     *
2506     * ImgPhotoInstanceSetSize --
2507     *
2508     * This procedure reallocates the instance pixmap and dithering
2509     * error array for a photo instance, as necessary, to change the
2510     * image's size to `width' x `height' pixels.
2511     *
2512     * Results:
2513     * None.
2514     *
2515     * Side effects:
2516     * Storage gets reallocated, here and in the X server.
2517     *
2518     *----------------------------------------------------------------------
2519     */
2520    
2521     static void
2522     ImgPhotoInstanceSetSize(instancePtr)
2523     PhotoInstance *instancePtr; /* Instance whose size is to be
2524     * changed. */
2525     {
2526     PhotoMaster *masterPtr;
2527     schar *newError;
2528     schar *errSrcPtr, *errDestPtr;
2529     int h, offset;
2530     XRectangle validBox;
2531     Pixmap newPixmap;
2532    
2533     masterPtr = instancePtr->masterPtr;
2534     TkClipBox(masterPtr->validRegion, &validBox);
2535    
2536     if ((instancePtr->width != masterPtr->width)
2537     || (instancePtr->height != masterPtr->height)
2538     || (instancePtr->pixels == None)) {
2539     newPixmap = Tk_GetPixmap(instancePtr->display,
2540     RootWindow(instancePtr->display,
2541     instancePtr->visualInfo.screen),
2542     (masterPtr->width > 0) ? masterPtr->width: 1,
2543     (masterPtr->height > 0) ? masterPtr->height: 1,
2544     instancePtr->visualInfo.depth);
2545    
2546     /*
2547     * The following is a gross hack needed to properly support colormaps
2548     * under Windows. Before the pixels can be copied to the pixmap,
2549     * the relevent colormap must be associated with the drawable.
2550     * Normally we can infer this association from the window that
2551     * was used to create the pixmap. However, in this case we're
2552     * using the root window, so we have to be more explicit.
2553     */
2554    
2555     TkSetPixmapColormap(newPixmap, instancePtr->colormap);
2556    
2557     if (instancePtr->pixels != None) {
2558     /*
2559     * Copy any common pixels from the old pixmap and free it.
2560     */
2561     XCopyArea(instancePtr->display, instancePtr->pixels, newPixmap,
2562     instancePtr->gc, validBox.x, validBox.y,
2563     validBox.width, validBox.height, validBox.x, validBox.y);
2564     Tk_FreePixmap(instancePtr->display, instancePtr->pixels);
2565     }
2566     instancePtr->pixels = newPixmap;
2567     }
2568    
2569     if ((instancePtr->width != masterPtr->width)
2570     || (instancePtr->height != masterPtr->height)
2571     || (instancePtr->error == NULL)) {
2572    
2573     newError = (schar *) ckalloc((unsigned)
2574     (masterPtr->height * masterPtr->width * 3 * sizeof(schar)));
2575    
2576     /*
2577     * Zero the new array so that we don't get bogus error values
2578     * propagating into areas we dither later.
2579     */
2580    
2581     if ((instancePtr->error != NULL)
2582     && ((instancePtr->width == masterPtr->width)
2583     || (validBox.width == masterPtr->width))) {
2584     if (validBox.y > 0) {
2585     memset((VOID *) newError, 0, (size_t)
2586     (validBox.y * masterPtr->width * 3 * sizeof(schar)));
2587     }
2588     h = validBox.y + validBox.height;
2589     if (h < masterPtr->height) {
2590     memset((VOID *) (newError + h * masterPtr->width * 3), 0,
2591     (size_t) ((masterPtr->height - h)
2592     * masterPtr->width * 3 * sizeof(schar)));
2593     }
2594     } else {
2595     memset((VOID *) newError, 0, (size_t)
2596     (masterPtr->height * masterPtr->width * 3 * sizeof(schar)));
2597     }
2598    
2599     if (instancePtr->error != NULL) {
2600    
2601     /*
2602     * Copy the common area over to the new array
2603     * and free the old array.
2604     */
2605    
2606     if (masterPtr->width == instancePtr->width) {
2607    
2608     offset = validBox.y * masterPtr->width * 3;
2609     memcpy((VOID *) (newError + offset),
2610     (VOID *) (instancePtr->error + offset),
2611     (size_t) (validBox.height
2612     * masterPtr->width * 3 * sizeof(schar)));
2613    
2614     } else if (validBox.width > 0 && validBox.height > 0) {
2615    
2616     errDestPtr = newError
2617     + (validBox.y * masterPtr->width + validBox.x) * 3;
2618     errSrcPtr = instancePtr->error
2619     + (validBox.y * instancePtr->width + validBox.x) * 3;
2620     for (h = validBox.height; h > 0; --h) {
2621     memcpy((VOID *) errDestPtr, (VOID *) errSrcPtr,
2622     validBox.width * 3 * sizeof(schar));
2623     errDestPtr += masterPtr->width * 3;
2624     errSrcPtr += instancePtr->width * 3;
2625     }
2626     }
2627     ckfree((char *) instancePtr->error);
2628     }
2629    
2630     instancePtr->error = newError;
2631     }
2632    
2633     instancePtr->width = masterPtr->width;
2634     instancePtr->height = masterPtr->height;
2635     }
2636    
2637     /*
2638     *----------------------------------------------------------------------
2639     *
2640     * IsValidPalette --
2641     *
2642     * This procedure is called to check whether a value given for
2643     * the -palette option is valid for a particular instance
2644     * of a photo image.
2645     *
2646     * Results:
2647     * A boolean value: 1 if the palette is acceptable, 0 otherwise.
2648     *
2649     * Side effects:
2650     * None.
2651     *
2652     *----------------------------------------------------------------------
2653     */
2654    
2655     static int
2656     IsValidPalette(instancePtr, palette)
2657     PhotoInstance *instancePtr; /* Instance to which the palette
2658     * specification is to be applied. */
2659     char *palette; /* Palette specification string. */
2660     {
2661     int nRed, nGreen, nBlue, mono, numColors;
2662     char *endp;
2663    
2664     /*
2665     * First parse the specification: it must be of the form
2666     * %d or %d/%d/%d.
2667     */
2668    
2669     nRed = strtol(palette, &endp, 10);
2670     if ((endp == palette) || ((*endp != 0) && (*endp != '/'))
2671     || (nRed < 2) || (nRed > 256)) {
2672     return 0;
2673     }
2674    
2675     if (*endp == 0) {
2676     mono = 1;
2677     nGreen = nBlue = nRed;
2678     } else {
2679     palette = endp + 1;
2680     nGreen = strtol(palette, &endp, 10);
2681     if ((endp == palette) || (*endp != '/') || (nGreen < 2)
2682     || (nGreen > 256)) {
2683     return 0;
2684     }
2685     palette = endp + 1;
2686     nBlue = strtol(palette, &endp, 10);
2687     if ((endp == palette) || (*endp != 0) || (nBlue < 2)
2688     || (nBlue > 256)) {
2689     return 0;
2690     }
2691     mono = 0;
2692     }
2693    
2694     switch (instancePtr->visualInfo.class) {
2695     case DirectColor:
2696     case TrueColor:
2697     if ((nRed > (1 << CountBits(instancePtr->visualInfo.red_mask)))
2698     || (nGreen > (1
2699     << CountBits(instancePtr->visualInfo.green_mask)))
2700     || (nBlue > (1
2701     << CountBits(instancePtr->visualInfo.blue_mask)))) {
2702     return 0;
2703     }
2704     break;
2705     case PseudoColor:
2706     case StaticColor:
2707     numColors = nRed;
2708     if (!mono) {
2709     numColors *= nGreen*nBlue;
2710     }
2711     if (numColors > (1 << instancePtr->visualInfo.depth)) {
2712     return 0;
2713     }
2714     break;
2715     case GrayScale:
2716     case StaticGray:
2717     if (!mono || (nRed > (1 << instancePtr->visualInfo.depth))) {
2718     return 0;
2719     }
2720     break;
2721     }
2722    
2723     return 1;
2724     }
2725    
2726     /*
2727     *----------------------------------------------------------------------
2728     *
2729     * CountBits --
2730     *
2731     * This procedure counts how many bits are set to 1 in `mask'.
2732     *
2733     * Results:
2734     * The integer number of bits.
2735     *
2736     * Side effects:
2737     * None.
2738     *
2739     *----------------------------------------------------------------------
2740     */
2741    
2742     static int
2743     CountBits(mask)
2744     pixel mask; /* Value to count the 1 bits in. */
2745     {
2746     int n;
2747    
2748     for( n = 0; mask != 0; mask &= mask - 1 )
2749     n++;
2750     return n;
2751     }
2752    
2753     /*
2754     *----------------------------------------------------------------------
2755     *
2756     * GetColorTable --
2757     *
2758     * This procedure is called to allocate a table of colormap
2759     * information for an instance of a photo image. Only one such
2760     * table is allocated for all photo instances using the same
2761     * display, colormap, palette and gamma values, so that the
2762     * application need only request a set of colors from the X
2763     * server once for all such photo widgets. This procedure
2764     * maintains a hash table to find previously-allocated
2765     * ColorTables.
2766     *
2767     * Results:
2768     * None.
2769     *
2770     * Side effects:
2771     * A new ColorTable may be allocated and placed in the hash
2772     * table, and have colors allocated for it.
2773     *
2774     *----------------------------------------------------------------------
2775     */
2776    
2777     static void
2778     GetColorTable(instancePtr)
2779     PhotoInstance *instancePtr; /* Instance needing a color table. */
2780     {
2781     ColorTable *colorPtr;
2782     Tcl_HashEntry *entry;
2783     ColorTableId id;
2784     int isNew;
2785    
2786     /*
2787     * Look for an existing ColorTable in the hash table.
2788     */
2789    
2790     memset((VOID *) &id, 0, sizeof(id));
2791     id.display = instancePtr->display;
2792     id.colormap = instancePtr->colormap;
2793     id.palette = instancePtr->palette;
2794     id.gamma = instancePtr->gamma;
2795     if (!imgPhotoColorHashInitialized) {
2796     Tcl_InitHashTable(&imgPhotoColorHash, N_COLOR_HASH);
2797     imgPhotoColorHashInitialized = 1;
2798     }
2799     entry = Tcl_CreateHashEntry(&imgPhotoColorHash, (char *) &id, &isNew);
2800    
2801     if (!isNew) {
2802     /*
2803     * Re-use the existing entry.
2804     */
2805    
2806     colorPtr = (ColorTable *) Tcl_GetHashValue(entry);
2807    
2808     } else {
2809     /*
2810     * No color table currently available; need to make one.
2811     */
2812    
2813     colorPtr = (ColorTable *) ckalloc(sizeof(ColorTable));
2814    
2815     /*
2816     * The following line of code should not normally be needed due
2817     * to the assignment in the following line. However, it compensates
2818     * for bugs in some compilers (HP, for example) where
2819     * sizeof(ColorTable) is 24 but the assignment only copies 20 bytes,
2820     * leaving 4 bytes uninitialized; these cause problems when using
2821     * the id for lookups in imgPhotoColorHash, and can result in
2822     * core dumps.
2823     */
2824    
2825     memset((VOID *) &colorPtr->id, 0, sizeof(ColorTableId));
2826     colorPtr->id = id;
2827     Tk_PreserveColormap(colorPtr->id.display, colorPtr->id.colormap);
2828     colorPtr->flags = 0;
2829     colorPtr->refCount = 0;
2830     colorPtr->liveRefCount = 0;
2831     colorPtr->numColors = 0;
2832     colorPtr->visualInfo = instancePtr->visualInfo;
2833     colorPtr->pixelMap = NULL;
2834     Tcl_SetHashValue(entry, colorPtr);
2835     }
2836    
2837     colorPtr->refCount++;
2838     colorPtr->liveRefCount++;
2839     instancePtr->colorTablePtr = colorPtr;
2840     if (colorPtr->flags & DISPOSE_PENDING) {
2841     Tcl_CancelIdleCall(DisposeColorTable, (ClientData) colorPtr);
2842     colorPtr->flags &= ~DISPOSE_PENDING;
2843     }
2844    
2845     /*
2846     * Allocate colors for this color table if necessary.
2847     */
2848    
2849     if ((colorPtr->numColors == 0)
2850     && ((colorPtr->flags & BLACK_AND_WHITE) == 0)) {
2851     AllocateColors(colorPtr);
2852     }
2853     }
2854    
2855     /*
2856     *----------------------------------------------------------------------
2857     *
2858     * FreeColorTable --
2859     *
2860     * This procedure is called when an instance ceases using a
2861     * color table.
2862     *
2863     * Results:
2864     * None.
2865     *
2866     * Side effects:
2867     * If no other instances are using this color table, a when-idle
2868     * handler is registered to free up the color table and the colors
2869     * allocated for it.
2870     *
2871     *----------------------------------------------------------------------
2872     */
2873    
2874     static void
2875     FreeColorTable(colorPtr, force)
2876     ColorTable *colorPtr; /* Pointer to the color table which is
2877     * no longer required by an instance. */
2878     int force; /* Force free to happen immediately. */
2879     {
2880     colorPtr->refCount--;
2881     if (colorPtr->refCount > 0) {
2882     return;
2883     }
2884     if (force) {
2885     if ((colorPtr->flags & DISPOSE_PENDING) != 0) {
2886     Tcl_CancelIdleCall(DisposeColorTable, (ClientData) colorPtr);
2887     colorPtr->flags &= ~DISPOSE_PENDING;
2888     }
2889     DisposeColorTable((ClientData) colorPtr);
2890     } else if ((colorPtr->flags & DISPOSE_PENDING) == 0) {
2891     Tcl_DoWhenIdle(DisposeColorTable, (ClientData) colorPtr);
2892     colorPtr->flags |= DISPOSE_PENDING;
2893     }
2894     }
2895    
2896     /*
2897     *----------------------------------------------------------------------
2898     *
2899     * AllocateColors --
2900     *
2901     * This procedure allocates the colors required by a color table,
2902     * and sets up the fields in the color table data structure which
2903     * are used in dithering.
2904     *
2905     * Results:
2906     * None.
2907     *
2908     * Side effects:
2909     * Colors are allocated from the X server. Fields in the
2910     * color table data structure are updated.
2911     *
2912     *----------------------------------------------------------------------
2913     */
2914    
2915     static void
2916     AllocateColors(colorPtr)
2917     ColorTable *colorPtr; /* Pointer to the color table requiring
2918     * colors to be allocated. */
2919     {
2920     int i, r, g, b, rMult, mono;
2921     int numColors, nRed, nGreen, nBlue;
2922     double fr, fg, fb, igam;
2923     XColor *colors;
2924     unsigned long *pixels;
2925    
2926     /* 16-bit intensity value for i/n of full intensity. */
2927     # define CFRAC(i, n) ((i) * 65535 / (n))
2928    
2929     /* As for CFRAC, but apply exponent of g. */
2930     # define CGFRAC(i, n, g) ((int)(65535 * pow((double)(i) / (n), (g))))
2931    
2932     /*
2933     * First parse the palette specification to get the required number of
2934     * shades of each primary.
2935     */
2936    
2937     mono = sscanf(colorPtr->id.palette, "%d/%d/%d", &nRed, &nGreen, &nBlue)
2938     <= 1;
2939     igam = 1.0 / colorPtr->id.gamma;
2940    
2941     /*
2942     * Each time around this loop, we reduce the number of colors we're
2943     * trying to allocate until we succeed in allocating all of the colors
2944     * we need.
2945     */
2946    
2947     for (;;) {
2948     /*
2949     * If we are using 1 bit/pixel, we don't need to allocate
2950     * any colors (we just use the foreground and background
2951     * colors in the GC).
2952     */
2953    
2954     if (mono && (nRed <= 2)) {
2955     colorPtr->flags |= BLACK_AND_WHITE;
2956     return;
2957     }
2958    
2959     /*
2960     * Calculate the RGB coordinates of the colors we want to
2961     * allocate and store them in *colors.
2962     */
2963    
2964     if ((colorPtr->visualInfo.class == DirectColor)
2965     || (colorPtr->visualInfo.class == TrueColor)) {
2966    
2967     /*
2968     * Direct/True Color: allocate shades of red, green, blue
2969     * independently.
2970     */
2971    
2972     if (mono) {
2973     numColors = nGreen = nBlue = nRed;
2974     } else {
2975     numColors = MAX(MAX(nRed, nGreen), nBlue);
2976     }
2977     colors = (XColor *) ckalloc(numColors * sizeof(XColor));
2978    
2979     for (i = 0; i < numColors; ++i) {
2980     if (igam == 1.0) {
2981     colors[i].red = CFRAC(i, nRed - 1);
2982     colors[i].green = CFRAC(i, nGreen - 1);
2983     colors[i].blue = CFRAC(i, nBlue - 1);
2984     } else {
2985     colors[i].red = CGFRAC(i, nRed - 1, igam);
2986     colors[i].green = CGFRAC(i, nGreen - 1, igam);
2987     colors[i].blue = CGFRAC(i, nBlue - 1, igam);
2988     }
2989     }
2990     } else {
2991     /*
2992     * PseudoColor, StaticColor, GrayScale or StaticGray visual:
2993     * we have to allocate each color in the color cube separately.
2994     */
2995    
2996     numColors = (mono) ? nRed: (nRed * nGreen * nBlue);
2997     colors = (XColor *) ckalloc(numColors * sizeof(XColor));
2998    
2999     if (!mono) {
3000     /*
3001     * Color display using a PseudoColor or StaticColor visual.
3002     */
3003    
3004     i = 0;
3005     for (r = 0; r < nRed; ++r) {
3006     for (g = 0; g < nGreen; ++g) {
3007     for (b = 0; b < nBlue; ++b) {
3008     if (igam == 1.0) {
3009     colors[i].red = CFRAC(r, nRed - 1);
3010     colors[i].green = CFRAC(g, nGreen - 1);
3011     colors[i].blue = CFRAC(b, nBlue - 1);
3012     } else {
3013     colors[i].red = CGFRAC(r, nRed - 1, igam);
3014     colors[i].green = CGFRAC(g, nGreen - 1, igam);
3015     colors[i].blue = CGFRAC(b, nBlue - 1, igam);
3016     }
3017     i++;
3018     }
3019     }
3020     }
3021     } else {
3022     /*
3023     * Monochrome display - allocate the shades of grey we want.
3024     */
3025    
3026     for (i = 0; i < numColors; ++i) {
3027     if (igam == 1.0) {
3028     r = CFRAC(i, numColors - 1);
3029     } else {
3030     r = CGFRAC(i, numColors - 1, igam);
3031     }
3032     colors[i].red = colors[i].green = colors[i].blue = r;
3033     }
3034     }
3035     }
3036    
3037     /*
3038     * Now try to allocate the colors we've calculated.
3039     */
3040    
3041     pixels = (unsigned long *) ckalloc(numColors * sizeof(unsigned long));
3042     for (i = 0; i < numColors; ++i) {
3043     if (!XAllocColor(colorPtr->id.display, colorPtr->id.colormap,
3044     &colors[i])) {
3045    
3046     /*
3047     * Can't get all the colors we want in the default colormap;
3048     * first try freeing colors from other unused color tables.
3049     */
3050    
3051     if (!ReclaimColors(&colorPtr->id, numColors - i)
3052     || !XAllocColor(colorPtr->id.display,
3053     colorPtr->id.colormap, &colors[i])) {
3054     /*
3055     * Still can't allocate the color.
3056     */
3057     break;
3058     }
3059     }
3060     pixels[i] = colors[i].pixel;
3061     }
3062    
3063     /*
3064     * If we didn't get all of the colors, reduce the
3065     * resolution of the color cube, free the ones we got,
3066     * and try again.
3067     */
3068    
3069     if (i >= numColors) {
3070     break;
3071     }
3072     XFreeColors(colorPtr->id.display, colorPtr->id.colormap, pixels, i, 0);
3073     ckfree((char *) colors);
3074     ckfree((char *) pixels);
3075    
3076     if (!mono) {
3077     if ((nRed == 2) && (nGreen == 2) && (nBlue == 2)) {
3078     /*
3079     * Fall back to 1-bit monochrome display.
3080     */
3081    
3082     mono = 1;
3083     } else {
3084     /*
3085     * Reduce the number of shades of each primary to about
3086     * 3/4 of the previous value. This should reduce the
3087     * total number of colors required to about half the
3088     * previous value for PseudoColor displays.
3089     */
3090    
3091     nRed = (nRed * 3 + 2) / 4;
3092     nGreen = (nGreen * 3 + 2) / 4;
3093     nBlue = (nBlue * 3 + 2) / 4;
3094     }
3095     } else {
3096     /*
3097     * Reduce the number of shades of gray to about 1/2.
3098     */
3099    
3100     nRed = nRed / 2;
3101     }
3102     }
3103    
3104     /*
3105     * We have allocated all of the necessary colors:
3106     * fill in various fields of the ColorTable record.
3107     */
3108    
3109     if (!mono) {
3110     colorPtr->flags |= COLOR_WINDOW;
3111    
3112     /*
3113     * The following is a hairy hack. We only want to index into
3114     * the pixelMap on colormap displays. However, if the display
3115     * is on Windows, then we actually want to store the index not
3116     * the value since we will be passing the color table into the
3117     * TkPutImage call.
3118     */
3119    
3120     #ifndef __WIN32__
3121     if ((colorPtr->visualInfo.class != DirectColor)
3122     && (colorPtr->visualInfo.class != TrueColor)) {
3123     colorPtr->flags |= MAP_COLORS;
3124     }
3125     #endif /* __WIN32__ */
3126     }
3127    
3128     colorPtr->numColors = numColors;
3129     colorPtr->pixelMap = pixels;
3130    
3131     /*
3132     * Set up quantization tables for dithering.
3133     */
3134     rMult = nGreen * nBlue;
3135     for (i = 0; i < 256; ++i) {
3136     r = (i * (nRed - 1) + 127) / 255;
3137     if (mono) {
3138     fr = (double) colors[r].red / 65535.0;
3139     if (colorPtr->id.gamma != 1.0 ) {
3140     fr = pow(fr, colorPtr->id.gamma);
3141     }
3142     colorPtr->colorQuant[0][i] = (int)(fr * 255.99);
3143     colorPtr->redValues[i] = colors[r].pixel;
3144     } else {
3145     g = (i * (nGreen - 1) + 127) / 255;
3146     b = (i * (nBlue - 1) + 127) / 255;
3147     if ((colorPtr->visualInfo.class == DirectColor)
3148     || (colorPtr->visualInfo.class == TrueColor)) {
3149     colorPtr->redValues[i] = colors[r].pixel
3150     & colorPtr->visualInfo.red_mask;
3151     colorPtr->greenValues[i] = colors[g].pixel
3152     & colorPtr->visualInfo.green_mask;
3153     colorPtr->blueValues[i] = colors[b].pixel
3154     & colorPtr->visualInfo.blue_mask;
3155     } else {
3156     r *= rMult;
3157     g *= nBlue;
3158     colorPtr->redValues[i] = r;
3159     colorPtr->greenValues[i] = g;
3160     colorPtr->blueValues[i] = b;
3161     }
3162     fr = (double) colors[r].red / 65535.0;
3163     fg = (double) colors[g].green / 65535.0;
3164     fb = (double) colors[b].blue / 65535.0;
3165     if (colorPtr->id.gamma != 1.0) {
3166     fr = pow(fr, colorPtr->id.gamma);
3167     fg = pow(fg, colorPtr->id.gamma);
3168     fb = pow(fb, colorPtr->id.gamma);
3169     }
3170     colorPtr->colorQuant[0][i] = (int)(fr * 255.99);
3171     colorPtr->colorQuant[1][i] = (int)(fg * 255.99);
3172     colorPtr->colorQuant[2][i] = (int)(fb * 255.99);
3173     }
3174     }
3175    
3176     ckfree((char *) colors);
3177     }
3178    
3179     /*
3180     *----------------------------------------------------------------------
3181     *
3182     * DisposeColorTable --
3183     *
3184     *
3185     * Results:
3186     * None.
3187     *
3188     * Side effects:
3189     * The colors in the argument color table are freed, as is the
3190     * color table structure itself. The color table is removed
3191     * from the hash table which is used to locate color tables.
3192     *
3193     *----------------------------------------------------------------------
3194     */
3195    
3196     static void
3197     DisposeColorTable(clientData)
3198     ClientData clientData; /* Pointer to the ColorTable whose
3199     * colors are to be released. */
3200     {
3201     ColorTable *colorPtr;
3202     Tcl_HashEntry *entry;
3203    
3204     colorPtr = (ColorTable *) clientData;
3205     if (colorPtr->pixelMap != NULL) {
3206     if (colorPtr->numColors > 0) {
3207     XFreeColors(colorPtr->id.display, colorPtr->id.colormap,
3208     colorPtr->pixelMap, colorPtr->numColors, 0);
3209     Tk_FreeColormap(colorPtr->id.display, colorPtr->id.colormap);
3210     }
3211     ckfree((char *) colorPtr->pixelMap);
3212     }
3213    
3214     entry = Tcl_FindHashEntry(&imgPhotoColorHash, (char *) &colorPtr->id);
3215     if (entry == NULL) {
3216     panic("DisposeColorTable couldn't find hash entry");
3217     }
3218     Tcl_DeleteHashEntry(entry);
3219    
3220     ckfree((char *) colorPtr);
3221     }
3222    
3223     /*
3224     *----------------------------------------------------------------------
3225     *
3226     * ReclaimColors --
3227     *
3228     * This procedure is called to try to free up colors in the
3229     * colormap used by a color table. It looks for other color
3230     * tables with the same colormap and with a zero live reference
3231     * count, and frees their colors. It only does so if there is
3232     * the possibility of freeing up at least `numColors' colors.
3233     *
3234     * Results:
3235     * The return value is TRUE if any colors were freed, FALSE
3236     * otherwise.
3237     *
3238     * Side effects:
3239     * ColorTables which are not currently in use may lose their
3240     * color allocations.
3241     *
3242     *---------------------------------------------------------------------- */
3243    
3244     static int
3245     ReclaimColors(id, numColors)
3246     ColorTableId *id; /* Pointer to information identifying
3247     * the color table which needs more colors. */
3248     int numColors; /* Number of colors required. */
3249     {
3250     Tcl_HashSearch srch;
3251     Tcl_HashEntry *entry;
3252     ColorTable *colorPtr;
3253     int nAvail;
3254    
3255     /*
3256     * First scan through the color hash table to get an
3257     * upper bound on how many colors we might be able to free.
3258     */
3259    
3260     nAvail = 0;
3261     entry = Tcl_FirstHashEntry(&imgPhotoColorHash, &srch);
3262     while (entry != NULL) {
3263     colorPtr = (ColorTable *) Tcl_GetHashValue(entry);
3264     if ((colorPtr->id.display == id->display)
3265     && (colorPtr->id.colormap == id->colormap)
3266     && (colorPtr->liveRefCount == 0 )&& (colorPtr->numColors != 0)
3267     && ((colorPtr->id.palette != id->palette)
3268     || (colorPtr->id.gamma != id->gamma))) {
3269    
3270     /*
3271     * We could take this guy's colors off him.
3272     */
3273    
3274     nAvail += colorPtr->numColors;
3275     }
3276     entry = Tcl_NextHashEntry(&srch);
3277     }
3278    
3279     /*
3280     * nAvail is an (over)estimate of the number of colors we could free.
3281     */
3282    
3283     if (nAvail < numColors) {
3284     return 0;
3285     }
3286    
3287     /*
3288     * Scan through a second time freeing colors.
3289     */
3290    
3291     entry = Tcl_FirstHashEntry(&imgPhotoColorHash, &srch);
3292     while ((entry != NULL) && (numColors > 0)) {
3293     colorPtr = (ColorTable *) Tcl_GetHashValue(entry);
3294     if ((colorPtr->id.display == id->display)
3295     && (colorPtr->id.colormap == id->colormap)
3296     && (colorPtr->liveRefCount == 0) && (colorPtr->numColors != 0)
3297     && ((colorPtr->id.palette != id->palette)
3298     || (colorPtr->id.gamma != id->gamma))) {
3299    
3300     /*
3301     * Free the colors that this ColorTable has.
3302     */
3303    
3304     XFreeColors(colorPtr->id.display, colorPtr->id.colormap,
3305     colorPtr->pixelMap, colorPtr->numColors, 0);
3306     numColors -= colorPtr->numColors;
3307     colorPtr->numColors = 0;
3308     ckfree((char *) colorPtr->pixelMap);
3309     colorPtr->pixelMap = NULL;
3310     }
3311    
3312     entry = Tcl_NextHashEntry(&srch);
3313     }
3314     return 1; /* we freed some colors */
3315     }
3316    
3317     /*
3318     *----------------------------------------------------------------------
3319     *
3320     * DisposeInstance --
3321     *
3322     * This procedure is called to finally free up an instance
3323     * of a photo image which is no longer required.
3324     *
3325     * Results:
3326     * None.
3327     *
3328     * Side effects:
3329     * The instance data structure and the resources it references
3330     * are freed.
3331     *
3332     *----------------------------------------------------------------------
3333     */
3334    
3335     static void
3336     DisposeInstance(clientData)
3337     ClientData clientData; /* Pointer to the instance whose resources
3338     * are to be released. */
3339     {
3340     PhotoInstance *instancePtr = (PhotoInstance *) clientData;
3341     PhotoInstance *prevPtr;
3342    
3343     if (instancePtr->pixels != None) {
3344     Tk_FreePixmap(instancePtr->display, instancePtr->pixels);
3345     }
3346     if (instancePtr->gc != None) {
3347     Tk_FreeGC(instancePtr->display, instancePtr->gc);
3348     }
3349     if (instancePtr->imagePtr != NULL) {
3350     XFree((char *) instancePtr->imagePtr);
3351     }
3352     if (instancePtr->error != NULL) {
3353     ckfree((char *) instancePtr->error);
3354     }
3355     if (instancePtr->colorTablePtr != NULL) {
3356     FreeColorTable(instancePtr->colorTablePtr, 1);
3357     }
3358    
3359     if (instancePtr->masterPtr->instancePtr == instancePtr) {
3360     instancePtr->masterPtr->instancePtr = instancePtr->nextPtr;
3361     } else {
3362     for (prevPtr = instancePtr->masterPtr->instancePtr;
3363     prevPtr->nextPtr != instancePtr; prevPtr = prevPtr->nextPtr) {
3364     /* Empty loop body */
3365     }
3366     prevPtr->nextPtr = instancePtr->nextPtr;
3367     }
3368     Tk_FreeColormap(instancePtr->display, instancePtr->colormap);
3369     ckfree((char *) instancePtr);
3370     }
3371    
3372     /*
3373     *----------------------------------------------------------------------
3374     *
3375     * MatchFileFormat --
3376     *
3377     * This procedure is called to find a photo image file format
3378     * handler which can parse the image data in the given file.
3379     * If a user-specified format string is provided, only handlers
3380     * whose names match a prefix of the format string are tried.
3381     *
3382     * Results:
3383     * A standard TCL return value. If the return value is TCL_OK, a
3384     * pointer to the image format record is returned in
3385     * *imageFormatPtr, and the width and height of the image are
3386     * returned in *widthPtr and *heightPtr.
3387     *
3388     * Side effects:
3389     * None.
3390     *
3391     *----------------------------------------------------------------------
3392     */
3393    
3394     static int
3395     MatchFileFormat(interp, chan, fileName, formatObj, imageFormatPtr,
3396     widthPtr, heightPtr, oldformat)
3397     Tcl_Interp *interp; /* Interpreter to use for reporting errors. */
3398     Tcl_Channel chan; /* The image file, open for reading. */
3399     char *fileName; /* The name of the image file. */
3400     Tcl_Obj *formatObj; /* User-specified format string, or NULL. */
3401     Tk_PhotoImageFormat **imageFormatPtr;
3402     /* A pointer to the photo image format
3403     * record is returned here. */
3404     int *widthPtr, *heightPtr; /* The dimensions of the image are
3405     * returned here. */
3406     int *oldformat;
3407     {
3408     int matched;
3409     int useoldformat = 0;
3410     Tk_PhotoImageFormat *formatPtr;
3411     ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
3412     Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
3413     char *formatString = NULL;
3414    
3415     if (formatObj) {
3416     formatString = Tcl_GetString(formatObj);
3417     }
3418    
3419     /*
3420     * Scan through the table of file format handlers to find
3421     * one which can handle the image.
3422     */
3423    
3424     matched = 0;
3425     for (formatPtr = tsdPtr->formatList; formatPtr != NULL;
3426     formatPtr = formatPtr->nextPtr) {
3427     if (formatObj != NULL) {
3428     if (strncasecmp(formatString,
3429     formatPtr->name, strlen(formatPtr->name)) != 0) {
3430     continue;
3431     }
3432     matched = 1;
3433     if (formatPtr->fileMatchProc == NULL) {
3434     Tcl_AppendResult(interp, "-file option isn't supported for ",
3435     formatString, " images", (char *) NULL);
3436     return TCL_ERROR;
3437     }
3438     }
3439     if (formatPtr->fileMatchProc != NULL) {
3440     (void) Tcl_Seek(chan, 0L, SEEK_SET);
3441    
3442     if ((*formatPtr->fileMatchProc)(chan, fileName, formatObj,
3443     widthPtr, heightPtr, interp)) {
3444     if (*widthPtr < 1) {
3445     *widthPtr = 1;
3446     }
3447     if (*heightPtr < 1) {
3448     *heightPtr = 1;
3449     }
3450     break;
3451     }
3452     }
3453     }
3454     if (formatPtr == NULL) {
3455     useoldformat = 1;
3456     for (formatPtr = tsdPtr->oldFormatList; formatPtr != NULL;
3457     formatPtr = formatPtr->nextPtr) {
3458     if (formatString != NULL) {
3459     if (strncasecmp(formatString,
3460     formatPtr->name, strlen(formatPtr->name)) != 0) {
3461     continue;
3462     }
3463     matched = 1;
3464     if (formatPtr->fileMatchProc == NULL) {
3465     Tcl_AppendResult(interp, "-file option isn't supported for ",
3466     formatString, " images", (char *) NULL);
3467     return TCL_ERROR;
3468     }
3469     }
3470     if (formatPtr->fileMatchProc != NULL) {
3471     (void) Tcl_Seek(chan, 0L, SEEK_SET);
3472     if ((*formatPtr->fileMatchProc)(chan, fileName, (Tcl_Obj *) formatString,
3473     widthPtr, heightPtr, interp)) {
3474     if (*widthPtr < 1) {
3475     *widthPtr = 1;
3476     }
3477     if (*heightPtr < 1) {
3478     *heightPtr = 1;
3479     }
3480     break;
3481     }
3482     }
3483     }
3484     }
3485    
3486     if (formatPtr == NULL) {
3487     if ((formatObj != NULL) && !matched) {
3488     Tcl_AppendResult(interp, "image file format \"",
3489     formatString,
3490     "\" is not supported", (char *) NULL);
3491     } else {
3492     Tcl_AppendResult(interp,
3493     "couldn't recognize data in image file \"",
3494     fileName, "\"", (char *) NULL);
3495     }
3496     return TCL_ERROR;
3497     }
3498    
3499     *imageFormatPtr = formatPtr;
3500     *oldformat = useoldformat;
3501     (void) Tcl_Seek(chan, 0L, SEEK_SET);
3502     return TCL_OK;
3503     }
3504    
3505     /*
3506     *----------------------------------------------------------------------
3507     *
3508     * MatchStringFormat --
3509     *
3510     * This procedure is called to find a photo image file format
3511     * handler which can parse the image data in the given string.
3512     * If a user-specified format string is provided, only handlers
3513     * whose names match a prefix of the format string are tried.
3514     *
3515     * Results:
3516     * A standard TCL return value. If the return value is TCL_OK, a
3517     * pointer to the image format record is returned in
3518     * *imageFormatPtr, and the width and height of the image are
3519     * returned in *widthPtr and *heightPtr.
3520     *
3521     * Side effects:
3522     * None.
3523     *
3524     *----------------------------------------------------------------------
3525     */
3526    
3527     static int
3528     MatchStringFormat(interp, data, formatObj, imageFormatPtr,
3529     widthPtr, heightPtr, oldformat)
3530     Tcl_Interp *interp; /* Interpreter to use for reporting errors. */
3531     Tcl_Obj *data; /* Object containing the image data. */
3532     Tcl_Obj *formatObj; /* User-specified format string, or NULL. */
3533     Tk_PhotoImageFormat **imageFormatPtr;
3534     /* A pointer to the photo image format
3535     * record is returned here. */
3536     int *widthPtr, *heightPtr; /* The dimensions of the image are
3537     * returned here. */
3538     int *oldformat; /* returns 1 if the old image API is used */
3539     {
3540     int matched;
3541     int useoldformat = 0;
3542     Tk_PhotoImageFormat *formatPtr;
3543     ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
3544     Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
3545     char *formatString = NULL;
3546    
3547     if (formatObj) {
3548     formatString = Tcl_GetString(formatObj);
3549     }
3550    
3551     /*
3552     * Scan through the table of file format handlers to find
3553     * one which can handle the image.
3554     */
3555    
3556     matched = 0;
3557     for (formatPtr = tsdPtr->formatList; formatPtr != NULL;
3558     formatPtr = formatPtr->nextPtr) {
3559     if (formatObj != NULL) {
3560     if (strncasecmp(formatString,
3561     formatPtr->name, strlen(formatPtr->name)) != 0) {
3562     continue;
3563     }
3564     matched = 1;
3565     if (formatPtr->stringMatchProc == NULL) {
3566     Tcl_AppendResult(interp, "-data option isn't supported for ",
3567     formatString, " images", (char *) NULL);
3568     return TCL_ERROR;
3569     }
3570     }
3571     if ((formatPtr->stringMatchProc != NULL)
3572     && (formatPtr->stringReadProc != NULL)
3573     && (*formatPtr->stringMatchProc)(data, formatObj,
3574     widthPtr, heightPtr, interp)) {
3575     break;
3576     }
3577     }
3578    
3579     if (formatPtr == NULL) {
3580     useoldformat = 1;
3581     for (formatPtr = tsdPtr->oldFormatList; formatPtr != NULL;
3582     formatPtr = formatPtr->nextPtr) {
3583     if (formatObj != NULL) {
3584     if (strncasecmp(formatString,
3585     formatPtr->name, strlen(formatPtr->name)) != 0) {
3586     continue;
3587     }
3588     matched = 1;
3589     if (formatPtr->stringMatchProc == NULL) {
3590     Tcl_AppendResult(interp, "-data option isn't supported for ",
3591     formatString, " images", (char *) NULL);
3592     return TCL_ERROR;
3593     }
3594     }
3595     if ((formatPtr->stringMatchProc != NULL)
3596     && (formatPtr->stringReadProc != NULL)
3597     && (*formatPtr->stringMatchProc)((Tcl_Obj *) Tcl_GetString(data),
3598     (Tcl_Obj *) formatString,
3599     widthPtr, heightPtr, interp)) {
3600     break;
3601     }
3602     }
3603     }
3604     if (formatPtr == NULL) {
3605     if ((formatObj != NULL) && !matched) {
3606     Tcl_AppendResult(interp, "image format \"",
3607     formatString,
3608     "\" is not supported", (char *) NULL);
3609     } else {
3610     Tcl_AppendResult(interp, "couldn't recognize image data",
3611     (char *) NULL);
3612     }
3613     return TCL_ERROR;
3614     }
3615    
3616     *imageFormatPtr = formatPtr;
3617     *oldformat = useoldformat;
3618     return TCL_OK;
3619     }
3620    
3621     /*
3622     *----------------------------------------------------------------------
3623     *
3624     * Tk_FindPhoto --
3625     *
3626     * This procedure is called to get an opaque handle (actually a
3627     * PhotoMaster *) for a given image, which can be used in
3628     * subsequent calls to Tk_PhotoPutBlock, etc. The `name'
3629     * parameter is the name of the image.
3630     *
3631     * Results:
3632     * The handle for the photo image, or NULL if there is no
3633     * photo image with the name given.
3634     *
3635     * Side effects:
3636     * None.
3637     *
3638     *----------------------------------------------------------------------
3639     */
3640    
3641     Tk_PhotoHandle
3642     Tk_FindPhoto(interp, imageName)
3643     Tcl_Interp *interp; /* Interpreter (application) in which image
3644     * exists. */
3645     char *imageName; /* Name of the desired photo image. */
3646     {
3647     ClientData clientData;
3648     Tk_ImageType *typePtr;
3649    
3650     clientData = Tk_GetImageMasterData(interp, imageName, &typePtr);
3651     if (typePtr != &tkPhotoImageType) {
3652     return NULL;
3653     }
3654     return (Tk_PhotoHandle) clientData;
3655     }
3656    
3657     /*
3658     *----------------------------------------------------------------------
3659     *
3660     * Tk_PhotoPutBlock --
3661     *
3662     * This procedure is called to put image data into a photo image.
3663     *
3664     * Results:
3665     * None.
3666     *
3667     * Side effects:
3668     * The image data is stored. The image may be expanded.
3669     * The Tk image code is informed that the image has changed.
3670     *
3671     *---------------------------------------------------------------------- */
3672    
3673     void
3674     Tk_PhotoPutBlock(handle, blockPtr, x, y, width, height)
3675     Tk_PhotoHandle handle; /* Opaque handle for the photo image
3676     * to be updated. */
3677     register Tk_PhotoImageBlock *blockPtr;
3678     /* Pointer to a structure describing the
3679     * pixel data to be copied into the image. */
3680     int x, y; /* Coordinates of the top-left pixel to
3681     * be updated in the image. */
3682     int width, height; /* Dimensions of the area of the image
3683     * to be updated. */
3684     {
3685     register PhotoMaster *masterPtr;
3686     int xEnd, yEnd;
3687     int greenOffset, blueOffset, alphaOffset;
3688     int wLeft, hLeft;
3689     int wCopy, hCopy;
3690     unsigned char *srcPtr, *srcLinePtr;
3691     unsigned char *destPtr, *destLinePtr;
3692     int pitch;
3693     XRectangle rect;
3694    
3695     masterPtr = (PhotoMaster *) handle;
3696    
3697     if ((masterPtr->userWidth != 0) && ((x + width) > masterPtr->userWidth)) {
3698     width = masterPtr->userWidth - x;
3699     }
3700     if ((masterPtr->userHeight != 0)
3701     && ((y + height) > masterPtr->userHeight)) {
3702     height = masterPtr->userHeight - y;
3703     }
3704     if ((width <= 0) || (height <= 0))
3705     return;
3706    
3707     xEnd = x + width;
3708     yEnd = y + height;
3709     if ((xEnd > masterPtr->width) || (yEnd > masterPtr->height)) {
3710     ImgPhotoSetSize(masterPtr, MAX(xEnd, masterPtr->width),
3711     MAX(yEnd, masterPtr->height));
3712     }
3713    
3714     if ((y < masterPtr->ditherY) || ((y == masterPtr->ditherY)
3715     && (x < masterPtr->ditherX))) {
3716     /*
3717     * The dithering isn't correct past the start of this block.
3718     */
3719     masterPtr->ditherX = x;
3720     masterPtr->ditherY = y;
3721     }
3722    
3723     /*
3724     * If this image block could have different red, green and blue
3725     * components, mark it as a color image.
3726     */
3727    
3728     greenOffset = blockPtr->offset[1] - blockPtr->offset[0];
3729     blueOffset = blockPtr->offset[2] - blockPtr->offset[0];
3730     alphaOffset = blockPtr->offset[3];
3731     if ((alphaOffset >= blockPtr->pixelSize) || (alphaOffset < 0)) {
3732     alphaOffset = 0;
3733     } else {
3734     alphaOffset -= blockPtr->offset[0];
3735     }
3736     if ((greenOffset != 0) || (blueOffset != 0)) {
3737     masterPtr->flags |= COLOR_IMAGE;
3738     }
3739    
3740     /*
3741     * Copy the data into our local 24-bit/pixel array.
3742     * If we can do it with a single memcpy, we do.
3743     */
3744    
3745     destLinePtr = masterPtr->pix24 + (y * masterPtr->width + x) * 4;
3746     pitch = masterPtr->width * 4;
3747    
3748     /*
3749     * This test is probably too restrictive. We should also be able to
3750     * do a memcpy if pixelSize == 3 and alphaOffset == 0. Maybe other cases
3751     * too.
3752     */
3753     if ((blockPtr->pixelSize == 4)
3754     && (greenOffset == 1) && (blueOffset == 2) && (alphaOffset == 3)
3755     && (width <= blockPtr->width) && (height <= blockPtr->height)
3756     && ((height == 1) || ((x == 0) && (width == masterPtr->width)
3757     && (blockPtr->pitch == pitch)))) {
3758     memcpy((VOID *) destLinePtr,
3759     (VOID *) (blockPtr->pixelPtr + blockPtr->offset[0]),
3760     (size_t) (height * width * 4));
3761     } else {
3762     for (hLeft = height; hLeft > 0;) {
3763     srcLinePtr = blockPtr->pixelPtr + blockPtr->offset[0];
3764     hCopy = MIN(hLeft, blockPtr->height);
3765     hLeft -= hCopy;
3766     for (; hCopy > 0; --hCopy) {
3767     destPtr = destLinePtr;
3768     for (wLeft = width; wLeft > 0;) {
3769     wCopy = MIN(wLeft, blockPtr->width);
3770     wLeft -= wCopy;
3771     srcPtr = srcLinePtr;
3772     for (; wCopy > 0; --wCopy) {
3773     if (!destPtr[3]) {
3774     destPtr[0] = destPtr[1] = destPtr[2] = 0xd9;
3775     }
3776     if (!alphaOffset || (srcPtr[alphaOffset] == 255)) {
3777     *destPtr++ = srcPtr[0];
3778     *destPtr++ = srcPtr[greenOffset];
3779     *destPtr++ = srcPtr[blueOffset];
3780     *destPtr++ = 255;
3781     } else {
3782     if (srcPtr[alphaOffset]) {
3783     destPtr[0] += (srcPtr[0] - destPtr[0]) * srcPtr[alphaOffset] / 255;
3784     destPtr[1] += (srcPtr[greenOffset] - destPtr[1]) * srcPtr[alphaOffset] / 255;
3785     destPtr[2] += (srcPtr[blueOffset] - destPtr[2]) * srcPtr[alphaOffset] / 255;
3786     destPtr[3] += (255 - destPtr[3]) * srcPtr[alphaOffset] / 255;
3787     }
3788     destPtr+=4;
3789     }
3790     srcPtr += blockPtr->pixelSize;
3791     }
3792     }
3793     srcLinePtr += blockPtr->pitch;
3794     destLinePtr += pitch;
3795     }
3796     }
3797     }
3798    
3799     /*
3800     * Add this new block to the region which specifies which data is valid.
3801     */
3802    
3803     if (alphaOffset) {
3804     int x1, y1, end;
3805    
3806     /*
3807     * This block is grossly inefficient. For each row in the image, it
3808     * finds each continguous string of transparent pixels, then marks those
3809     * areas as invalid in the validRegion mask. This makes drawing very
3810     * efficient, because of the way we use X: we just say, here's your
3811     * mask, and here's your data. We need not worry about the current
3812     * background color, etc. But this costs us a lot on the image setup.
3813     * Still, image setup only happens once, whereas the drawing happens
3814     * many times, so this might be the best way to go.
3815     *
3816     * An alternative might be to not set up this mask, and instead, at
3817     * drawing time, for each transparent pixel, set its color to the
3818     * color of the background behind that pixel. This is what I suspect
3819     * most of programs do. However, they don't have to deal with the canvas,
3820     * which could have many different background colors. Determining the
3821     * correct bg color for a given pixel might be expensive.
3822     */
3823    
3824     destLinePtr = masterPtr->pix24 + (y * masterPtr->width + x) * 4 + 3;
3825     for (y1 = 0; y1 < height; y1++) {
3826     x1 = 0;
3827     destPtr = destLinePtr;
3828     while (x1 < width) {
3829     /* search for first non-transparent pixel */
3830     while ((x1 < width) && !*destPtr) {
3831     x1++; destPtr += 4;
3832     }
3833     end = x1;
3834     /* search for first transparent pixel */
3835     while ((end < width) && *destPtr) {
3836     end++; destPtr += 4;
3837     }
3838     if (end > x1) {
3839     rect.x = x + x1;
3840     rect.y = y + y1;
3841     rect.width = end - x1;
3842     rect.height = 1;
3843     TkUnionRectWithRegion(&rect, masterPtr->validRegion,
3844     masterPtr->validRegion);
3845     }
3846     x1 = end;
3847     }
3848     destLinePtr += masterPtr->width * 4;
3849     }
3850     } else {
3851     rect.x = x;
3852     rect.y = y;
3853     rect.width = width;
3854     rect.height = height;
3855     TkUnionRectWithRegion(&rect, masterPtr->validRegion,
3856     masterPtr->validRegion);
3857     }
3858    
3859     /*
3860     * Update each instance.
3861     */
3862    
3863     Tk_DitherPhoto((Tk_PhotoHandle)masterPtr, x, y, width, height);
3864