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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 71 - (show annotations) (download)
Sat Nov 5 11:07:06 2016 UTC (7 years, 4 months ago) by dashley
File MIME type: text/plain
File size: 148868 byte(s)
Set EOL properties appropriately to facilitate simultaneous Linux and Windows development.
1 /* $Header$ */
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
3865 /*
3866 * Tell the core image code that this image has changed.
3867 */
3868
3869 Tk_ImageChanged(masterPtr->tkMaster, x, y, width, height, masterPtr->width,
3870 masterPtr->height);
3871 }
3872
3873 /*
3874 *----------------------------------------------------------------------
3875 *
3876 * Tk_PhotoPutZoomedBlock --
3877 *
3878 * This procedure is called to put image data into a photo image,
3879 * with possible subsampling and/or zooming of the pixels.
3880 *
3881 * Results:
3882 * None.
3883 *
3884 * Side effects:
3885 * The image data is stored. The image may be expanded.
3886 * The Tk image code is informed that the image has changed.
3887 *
3888 *----------------------------------------------------------------------
3889 */
3890
3891 void
3892 Tk_PhotoPutZoomedBlock(handle, blockPtr, x, y, width, height, zoomX, zoomY,
3893 subsampleX, subsampleY)
3894 Tk_PhotoHandle handle; /* Opaque handle for the photo image
3895 * to be updated. */
3896 register Tk_PhotoImageBlock *blockPtr;
3897 /* Pointer to a structure describing the
3898 * pixel data to be copied into the image. */
3899 int x, y; /* Coordinates of the top-left pixel to
3900 * be updated in the image. */
3901 int width, height; /* Dimensions of the area of the image
3902 * to be updated. */
3903 int zoomX, zoomY; /* Zoom factors for the X and Y axes. */
3904 int subsampleX, subsampleY; /* Subsampling factors for the X and Y axes. */
3905 {
3906 register PhotoMaster *masterPtr;
3907 int xEnd, yEnd;
3908 int greenOffset, blueOffset, alphaOffset;
3909 int wLeft, hLeft;
3910 int wCopy, hCopy;
3911 int blockWid, blockHt;
3912 unsigned char *srcPtr, *srcLinePtr, *srcOrigPtr;
3913 unsigned char *destPtr, *destLinePtr;
3914 int pitch;
3915 int xRepeat, yRepeat;
3916 int blockXSkip, blockYSkip;
3917 XRectangle rect;
3918
3919 if ((zoomX == 1) && (zoomY == 1) && (subsampleX == 1)
3920 && (subsampleY == 1)) {
3921 Tk_PhotoPutBlock(handle, blockPtr, x, y, width, height);
3922 return;
3923 }
3924
3925 masterPtr = (PhotoMaster *) handle;
3926
3927 if ((zoomX <= 0) || (zoomY <= 0))
3928 return;
3929 if ((masterPtr->userWidth != 0) && ((x + width) > masterPtr->userWidth)) {
3930 width = masterPtr->userWidth - x;
3931 }
3932 if ((masterPtr->userHeight != 0)
3933 && ((y + height) > masterPtr->userHeight)) {
3934 height = masterPtr->userHeight - y;
3935 }
3936 if ((width <= 0) || (height <= 0))
3937 return;
3938
3939 xEnd = x + width;
3940 yEnd = y + height;
3941 if ((xEnd > masterPtr->width) || (yEnd > masterPtr->height)) {
3942 int sameSrc = (blockPtr->pixelPtr == masterPtr->pix24);
3943 ImgPhotoSetSize(masterPtr, MAX(xEnd, masterPtr->width),
3944 MAX(yEnd, masterPtr->height));
3945 if (sameSrc) {
3946 blockPtr->pixelPtr = masterPtr->pix24;
3947 }
3948 }
3949
3950 if ((y < masterPtr->ditherY) || ((y == masterPtr->ditherY)
3951 && (x < masterPtr->ditherX))) {
3952 /*
3953 * The dithering isn't correct past the start of this block.
3954 */
3955
3956 masterPtr->ditherX = x;
3957 masterPtr->ditherY = y;
3958 }
3959
3960 /*
3961 * If this image block could have different red, green and blue
3962 * components, mark it as a color image.
3963 */
3964
3965 greenOffset = blockPtr->offset[1] - blockPtr->offset[0];
3966 blueOffset = blockPtr->offset[2] - blockPtr->offset[0];
3967 alphaOffset = blockPtr->offset[3];
3968 if ((alphaOffset >= blockPtr->pixelSize) || (alphaOffset < 0)) {
3969 alphaOffset = 0;
3970 } else {
3971 alphaOffset -= blockPtr->offset[0];
3972 }
3973 if ((greenOffset != 0) || (blueOffset != 0)) {
3974 masterPtr->flags |= COLOR_IMAGE;
3975 }
3976
3977 /*
3978 * Work out what area the pixel data in the block expands to after
3979 * subsampling and zooming.
3980 */
3981
3982 blockXSkip = subsampleX * blockPtr->pixelSize;
3983 blockYSkip = subsampleY * blockPtr->pitch;
3984 if (subsampleX > 0)
3985 blockWid = ((blockPtr->width + subsampleX - 1) / subsampleX) * zoomX;
3986 else if (subsampleX == 0)
3987 blockWid = width;
3988 else
3989 blockWid = ((blockPtr->width - subsampleX - 1) / -subsampleX) * zoomX;
3990 if (subsampleY > 0)
3991 blockHt = ((blockPtr->height + subsampleY - 1) / subsampleY) * zoomY;
3992 else if (subsampleY == 0)
3993 blockHt = height;
3994 else
3995 blockHt = ((blockPtr->height - subsampleY - 1) / -subsampleY) * zoomY;
3996
3997 /*
3998 * Copy the data into our local 24-bit/pixel array.
3999 */
4000
4001 destLinePtr = masterPtr->pix24 + (y * masterPtr->width + x) * 4;
4002 srcOrigPtr = blockPtr->pixelPtr + blockPtr->offset[0];
4003 if (subsampleX < 0) {
4004 srcOrigPtr += (blockPtr->width - 1) * blockPtr->pixelSize;
4005 }
4006 if (subsampleY < 0) {
4007 srcOrigPtr += (blockPtr->height - 1) * blockPtr->pitch;
4008 }
4009
4010 pitch = masterPtr->width * 4;
4011 for (hLeft = height; hLeft > 0; ) {
4012 hCopy = MIN(hLeft, blockHt);
4013 hLeft -= hCopy;
4014 yRepeat = zoomY;
4015 srcLinePtr = srcOrigPtr;
4016 for (; hCopy > 0; --hCopy) {
4017 destPtr = destLinePtr;
4018 for (wLeft = width; wLeft > 0;) {
4019 wCopy = MIN(wLeft, blockWid);
4020 wLeft -= wCopy;
4021 srcPtr = srcLinePtr;
4022 for (; wCopy > 0; wCopy -= zoomX) {
4023 for (xRepeat = MIN(wCopy, zoomX); xRepeat > 0; xRepeat--) {
4024 if (!destPtr[3]) {
4025 destPtr[0] = destPtr[1] = destPtr[2] = 0xd9;
4026 }
4027 if (!alphaOffset || (srcPtr[alphaOffset] == 255)) {
4028 *destPtr++ = srcPtr[0];
4029 *destPtr++ = srcPtr[greenOffset];
4030 *destPtr++ = srcPtr[blueOffset];
4031 *destPtr++ = 255;
4032 } else {
4033 if (srcPtr[alphaOffset]) {
4034 destPtr[0] += (srcPtr[0] - destPtr[0]) * srcPtr[alphaOffset] / 255;
4035 destPtr[1] += (srcPtr[greenOffset] - destPtr[1]) * srcPtr[alphaOffset] / 255;
4036 destPtr[2] += (srcPtr[blueOffset] - destPtr[2]) * srcPtr[alphaOffset] / 255;
4037 destPtr[3] += (255 - destPtr[3]) * srcPtr[alphaOffset] / 255;
4038 }
4039 destPtr+=4;
4040 }
4041 }
4042 srcPtr += blockXSkip;
4043 }
4044 }
4045 destLinePtr += pitch;
4046 yRepeat--;
4047 if (yRepeat <= 0) {
4048 srcLinePtr += blockYSkip;
4049 yRepeat = zoomY;
4050 }
4051 }
4052 }
4053
4054 /*
4055 * Add this new block to the region that specifies which data is valid.
4056 */
4057
4058 if (alphaOffset) {
4059 int x1, y1, end;
4060
4061 destLinePtr = masterPtr->pix24 + (y * masterPtr->width + x) * 4 + 3;
4062 for (y1 = 0; y1 < height; y1++) {
4063 x1 = 0;
4064 destPtr = destLinePtr;
4065 while (x1 < width) {
4066 /* search for first non-transparent pixel */
4067 while ((x1 < width) && !*destPtr) {
4068 x1++; destPtr += 4;
4069 }
4070 end = x1;
4071 /* search for first transparent pixel */
4072 while ((end < width) && *destPtr) {
4073 end++; destPtr += 4;
4074 }
4075 if (end > x1) {
4076 rect.x = x + x1;
4077 rect.y = y + y1;
4078 rect.width = end - x1;
4079 rect.height = 1;
4080 TkUnionRectWithRegion(&rect, masterPtr->validRegion,
4081 masterPtr->validRegion);
4082 }
4083 x1 = end;
4084 }
4085 destLinePtr += masterPtr->width * 4;
4086 }
4087 } else {
4088 rect.x = x;
4089 rect.y = y;
4090 rect.width = width;
4091 rect.height = height;
4092 TkUnionRectWithRegion(&rect, masterPtr->validRegion,
4093 masterPtr->validRegion);
4094 }
4095
4096 /*
4097 * Update each instance.
4098 */
4099
4100 Tk_DitherPhoto((Tk_PhotoHandle)masterPtr, x, y, width, height);
4101
4102 /*
4103 * Tell the core image code that this image has changed.
4104 */
4105
4106 Tk_ImageChanged(masterPtr->tkMaster, x, y, width, height, masterPtr->width,
4107 masterPtr->height);
4108 }
4109
4110 /*
4111 *----------------------------------------------------------------------
4112 *
4113 * Tk_DitherPhoto --
4114 *
4115 * This procedure is called to update an area of each instance's
4116 * pixmap by dithering the corresponding area of the image master.
4117 *
4118 * Results:
4119 * None.
4120 *
4121 * Side effects:
4122 * The pixmap of each instance of this image gets updated.
4123 * The fields in *masterPtr indicating which area of the image
4124 * is correctly dithered get updated.
4125 *
4126 *----------------------------------------------------------------------
4127 */
4128
4129 void
4130 Tk_DitherPhoto(photo, x, y, width, height)
4131 Tk_PhotoHandle photo; /* Image master whose instances are
4132 * to be updated. */
4133 int x, y; /* Coordinates of the top-left pixel
4134 * in the area to be dithered. */
4135 int width, height; /* Dimensions of the area to be dithered. */
4136 {
4137 PhotoMaster *masterPtr = (PhotoMaster *) photo;
4138 PhotoInstance *instancePtr;
4139
4140 if ((width <= 0) || (height <= 0)) {
4141 return;
4142 }
4143
4144 for (instancePtr = masterPtr->instancePtr; instancePtr != NULL;
4145 instancePtr = instancePtr->nextPtr) {
4146 DitherInstance(instancePtr, x, y, width, height);
4147 }
4148
4149 /*
4150 * Work out whether this block will be correctly dithered
4151 * and whether it will extend the correctly dithered region.
4152 */
4153
4154 if (((y < masterPtr->ditherY)
4155 || ((y == masterPtr->ditherY) && (x <= masterPtr->ditherX)))
4156 && ((y + height) > (masterPtr->ditherY))) {
4157
4158 /*
4159 * This block starts inside (or immediately after) the correctly
4160 * dithered region, so the first scan line at least will be right.
4161 * Furthermore this block extends into scanline masterPtr->ditherY.
4162 */
4163
4164 if ((x == 0) && (width == masterPtr->width)) {
4165 /*
4166 * We are doing the full width, therefore the dithering
4167 * will be correct to the end.
4168 */
4169
4170 masterPtr->ditherX = 0;
4171 masterPtr->ditherY = y + height;
4172 } else {
4173 /*
4174 * We are doing partial scanlines, therefore the
4175 * correctly-dithered region will be extended by
4176 * at most one scan line.
4177 */
4178
4179 if (x <= masterPtr->ditherX) {
4180 masterPtr->ditherX = x + width;
4181 if (masterPtr->ditherX >= masterPtr->width) {
4182 masterPtr->ditherX = 0;
4183 masterPtr->ditherY++;
4184 }
4185 }
4186 }
4187 }
4188
4189 }
4190
4191 /*
4192 *----------------------------------------------------------------------
4193 *
4194 * DitherInstance --
4195 *
4196 * This procedure is called to update an area of an instance's
4197 * pixmap by dithering the corresponding area of the master.
4198 *
4199 * Results:
4200 * None.
4201 *
4202 * Side effects:
4203 * The instance's pixmap gets updated.
4204 *
4205 *----------------------------------------------------------------------
4206 */
4207
4208 static void
4209 DitherInstance(instancePtr, xStart, yStart, width, height)
4210 PhotoInstance *instancePtr; /* The instance to be updated. */
4211 int xStart, yStart; /* Coordinates of the top-left pixel in the
4212 * block to be dithered. */
4213 int width, height; /* Dimensions of the block to be dithered. */
4214 {
4215 PhotoMaster *masterPtr;
4216 ColorTable *colorPtr;
4217 XImage *imagePtr;
4218 int nLines, bigEndian;
4219 int i, c, x, y;
4220 int xEnd, yEnd;
4221 int bitsPerPixel, bytesPerLine, lineLength;
4222 unsigned char *srcLinePtr, *srcPtr;
4223 schar *errLinePtr, *errPtr;
4224 unsigned char *destBytePtr, *dstLinePtr;
4225 pixel *destLongPtr;
4226 pixel firstBit, word, mask;
4227 int col[3];
4228 int doDithering = 1;
4229
4230 colorPtr = instancePtr->colorTablePtr;
4231 masterPtr = instancePtr->masterPtr;
4232
4233 /*
4234 * Turn dithering off in certain cases where it is not
4235 * needed (TrueColor, DirectColor with many colors).
4236 */
4237
4238 if ((colorPtr->visualInfo.class == DirectColor)
4239 || (colorPtr->visualInfo.class == TrueColor)) {
4240 int nRed, nGreen, nBlue, result;
4241
4242 result = sscanf(colorPtr->id.palette, "%d/%d/%d", &nRed,
4243 &nGreen, &nBlue);
4244 if ((nRed >= 256)
4245 && ((result == 1) || ((nGreen >= 256) && (nBlue >= 256)))) {
4246 doDithering = 0;
4247 }
4248 }
4249
4250 /*
4251 * First work out how many lines to do at a time,
4252 * then how many bytes we'll need for pixel storage,
4253 * and allocate it.
4254 */
4255
4256 nLines = (MAX_PIXELS + width - 1) / width;
4257 if (nLines < 1) {
4258 nLines = 1;
4259 }
4260 if (nLines > height ) {
4261 nLines = height;
4262 }
4263
4264 imagePtr = instancePtr->imagePtr;
4265 if (imagePtr == NULL) {
4266 return; /* we must be really tight on memory */
4267 }
4268 bitsPerPixel = imagePtr->bits_per_pixel;
4269 bytesPerLine = ((bitsPerPixel * width + 31) >> 3) & ~3;
4270 imagePtr->width = width;
4271 imagePtr->height = nLines;
4272 imagePtr->bytes_per_line = bytesPerLine;
4273 imagePtr->data = (char *) ckalloc((unsigned) (imagePtr->bytes_per_line * nLines));
4274 bigEndian = imagePtr->bitmap_bit_order == MSBFirst;
4275 firstBit = bigEndian? (1 << (imagePtr->bitmap_unit - 1)): 1;
4276
4277 lineLength = masterPtr->width * 3;
4278 srcLinePtr = masterPtr->pix24 + (yStart * masterPtr->width + xStart) * 4;
4279 errLinePtr = instancePtr->error + yStart * lineLength + xStart * 3;
4280 xEnd = xStart + width;
4281
4282 /*
4283 * Loop over the image, doing at most nLines lines before
4284 * updating the screen image.
4285 */
4286
4287 for (; height > 0; height -= nLines) {
4288 if (nLines > height) {
4289 nLines = height;
4290 }
4291 dstLinePtr = (unsigned char *) imagePtr->data;
4292 yEnd = yStart + nLines;
4293 for (y = yStart; y < yEnd; ++y) {
4294 srcPtr = srcLinePtr;
4295 errPtr = errLinePtr;
4296 destBytePtr = dstLinePtr;
4297 destLongPtr = (pixel *) dstLinePtr;
4298 if (colorPtr->flags & COLOR_WINDOW) {
4299 /*
4300 * Color window. We dither the three components
4301 * independently, using Floyd-Steinberg dithering,
4302 * which propagates errors from the quantization of
4303 * pixels to the pixels below and to the right.
4304 */
4305
4306 for (x = xStart; x < xEnd; ++x) {
4307 if (doDithering) {
4308 for (i = 0; i < 3; ++i) {
4309 /*
4310 * Compute the error propagated into this pixel
4311 * for this component.
4312 * If e[x,y] is the array of quantization error
4313 * values, we compute
4314 * 7/16 * e[x-1,y] + 1/16 * e[x-1,y-1]
4315 * + 5/16 * e[x,y-1] + 3/16 * e[x+1,y-1]
4316 * and round it to an integer.
4317 *
4318 * The expression ((c + 2056) >> 4) - 128
4319 * computes round(c / 16), and works correctly on
4320 * machines without a sign-extending right shift.
4321 */
4322
4323 c = (x > 0) ? errPtr[-3] * 7: 0;
4324 if (y > 0) {
4325 if (x > 0) {
4326 c += errPtr[-lineLength-3];
4327 }
4328 c += errPtr[-lineLength] * 5;
4329 if ((x + 1) < masterPtr->width) {
4330 c += errPtr[-lineLength+3] * 3;
4331 }
4332 }
4333
4334 /*
4335 * Add the propagated error to the value of this
4336 * component, quantize it, and store the
4337 * quantization error.
4338 */
4339
4340 c = ((c + 2056) >> 4) - 128 + *srcPtr++;
4341 if (c < 0) {
4342 c = 0;
4343 } else if (c > 255) {
4344 c = 255;
4345 }
4346 col[i] = colorPtr->colorQuant[i][c];
4347 *errPtr++ = c - col[i];
4348 }
4349 } else {
4350 /*
4351 * Output is virtually continuous in this case,
4352 * so don't bother dithering.
4353 */
4354
4355 col[0] = *srcPtr++;
4356 col[1] = *srcPtr++;
4357 col[2] = *srcPtr++;
4358 }
4359 srcPtr++;
4360
4361 /*
4362 * Translate the quantized component values into
4363 * an X pixel value, and store it in the image.
4364 */
4365
4366 i = colorPtr->redValues[col[0]]
4367 + colorPtr->greenValues[col[1]]
4368 + colorPtr->blueValues[col[2]];
4369 if (colorPtr->flags & MAP_COLORS) {
4370 i = colorPtr->pixelMap[i];
4371 }
4372 switch (bitsPerPixel) {
4373 case NBBY:
4374 *destBytePtr++ = i;
4375 break;
4376 #ifndef __WIN32__
4377 /*
4378 * This case is not valid for Windows because the image format is different
4379 * from the pixel format in Win32. Eventually we need to fix the image
4380 * code in Tk to use the Windows native image ordering. This would speed
4381 * up the image code for all of the common sizes.
4382 */
4383
4384 case NBBY * sizeof(pixel):
4385 *destLongPtr++ = i;
4386 break;
4387 #endif
4388 default:
4389 XPutPixel(imagePtr, x - xStart, y - yStart,
4390 (unsigned) i);
4391 }
4392 }
4393
4394 } else if (bitsPerPixel > 1) {
4395 /*
4396 * Multibit monochrome window. The operation here is similar
4397 * to the color window case above, except that there is only
4398 * one component. If the master image is in color, use the
4399 * luminance computed as
4400 * 0.344 * red + 0.5 * green + 0.156 * blue.
4401 */
4402
4403 for (x = xStart; x < xEnd; ++x) {
4404 c = (x > 0) ? errPtr[-1] * 7: 0;
4405 if (y > 0) {
4406 if (x > 0) {
4407 c += errPtr[-lineLength-1];
4408 }
4409 c += errPtr[-lineLength] * 5;
4410 if (x + 1 < masterPtr->width) {
4411 c += errPtr[-lineLength+1] * 3;
4412 }
4413 }
4414 c = ((c + 2056) >> 4) - 128;
4415
4416 if ((masterPtr->flags & COLOR_IMAGE) == 0) {
4417 c += srcPtr[0];
4418 } else {
4419 c += (unsigned)(srcPtr[0] * 11 + srcPtr[1] * 16
4420 + srcPtr[2] * 5 + 16) >> 5;
4421 }
4422 srcPtr += 4;
4423
4424 if (c < 0) {
4425 c = 0;
4426 } else if (c > 255) {
4427 c = 255;
4428 }
4429 i = colorPtr->colorQuant[0][c];
4430 *errPtr++ = c - i;
4431 i = colorPtr->redValues[i];
4432 switch (bitsPerPixel) {
4433 case NBBY:
4434 *destBytePtr++ = i;
4435 break;
4436 #ifndef __WIN32__
4437 /*
4438 * This case is not valid for Windows because the image format is different
4439 * from the pixel format in Win32. Eventually we need to fix the image
4440 * code in Tk to use the Windows native image ordering. This would speed
4441 * up the image code for all of the common sizes.
4442 */
4443
4444 case NBBY * sizeof(pixel):
4445 *destLongPtr++ = i;
4446 break;
4447 #endif
4448 default:
4449 XPutPixel(imagePtr, x - xStart, y - yStart,
4450 (unsigned) i);
4451 }
4452 }
4453 } else {
4454 /*
4455 * 1-bit monochrome window. This is similar to the
4456 * multibit monochrome case above, except that the
4457 * quantization is simpler (we only have black = 0
4458 * and white = 255), and we produce an XY-Bitmap.
4459 */
4460
4461 word = 0;
4462 mask = firstBit;
4463 for (x = xStart; x < xEnd; ++x) {
4464 /*
4465 * If we have accumulated a whole word, store it
4466 * in the image and start a new word.
4467 */
4468
4469 if (mask == 0) {
4470 *destLongPtr++ = word;
4471 mask = firstBit;
4472 word = 0;
4473 }
4474
4475 c = (x > 0) ? errPtr[-1] * 7: 0;
4476 if (y > 0) {
4477 if (x > 0) {
4478 c += errPtr[-lineLength-1];
4479 }
4480 c += errPtr[-lineLength] * 5;
4481 if (x + 1 < masterPtr->width) {
4482 c += errPtr[-lineLength+1] * 3;
4483 }
4484 }
4485 c = ((c + 2056) >> 4) - 128;
4486
4487 if ((masterPtr->flags & COLOR_IMAGE) == 0) {
4488 c += srcPtr[0];
4489 } else {
4490 c += (unsigned)(srcPtr[0] * 11 + srcPtr[1] * 16
4491 + srcPtr[2] * 5 + 16) >> 5;
4492 }
4493 srcPtr += 4;
4494
4495 if (c < 0) {
4496 c = 0;
4497 } else if (c > 255) {
4498 c = 255;
4499 }
4500 if (c >= 128) {
4501 word |= mask;
4502 *errPtr++ = c - 255;
4503 } else {
4504 *errPtr++ = c;
4505 }
4506 mask = bigEndian? (mask >> 1): (mask << 1);
4507 }
4508 *destLongPtr = word;
4509 }
4510 srcLinePtr += masterPtr->width * 4;
4511 errLinePtr += lineLength;
4512 dstLinePtr += bytesPerLine;
4513 }
4514
4515 /*
4516 * Update the pixmap for this instance with the block of
4517 * pixels that we have just computed.
4518 */
4519
4520 TkPutImage(colorPtr->pixelMap, colorPtr->numColors,
4521 instancePtr->display, instancePtr->pixels,
4522 instancePtr->gc, imagePtr, 0, 0, xStart, yStart,
4523 (unsigned) width, (unsigned) nLines);
4524 yStart = yEnd;
4525
4526 }
4527
4528 ckfree(imagePtr->data);
4529 imagePtr->data = NULL;
4530 }
4531
4532 /*
4533 *----------------------------------------------------------------------
4534 *
4535 * Tk_PhotoBlank --
4536 *
4537 * This procedure is called to clear an entire photo image.
4538 *
4539 * Results:
4540 * None.
4541 *
4542 * Side effects:
4543 * The valid region for the image is set to the null region.
4544 * The generic image code is notified that the image has changed.
4545 *
4546 *----------------------------------------------------------------------
4547 */
4548
4549 void
4550 Tk_PhotoBlank(handle)
4551 Tk_PhotoHandle handle; /* Handle for the image to be blanked. */
4552 {
4553 PhotoMaster *masterPtr;
4554 PhotoInstance *instancePtr;
4555
4556 masterPtr = (PhotoMaster *) handle;
4557 masterPtr->ditherX = masterPtr->ditherY = 0;
4558 masterPtr->flags = 0;
4559
4560 /*
4561 * The image has valid data nowhere.
4562 */
4563
4564 if (masterPtr->validRegion != NULL) {
4565 TkDestroyRegion(masterPtr->validRegion);
4566 }
4567 masterPtr->validRegion = TkCreateRegion();
4568
4569 /*
4570 * Clear out the 24-bit pixel storage array.
4571 * Clear out the dithering error arrays for each instance.
4572 */
4573
4574 memset((VOID *) masterPtr->pix24, 0,
4575 (size_t) (masterPtr->width * masterPtr->height * 4));
4576 for (instancePtr = masterPtr->instancePtr; instancePtr != NULL;
4577 instancePtr = instancePtr->nextPtr) {
4578 if (instancePtr->error) {
4579 memset((VOID *) instancePtr->error, 0,
4580 (size_t) (masterPtr->width * masterPtr->height
4581 * 3 * sizeof(schar)));
4582 }
4583 }
4584
4585 /*
4586 * Tell the core image code that this image has changed.
4587 */
4588
4589 Tk_ImageChanged(masterPtr->tkMaster, 0, 0, masterPtr->width,
4590 masterPtr->height, masterPtr->width, masterPtr->height);
4591 }
4592
4593 /*
4594 *----------------------------------------------------------------------
4595 *
4596 * Tk_PhotoExpand --
4597 *
4598 * This procedure is called to request that a photo image be
4599 * expanded if necessary to be at least `width' pixels wide and
4600 * `height' pixels high. If the user has declared a definite
4601 * image size (using the -width and -height configuration
4602 * options) then this call has no effect.
4603 *
4604 * Results:
4605 * None.
4606 *
4607 * Side effects:
4608 * The size of the photo image may change; if so the generic
4609 * image code is informed.
4610 *
4611 *----------------------------------------------------------------------
4612 */
4613
4614 void
4615 Tk_PhotoExpand(handle, width, height)
4616 Tk_PhotoHandle handle; /* Handle for the image to be expanded. */
4617 int width, height; /* Desired minimum dimensions of the image. */
4618 {
4619 PhotoMaster *masterPtr;
4620
4621 masterPtr = (PhotoMaster *) handle;
4622
4623 if (width <= masterPtr->width) {
4624 width = masterPtr->width;
4625 }
4626 if (height <= masterPtr->height) {
4627 height = masterPtr->height;
4628 }
4629 if ((width != masterPtr->width) || (height != masterPtr->height)) {
4630 ImgPhotoSetSize(masterPtr, MAX(width, masterPtr->width),
4631 MAX(height, masterPtr->height));
4632 Tk_ImageChanged(masterPtr->tkMaster, 0, 0, 0, 0, masterPtr->width,
4633 masterPtr->height);
4634 }
4635 }
4636
4637 /*
4638 *----------------------------------------------------------------------
4639 *
4640 * Tk_PhotoGetSize --
4641 *
4642 * This procedure is called to obtain the current size of a photo
4643 * image.
4644 *
4645 * Results:
4646 * The image's width and height are returned in *widthp
4647 * and *heightp.
4648 *
4649 * Side effects:
4650 * None.
4651 *
4652 *----------------------------------------------------------------------
4653 */
4654
4655 void
4656 Tk_PhotoGetSize(handle, widthPtr, heightPtr)
4657 Tk_PhotoHandle handle; /* Handle for the image whose dimensions
4658 * are requested. */
4659 int *widthPtr, *heightPtr; /* The dimensions of the image are returned
4660 * here. */
4661 {
4662 PhotoMaster *masterPtr;
4663
4664 masterPtr = (PhotoMaster *) handle;
4665 *widthPtr = masterPtr->width;
4666 *heightPtr = masterPtr->height;
4667 }
4668
4669 /*
4670 *----------------------------------------------------------------------
4671 *
4672 * Tk_PhotoSetSize --
4673 *
4674 * This procedure is called to set size of a photo image.
4675 * This call is equivalent to using the -width and -height
4676 * configuration options.
4677 *
4678 * Results:
4679 * None.
4680 *
4681 * Side effects:
4682 * The size of the image may change; if so the generic
4683 * image code is informed.
4684 *
4685 *----------------------------------------------------------------------
4686 */
4687
4688 void
4689 Tk_PhotoSetSize(handle, width, height)
4690 Tk_PhotoHandle handle; /* Handle for the image whose size is to
4691 * be set. */
4692 int width, height; /* New dimensions for the image. */
4693 {
4694 PhotoMaster *masterPtr;
4695
4696 masterPtr = (PhotoMaster *) handle;
4697
4698 masterPtr->userWidth = width;
4699 masterPtr->userHeight = height;
4700 ImgPhotoSetSize(masterPtr, ((width > 0) ? width: masterPtr->width),
4701 ((height > 0) ? height: masterPtr->height));
4702 Tk_ImageChanged(masterPtr->tkMaster, 0, 0, 0, 0,
4703 masterPtr->width, masterPtr->height);
4704 }
4705
4706 /*
4707 *----------------------------------------------------------------------
4708 *
4709 * ImgGetPhoto --
4710 *
4711 * This procedure is called to obtain image data from a photo
4712 * image. This procedure fills in the Tk_PhotoImageBlock structure
4713 * pointed to by `blockPtr' with details of the address and
4714 * layout of the image data in memory.
4715 *
4716 * Results:
4717 * A pointer to the allocated data which should be freed later.
4718 * NULL if there is no need to free data because
4719 * blockPtr->pixelPtr points directly to the image data.
4720 *
4721 * Side effects:
4722 * None.
4723 *
4724 *----------------------------------------------------------------------
4725 */
4726
4727 static char *
4728 ImgGetPhoto(masterPtr, blockPtr, optPtr)
4729 PhotoMaster *masterPtr; /* Handle for the photo image from which
4730 * image data is desired. */
4731 Tk_PhotoImageBlock *blockPtr;
4732 /* Information about the address and layout
4733 * of the image data is returned here. */
4734 struct SubcommandOptions *optPtr;
4735 {
4736 unsigned char *pixelPtr;
4737 int x, y, greenOffset, blueOffset, alphaOffset;
4738
4739 Tk_PhotoGetImage((Tk_PhotoHandle) masterPtr, blockPtr);
4740 blockPtr->pixelPtr += optPtr->fromY * blockPtr->pitch
4741 + optPtr->fromX * blockPtr->pixelSize;
4742 blockPtr->width = optPtr->fromX2 - optPtr->fromX;
4743 blockPtr->height = optPtr->fromY2 - optPtr->fromY;
4744
4745 if (!(masterPtr->flags & COLOR_IMAGE) &&
4746 (!(optPtr->options & OPT_BACKGROUND)
4747 || ((optPtr->background->red == optPtr->background->green)
4748 && (optPtr->background->red == optPtr->background->blue)))) {
4749 blockPtr->offset[0] = blockPtr->offset[1] =
4750 blockPtr->offset[2];
4751 }
4752 alphaOffset = 0;
4753 for (y = 0; y < blockPtr->height; y++) {
4754 pixelPtr = blockPtr->pixelPtr + (y * blockPtr->pitch)
4755 + blockPtr->pixelSize - 1;
4756 for (x = 0; x < blockPtr->width; x++) {
4757 if (*pixelPtr != 255) {
4758 alphaOffset = 3; break;
4759 }
4760 pixelPtr += blockPtr->pixelSize;
4761 }
4762 if (alphaOffset) break;
4763 }
4764 if (!alphaOffset) {
4765 blockPtr->pixelPtr--;
4766 blockPtr->offset[0]++;
4767 blockPtr->offset[1]++;
4768 blockPtr->offset[2]++;
4769 }
4770 greenOffset = blockPtr->offset[1] - blockPtr->offset[0];
4771 blueOffset = blockPtr->offset[2] - blockPtr->offset[0];
4772 if (((optPtr->options & OPT_BACKGROUND) && alphaOffset) ||
4773 ((optPtr->options & OPT_GRAYSCALE) && (greenOffset || blueOffset))) {
4774 int newPixelSize,x,y;
4775 unsigned char *srcPtr, *destPtr;
4776 char *data;
4777
4778 newPixelSize = (!(optPtr->options & OPT_BACKGROUND) && alphaOffset) ? 2 : 1;
4779 if ((greenOffset || blueOffset) && !(optPtr->options & OPT_GRAYSCALE)) {
4780 newPixelSize += 2;
4781 }
4782 data = ckalloc((unsigned int) (newPixelSize *
4783 blockPtr->width * blockPtr->height));
4784 srcPtr = blockPtr->pixelPtr + blockPtr->offset[0];
4785 destPtr = (unsigned char *) data;
4786 if (!greenOffset && !blueOffset) {
4787 for (y = blockPtr->height; y > 0; y--) {
4788 for (x = blockPtr->width; x > 0; x--) {
4789 *destPtr = *srcPtr;
4790 srcPtr += blockPtr->pixelSize;
4791 destPtr += newPixelSize;
4792 }
4793 srcPtr += blockPtr->pitch - (blockPtr->width * blockPtr->pixelSize);
4794 }
4795 } else if (optPtr->options & OPT_GRAYSCALE) {
4796 for (y = blockPtr->height; y > 0; y--) {
4797 for (x = blockPtr->width; x > 0; x--) {
4798 *destPtr = (unsigned char) ((srcPtr[0] * 11 + srcPtr[1] * 16
4799 + srcPtr[2] * 5 + 16) >> 5);
4800 srcPtr += blockPtr->pixelSize;
4801 destPtr += newPixelSize;
4802 }
4803 srcPtr += blockPtr->pitch - (blockPtr->width * blockPtr->pixelSize);
4804 }
4805 } else {
4806 for (y = blockPtr->height; y > 0; y--) {
4807 for (x = blockPtr->width; x > 0; x--) {
4808 destPtr[0] = srcPtr[0];
4809 destPtr[1] = srcPtr[1];
4810 destPtr[2] = srcPtr[2];
4811 srcPtr += blockPtr->pixelSize;
4812 destPtr += newPixelSize;
4813 }
4814 srcPtr += blockPtr->pitch - (blockPtr->width * blockPtr->pixelSize);
4815 }
4816 }
4817 srcPtr = blockPtr->pixelPtr + alphaOffset;
4818 destPtr = (unsigned char *) data;
4819 if (!alphaOffset) {
4820 /* nothing to be done */
4821 } else if (optPtr->options & OPT_BACKGROUND) {
4822 if (newPixelSize > 2) {
4823 int red = optPtr->background->red>>8;
4824 int green = optPtr->background->green>>8;
4825 int blue = optPtr->background->blue>>8;
4826 for (y = blockPtr->height; y > 0; y--) {
4827 for (x = blockPtr->width; x > 0; x--) {
4828 destPtr[0] += (unsigned char) (((255 - *srcPtr) *
4829 (red-destPtr[0])) / 255);
4830 destPtr[1] += (unsigned char) (((255 - *srcPtr) *
4831 (green-destPtr[1])) / 255);
4832 destPtr[2] += (unsigned char) (((255 - *srcPtr) *
4833 (blue-destPtr[2])) / 255);
4834 srcPtr += blockPtr->pixelSize;
4835 destPtr += newPixelSize;
4836 }
4837 srcPtr += blockPtr->pitch - (blockPtr->width * blockPtr->pixelSize);
4838 }
4839 } else {
4840 int gray = (unsigned char) (((optPtr->background->red>>8) * 11
4841 + (optPtr->background->green>>8) * 16
4842 + (optPtr->background->blue>>8) * 5 + 16) >> 5);
4843 for (y = blockPtr->height; y > 0; y--) {
4844 for (x = blockPtr->width; x > 0; x--) {
4845 destPtr[0] += ((255 - *srcPtr) *
4846 (gray-destPtr[0])) / 255;
4847 srcPtr += blockPtr->pixelSize;
4848 destPtr += newPixelSize;
4849 }
4850 srcPtr += blockPtr->pitch - (blockPtr->width * blockPtr->pixelSize);
4851 }
4852 }
4853 } else {
4854 destPtr += newPixelSize-1;
4855 for (y = blockPtr->height; y > 0; y--) {
4856 for (x = blockPtr->width; x > 0; x--) {
4857 *destPtr = *srcPtr;
4858 srcPtr += blockPtr->pixelSize;
4859 destPtr += newPixelSize;
4860 }
4861 srcPtr += blockPtr->pitch - (blockPtr->width * blockPtr->pixelSize);
4862 }
4863 }
4864 blockPtr->pixelPtr = (unsigned char *) data;
4865 blockPtr->pixelSize = newPixelSize;
4866 blockPtr->pitch = newPixelSize * blockPtr->width;
4867 blockPtr->offset[0] = 0;
4868 if (newPixelSize>2) {
4869 blockPtr->offset[1]= 1;
4870 blockPtr->offset[2]= 2;
4871 } else {
4872 blockPtr->offset[1]= 0;
4873 blockPtr->offset[2]= 0;
4874 }
4875 return data;
4876 }
4877 return NULL;
4878 }
4879
4880 /*
4881 *----------------------------------------------------------------------
4882 *
4883 * ImgStringWrite --
4884 *
4885 * Default string write function. The data is formatted in
4886 * the default format as accepted by the "<img> put" command.
4887 *
4888 * Results:
4889 * A standard Tcl result.
4890 *
4891 * Side effects:
4892 * See the user documentation.
4893 *
4894 *----------------------------------------------------------------------
4895 */
4896
4897 static int
4898 ImgStringWrite(interp, formatString, blockPtr)
4899 Tcl_Interp *interp;
4900 Tcl_Obj *formatString;
4901 Tk_PhotoImageBlock *blockPtr;
4902 {
4903 int row,col;
4904 char *line, *linePtr;
4905 unsigned char *pixelPtr;
4906 int greenOffset, blueOffset;
4907 Tcl_DString data;
4908
4909 greenOffset = blockPtr->offset[1] - blockPtr->offset[0];
4910 blueOffset = blockPtr->offset[2] - blockPtr->offset[0];
4911
4912 Tcl_DStringInit(&data);
4913 if ((blockPtr->width > 0) && (blockPtr->height > 0)) {
4914 line = (char *) ckalloc((unsigned int) ((8 * blockPtr->width) + 2));
4915 for (row=0; row<blockPtr->height; row++) {
4916 pixelPtr = blockPtr->pixelPtr + blockPtr->offset[0] +
4917 row * blockPtr->pitch;
4918 linePtr = line;
4919 for (col=0; col<blockPtr->width; col++) {
4920 sprintf(linePtr, " #%02x%02x%02x", *pixelPtr,
4921 pixelPtr[greenOffset], pixelPtr[blueOffset]);
4922 pixelPtr += blockPtr->pixelSize;
4923 linePtr += 8;
4924 }
4925 Tcl_DStringAppendElement(&data, line+1);
4926 }
4927 ckfree (line);
4928 }
4929 Tcl_DStringResult(interp, &data);
4930 return TCL_OK;
4931 }
4932
4933 /*
4934 *----------------------------------------------------------------------
4935 *
4936 * Tk_PhotoGetImage --
4937 *
4938 * This procedure is called to obtain image data from a photo
4939 * image. This procedure fills in the Tk_PhotoImageBlock structure
4940 * pointed to by `blockPtr' with details of the address and
4941 * layout of the image data in memory.
4942 *
4943 * Results:
4944 * TRUE (1) indicating that image data is available,
4945 * for backwards compatibility with the old photo widget.
4946 *
4947 * Side effects:
4948 * None.
4949 *
4950 *----------------------------------------------------------------------
4951 */
4952
4953 int
4954 Tk_PhotoGetImage(handle, blockPtr)
4955 Tk_PhotoHandle handle; /* Handle for the photo image from which
4956 * image data is desired. */
4957 Tk_PhotoImageBlock *blockPtr;
4958 /* Information about the address and layout
4959 * of the image data is returned here. */
4960 {
4961 PhotoMaster *masterPtr;
4962
4963 masterPtr = (PhotoMaster *) handle;
4964 blockPtr->pixelPtr = masterPtr->pix24;
4965 blockPtr->width = masterPtr->width;
4966 blockPtr->height = masterPtr->height;
4967 blockPtr->pitch = masterPtr->width * 4;
4968 blockPtr->pixelSize = 4;
4969 blockPtr->offset[0] = 0;
4970 blockPtr->offset[1] = 1;
4971 blockPtr->offset[2] = 2;
4972 blockPtr->offset[3] = 3;
4973 return 1;
4974 }
4975
4976 /*
4977 *----------------------------------------------------------------------
4978 *
4979 * PhotoOptionFind --
4980 *
4981 * Finds a specific Photo option.
4982 *
4983 * Results:
4984 * None.
4985 *
4986 * Side effects:
4987 * After commands are removed.
4988 *
4989 *----------------------------------------------------------------------
4990 */
4991
4992 typedef struct OptionAssocData {
4993 struct OptionAssocData *nextPtr; /* pointer to next OptionAssocData */
4994 Tcl_ObjCmdProc *command; /* command associated with this
4995 * option */
4996 char name[1]; /* name of option (remaining chars) */
4997 } OptionAssocData;
4998
4999 static Tcl_ObjCmdProc *
5000 PhotoOptionFind(interp, obj)
5001 Tcl_Interp *interp; /* Interpreter that is being deleted. */
5002 Tcl_Obj *obj; /* Name of option to be found. */
5003 {
5004 size_t length;
5005 char *name = Tcl_GetStringFromObj(obj, (int *) &length);
5006 OptionAssocData *list;
5007 char *prevname = NULL;
5008 Tcl_ObjCmdProc *proc = (Tcl_ObjCmdProc *) NULL;
5009 list = (OptionAssocData *) Tcl_GetAssocData(interp, "photoOption",
5010 (Tcl_InterpDeleteProc **) NULL);
5011 while (list != (OptionAssocData *) NULL) {
5012 if (strncmp(name, list->name, length) == 0) {
5013 if (proc != (Tcl_ObjCmdProc *) NULL) {
5014 Tcl_ResetResult(interp);
5015 Tcl_AppendResult(interp, "ambiguous option \"", name,
5016 "\": must be ", prevname, (char *) NULL);
5017 while (list->nextPtr != (OptionAssocData *) NULL) {
5018 Tcl_AppendResult(interp, prevname, ", ",(char *) NULL);
5019 list = list->nextPtr;
5020 prevname = list->name;
5021 }
5022 Tcl_AppendResult(interp, ", or", prevname, (char *) NULL);
5023 return (Tcl_ObjCmdProc *) NULL;
5024 }
5025 proc = list->command;
5026 prevname = list->name;
5027 }
5028 list = list->nextPtr;
5029 }
5030 if (proc != (Tcl_ObjCmdProc *) NULL) {
5031 Tcl_ResetResult(interp);
5032 }
5033 return proc;
5034 }
5035
5036 /*
5037 *----------------------------------------------------------------------
5038 *
5039 * PhotoOptionCleanupProc --
5040 *
5041 * This procedure is invoked whenever an interpreter is deleted
5042 * to cleanup the AssocData for "photoVisitor".
5043 *
5044 * Results:
5045 * None.
5046 *
5047 * Side effects:
5048 * Photo Visitor options are removed.
5049 *
5050 *----------------------------------------------------------------------
5051 */
5052
5053 static void
5054 PhotoOptionCleanupProc(clientData, interp)
5055 ClientData clientData; /* Points to "photoVisitor" AssocData
5056 * for the interpreter. */
5057 Tcl_Interp *interp; /* Interpreter that is being deleted. */
5058 {
5059 OptionAssocData *list = (OptionAssocData *) clientData;
5060 OptionAssocData *ptr;
5061
5062 while (list != NULL) {
5063 list = (ptr = list)->nextPtr;
5064 ckfree((char *) ptr);
5065 }
5066 }
5067
5068 /*
5069 *--------------------------------------------------------------
5070 *
5071 * Tk_CreatePhotoOption --
5072 *
5073 * This procedure may be invoked to add a new kind of photo
5074 * option to the core photo command supported by Tk.
5075 *
5076 * Results:
5077 * None.
5078 *
5079 * Side effects:
5080 * From now on, the new option will be useable by the
5081 * photo command.
5082 *
5083 *--------------------------------------------------------------
5084 */
5085
5086 void
5087 Tk_CreatePhotoOption(interp, name, proc)
5088 Tcl_Interp *interp; /* interpreter */
5089 CONST char *name; /* option name */
5090 Tcl_ObjCmdProc *proc; /* proc to execute command */
5091 {
5092 OptionAssocData *typePtr2, *prevPtr, *ptr;
5093 OptionAssocData *list;
5094
5095 list = (OptionAssocData *) Tcl_GetAssocData(interp, "photoOption",
5096 (Tcl_InterpDeleteProc **) NULL);
5097
5098 /*
5099 * If there's already a photo option with the given name, remove it.
5100 */
5101
5102 for (typePtr2 = list, prevPtr = NULL; typePtr2 != NULL;
5103 prevPtr = typePtr2, typePtr2 = typePtr2->nextPtr) {
5104 if (strcmp(typePtr2->name, name) == 0) {
5105 if (prevPtr == NULL) {
5106 list = typePtr2->nextPtr;
5107 } else {
5108 prevPtr->nextPtr = typePtr2->nextPtr;
5109 }
5110 ckfree((char *) typePtr2);
5111 break;
5112 }
5113 }
5114 ptr = (OptionAssocData *) ckalloc(sizeof(OptionAssocData) + strlen(name));
5115 strcpy(&(ptr->name[0]), name);
5116 ptr->command = proc;
5117 ptr->nextPtr = list;
5118 Tcl_SetAssocData(interp, "photoOption", PhotoOptionCleanupProc,
5119 (ClientData) ptr);
5120 }
5121
5122 /*
5123 *--------------------------------------------------------------
5124 *
5125 * TkPostscriptPhoto --
5126 *
5127 * This procedure is called to output the contents of a
5128 * photo image in Postscript by calling the Tk_PostscriptPhoto
5129 * function.
5130 *
5131 * Results:
5132 * Returns a standard Tcl return value.
5133 *
5134 * Side effects:
5135 * None.
5136 *
5137 *--------------------------------------------------------------
5138 */
5139 static int
5140 ImgPhotoPostscript(clientData, interp, tkwin, psInfo,
5141 x, y, width, height, prepass)
5142 ClientData clientData;
5143 Tcl_Interp *interp;
5144 Tk_Window tkwin;
5145 Tk_PostscriptInfo psInfo; /* postscript info */
5146 int x, y; /* First pixel to output */
5147 int width, height; /* Width and height of area */
5148 int prepass;
5149 {
5150 Tk_PhotoImageBlock block;
5151
5152 Tk_PhotoGetImage((Tk_PhotoHandle) clientData, &block);
5153 block.pixelPtr += y * block.pitch + x * block.pixelSize;
5154
5155 return Tk_PostscriptPhoto(interp, &block, psInfo, width, height);
5156 }
5157
5158 /* End of tkimgphoto.c */

Properties

Name Value
svn:eol-style native
svn:keywords Header

dashley@gmail.com
ViewVC Help
Powered by ViewVC 1.1.25