1 /*
2 * tkImgPhoto.c --
3 *
4 * Implements images of type "photo" for Tk. Photo images are stored in
5 * full color (32 bits per pixel including alpha channel) and displayed
6 * using dithering if necessary.
7 *
8 * Copyright (c) 1994 The Australian National University.
9 * Copyright (c) 1994-1997 Sun Microsystems, Inc.
10 * Copyright (c) 2002-2003 Donal K. Fellows
11 * Copyright (c) 2003 ActiveState Corporation.
12 *
13 * See the file "license.terms" for information on usage and redistribution of
14 * 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
21 #include "tkInt.h"
22 #include <ctype.h>
23
24 #ifdef __WIN32__
25 #include "tkWinInt.h"
26 #elif defined(__CYGWIN__)
27 #include "tkUnixInt.h"
28 #endif
29
30 /*
31 * Declaration for internal Xlib function used here:
32 */
33
34 extern int _XInitImageFuncPtrs(XImage *image);
35
36 /*
37 * A signed 8-bit integral type. If chars are unsigned and the compiler isn't
38 * an ANSI one, then we have to use short instead (which wastes space) to get
39 * signed behavior.
40 */
41
42 #if defined(__STDC__) || defined(_AIX)
43 typedef signed char schar;
44 #else
45 # ifndef __CHAR_UNSIGNED__
46 typedef char schar;
47 # else
48 typedef short schar;
49 # endif
50 #endif
51
52 /*
53 * An unsigned 32-bit integral type, used for pixel values. We use int rather
54 * than long here to accommodate those systems where longs are 64 bits.
55 */
56
57 typedef unsigned int pixel;
58
59 /*
60 * The maximum number of pixels to transmit to the server in a single
61 * XPutImage call.
62 */
63
64 #define MAX_PIXELS 65536
65
66 /*
67 * The set of colors required to display a photo image in a window depends on:
68 * - the visual used by the window
69 * - the palette, which specifies how many levels of each primary color to
70 * use, and
71 * - the gamma value for the image.
72 *
73 * Pixel values allocated for specific colors are valid only for the colormap
74 * in which they were allocated. Sets of pixel values allocated for displaying
75 * photos are re-used in other windows if possible, that is, if the display,
76 * colormap, palette and gamma values match. A hash table is used to locate
77 * these sets of pixel values, using the following data structure as key:
78 */
79
80 typedef struct {
81 Display *display; /* Qualifies the colormap resource ID. */
82 Colormap colormap; /* Colormap that the windows are using. */
83 double gamma; /* Gamma exponent value for images. */
84 Tk_Uid palette; /* Specifies how many shades of each primary
85 * we want to allocate. */
86 } ColorTableId;
87
88 /*
89 * For a particular (display, colormap, palette, gamma) combination, a data
90 * structure of the following type is used to store the allocated pixel values
91 * and other information:
92 */
93
94 typedef struct ColorTable {
95 ColorTableId id; /* Information used in selecting this color
96 * table. */
97 int flags; /* See below. */
98 int refCount; /* Number of instances using this map. */
99 int liveRefCount; /* Number of instances which are actually in
100 * use, using this map. */
101 int numColors; /* Number of colors allocated for this map. */
102
103 XVisualInfo visualInfo; /* Information about the visual for windows
104 * using this color table. */
105
106 pixel redValues[256]; /* Maps 8-bit values of red intensity to a
107 * pixel value or index in pixelMap. */
108 pixel greenValues[256]; /* Ditto for green intensity. */
109 pixel blueValues[256]; /* Ditto for blue intensity. */
110 unsigned long *pixelMap; /* Actual pixel values allocated. */
111
112 unsigned char colorQuant[3][256];
113 /* Maps 8-bit intensities to quantized
114 * intensities. The first index is 0 for red,
115 * 1 for green, 2 for blue. */
116 } ColorTable;
117
118 /*
119 * Bit definitions for the flags field of a ColorTable.
120 * BLACK_AND_WHITE: 1 means only black and white colors are
121 * available.
122 * COLOR_WINDOW: 1 means a full 3-D color cube has been
123 * allocated.
124 * DISPOSE_PENDING: 1 means a call to DisposeColorTable has been
125 * scheduled as an idle handler, but it hasn't
126 * been invoked yet.
127 * MAP_COLORS: 1 means pixel values should be mapped through
128 * pixelMap.
129 */
130
131 #ifdef COLOR_WINDOW
132 #undef COLOR_WINDOW
133 #endif
134
135 #define BLACK_AND_WHITE 1
136 #define COLOR_WINDOW 2
137 #define DISPOSE_PENDING 4
138 #define MAP_COLORS 8
139
140 /*
141 * Definition of the data associated with each photo image master.
142 */
143
144 typedef struct PhotoMaster {
145 Tk_ImageMaster tkMaster; /* Tk's token for image master. NULL means the
146 * image is being deleted. */
147 Tcl_Interp *interp; /* Interpreter associated with the application
148 * using this image. */
149 Tcl_Command imageCmd; /* Token for image command (used to delete it
150 * when the image goes away). NULL means the
151 * image command has already been deleted. */
152 int flags; /* Sundry flags, defined below. */
153 int width, height; /* Dimensions of image. */
154 int userWidth, userHeight; /* User-declared image dimensions. */
155 Tk_Uid palette; /* User-specified default palette for
156 * instances of this image. */
157 double gamma; /* Display gamma value to correct for. */
158 char *fileString; /* Name of file to read into image. */
159 Tcl_Obj *dataString; /* Object to use as contents of image. */
160 Tcl_Obj *format; /* User-specified format of data in image file
161 * or string value. */
162 unsigned char *pix32; /* Local storage for 32-bit image. */
163 int ditherX, ditherY; /* Location of first incorrectly dithered
164 * pixel in image. */
165 TkRegion validRegion; /* Tk region indicating which parts of the
166 * image have valid image data. */
167 struct PhotoInstance *instancePtr;
168 /* First in the list of instances associated
169 * with this master. */
170 } PhotoMaster;
171
172 /*
173 * Bit definitions for the flags field of a PhotoMaster.
174 * COLOR_IMAGE: 1 means that the image has different color
175 * components.
176 * IMAGE_CHANGED: 1 means that the instances of this image need
177 * to be redithered.
178 * COMPLEX_ALPHA: 1 means that the instances of this image have
179 * alpha values that aren't 0 or 255, and so need
180 * the copy-merge-replace renderer .
181 */
182
183 #define COLOR_IMAGE 1
184 #define IMAGE_CHANGED 2
185 #define COMPLEX_ALPHA 4
186
187 /*
188 * Flag to OR with the compositing rule to indicate that the source, despite
189 * having an alpha channel, has simple alpha.
190 */
191
192 #define SOURCE_IS_SIMPLE_ALPHA_PHOTO 0x10000000
193
194 /*
195 * The following data structure represents all of the instances of a photo
196 * image in windows on a given screen that are using the same colormap.
197 */
198
199 typedef struct PhotoInstance {
200 PhotoMaster *masterPtr; /* Pointer to master for image. */
201 Display *display; /* Display for windows using this instance. */
202 Colormap colormap; /* The image may only be used in windows with
203 * this particular colormap. */
204 struct PhotoInstance *nextPtr;
205 /* Pointer to the next instance in the list of
206 * instances associated with this master. */
207 int refCount; /* Number of instances using this structure. */
208 Tk_Uid palette; /* Palette for these particular instances. */
209 double gamma; /* Gamma value for these instances. */
210 Tk_Uid defaultPalette; /* Default palette to use if a palette is not
211 * specified for the master. */
212 ColorTable *colorTablePtr; /* Pointer to information about colors
213 * allocated for image display in windows like
214 * this one. */
215 Pixmap pixels; /* X pixmap containing dithered image. */
216 int width, height; /* Dimensions of the pixmap. */
217 schar *error; /* Error image, used in dithering. */
218 XImage *imagePtr; /* Image structure for converted pixels. */
219 XVisualInfo visualInfo; /* Information about the visual that these
220 * windows are using. */
221 GC gc; /* Graphics context for writing images to the
222 * pixmap. */
223 } PhotoInstance;
224
225 /*
226 * The following data structure is used to return information from
227 * ParseSubcommandOptions:
228 */
229
230 struct SubcommandOptions {
231 int options; /* Individual bits indicate which options were
232 * specified - see below. */
233 Tcl_Obj *name; /* Name specified without an option. */
234 int fromX, fromY; /* Values specified for -from option. */
235 int fromX2, fromY2; /* Second coordinate pair for -from option. */
236 int toX, toY; /* Values specified for -to option. */
237 int toX2, toY2; /* Second coordinate pair for -to option. */
238 int zoomX, zoomY; /* Values specified for -zoom option. */
239 int subsampleX, subsampleY; /* Values specified for -subsample option. */
240 Tcl_Obj *format; /* Value specified for -format option. */
241 XColor *background; /* Value specified for -background option. */
242 int compositingRule; /* Value specified for -compositingrule
243 * option. */
244 };
245
246 /*
247 * Bit definitions for use with ParseSubcommandOptions: each bit is set in the
248 * allowedOptions parameter on a call to ParseSubcommandOptions if that option
249 * is allowed for the current photo image subcommand. On return, the bit is
250 * set in the options field of the SubcommandOptions structure if that option
251 * was specified.
252 *
253 * OPT_BACKGROUND: Set if -format option allowed/specified.
254 * OPT_COMPOSITE: Set if -compositingrule option allowed/spec'd.
255 * OPT_FORMAT: Set if -format option allowed/specified.
256 * OPT_FROM: Set if -from option allowed/specified.
257 * OPT_GRAYSCALE: Set if -grayscale option allowed/specified.
258 * OPT_SHRINK: Set if -shrink option allowed/specified.
259 * OPT_SUBSAMPLE: Set if -subsample option allowed/spec'd.
260 * OPT_TO: Set if -to option allowed/specified.
261 * OPT_ZOOM: Set if -zoom option allowed/specified.
262 */
263
264 #define OPT_BACKGROUND 1
265 #define OPT_COMPOSITE 2
266 #define OPT_FORMAT 4
267 #define OPT_FROM 8
268 #define OPT_GRAYSCALE 0x10
269 #define OPT_SHRINK 0x20
270 #define OPT_SUBSAMPLE 0x40
271 #define OPT_TO 0x80
272 #define OPT_ZOOM 0x100
273
274 /*
275 * List of option names. The order here must match the order of declarations
276 * of the OPT_* constants above.
277 */
278
279 static const char *const optionNames[] = {
280 "-background",
281 "-compositingrule",
282 "-format",
283 "-from",
284 "-grayscale",
285 "-shrink",
286 "-subsample",
287 "-to",
288 "-zoom",
289 NULL
290 };
291
292 /*
293 * Message to generate when an attempt to resize an image fails due to memory
294 * problems.
295 */
296
297 #define TK_PHOTO_ALLOC_FAILURE_MESSAGE \
298 "not enough free memory for image buffer"
299
300 /*
301 * Functions used in the type record for photo images.
302 */
303
304 static int ImgPhotoCreate(Tcl_Interp *interp, char *name,
305 int objc, Tcl_Obj *CONST objv[],
306 Tk_ImageType *typePtr, Tk_ImageMaster master,
307 ClientData *clientDataPtr);
308 static ClientData ImgPhotoGet(Tk_Window tkwin, ClientData clientData);
309 static void ImgPhotoDisplay(ClientData clientData,
310 Display *display, Drawable drawable,
311 int imageX, int imageY, int width, int height,
312 int drawableX, int drawableY);
313 static void ImgPhotoFree(ClientData clientData, Display *display);
314 static void ImgPhotoDelete(ClientData clientData);
315 static int ImgPhotoPostscript(ClientData clientData,
316 Tcl_Interp *interp, Tk_Window tkwin,
317 Tk_PostscriptInfo psInfo, int x, int y, int width,
318 int height, int prepass);
319
320 /*
321 * The type record itself for photo images:
322 */
323
324 Tk_ImageType tkPhotoImageType = {
325 "photo", /* name */
326 ImgPhotoCreate, /* createProc */
327 ImgPhotoGet, /* getProc */
328 ImgPhotoDisplay, /* displayProc */
329 ImgPhotoFree, /* freeProc */
330 ImgPhotoDelete, /* deleteProc */
331 ImgPhotoPostscript, /* postscriptProc */
332 NULL /* nextPtr */
333 };
334
335 typedef struct ThreadSpecificData {
336 Tk_PhotoImageFormat *formatList;
337 /* Pointer to the first in the list of known
338 * photo image formats.*/
339 Tk_PhotoImageFormat *oldFormatList;
340 /* Pointer to the first in the list of known
341 * photo image formats.*/
342 int initialized; /* Set to 1 if we've initialized the
343 * strucuture. */
344 } ThreadSpecificData;
345 static Tcl_ThreadDataKey dataKey;
346
347 /*
348 * Default configuration
349 */
350
351 #define DEF_PHOTO_GAMMA "1"
352 #define DEF_PHOTO_HEIGHT "0"
353 #define DEF_PHOTO_PALETTE ""
354 #define DEF_PHOTO_WIDTH "0"
355
356 /*
357 * Information used for parsing configuration specifications:
358 */
359
360 static Tk_ConfigSpec configSpecs[] = {
361 {TK_CONFIG_STRING, "-file", NULL, NULL,
362 NULL, Tk_Offset(PhotoMaster, fileString), TK_CONFIG_NULL_OK},
363 {TK_CONFIG_DOUBLE, "-gamma", NULL, NULL,
364 DEF_PHOTO_GAMMA, Tk_Offset(PhotoMaster, gamma), 0},
365 {TK_CONFIG_INT, "-height", NULL, NULL,
366 DEF_PHOTO_HEIGHT, Tk_Offset(PhotoMaster, userHeight), 0},
367 {TK_CONFIG_UID, "-palette", NULL, NULL,
368 DEF_PHOTO_PALETTE, Tk_Offset(PhotoMaster, palette), 0},
369 {TK_CONFIG_INT, "-width", NULL, NULL,
370 DEF_PHOTO_WIDTH, Tk_Offset(PhotoMaster, userWidth), 0},
371 {TK_CONFIG_END, NULL, NULL, NULL, NULL, 0, 0}
372 };
373
374 /*
375 * Hash table used to hash from (display, colormap, palette, gamma) to
376 * ColorTable address.
377 */
378
379 static Tcl_HashTable imgPhotoColorHash;
380 static int imgPhotoColorHashInitialized;
381 #define N_COLOR_HASH (sizeof(ColorTableId) / sizeof(int))
382
383 /*
384 * Implementation of the Porter-Duff Source-Over compositing rule.
385 */
386
387 #define PD_SRC_OVER(srcColor,srcAlpha,dstColor,dstAlpha) \
388 (srcColor*srcAlpha/255) + dstAlpha*(255-srcAlpha)/255*dstColor/255
389 #define PD_SRC_OVER_ALPHA(srcAlpha,dstAlpha) \
390 (srcAlpha + (255-srcAlpha)*dstAlpha/255)
391
392 /*
393 * Forward declarations
394 */
395
396 static void PhotoFormatThreadExitProc(ClientData clientData);
397 static int ImgPhotoCmd(ClientData clientData, Tcl_Interp *interp,
398 int objc, Tcl_Obj *CONST objv[]);
399 static int ParseSubcommandOptions(
400 struct SubcommandOptions *optPtr,
401 Tcl_Interp *interp, int allowedOptions,
402 int *indexPtr, int objc, Tcl_Obj *const objv[]);
403 static void ImgPhotoCmdDeletedProc(ClientData clientData);
404 static int ImgPhotoConfigureMaster(Tcl_Interp *interp,
405 PhotoMaster *masterPtr, int objc,
406 Tcl_Obj *const objv[], int flags);
407 static void ImgPhotoConfigureInstance(PhotoInstance *instancePtr);
408 static int ToggleComplexAlphaIfNeeded(PhotoMaster *mPtr);
409 static void ImgPhotoBlendComplexAlpha(XImage *bgImg,
410 PhotoInstance *iPtr, int xOffset, int yOffset,
411 int width, int height);
412 static int ImgPhotoSetSize(PhotoMaster *masterPtr, int width,
413 int height);
414 static void ImgPhotoInstanceSetSize(PhotoInstance *instancePtr);
415 static int ImgStringWrite(Tcl_Interp *interp,
416 Tcl_Obj *formatString,
417 Tk_PhotoImageBlock *blockPtr);
418 static char * ImgGetPhoto(PhotoMaster *masterPtr,
419 Tk_PhotoImageBlock *blockPtr,
420 struct SubcommandOptions *optPtr);
421 static int IsValidPalette(PhotoInstance *instancePtr,
422 const char *palette);
423 static int CountBits(pixel mask);
424 static void GetColorTable(PhotoInstance *instancePtr);
425 static void FreeColorTable(ColorTable *colorPtr, int force);
426 static void AllocateColors(ColorTable *colorPtr);
427 static void DisposeColorTable(ClientData clientData);
428 static void DisposeInstance(ClientData clientData);
429 static int ReclaimColors(ColorTableId *id, int numColors);
430 static int MatchFileFormat(Tcl_Interp *interp, Tcl_Channel chan,
431 char *fileName, Tcl_Obj *formatString,
432 Tk_PhotoImageFormat **imageFormatPtr,
433 int *widthPtr, int *heightPtr, int *oldformat);
434 static int MatchStringFormat(Tcl_Interp *interp, Tcl_Obj *data,
435 Tcl_Obj *formatString,
436 Tk_PhotoImageFormat **imageFormatPtr,
437 int *widthPtr, int *heightPtr, int *oldformat);
438 static Tcl_ObjCmdProc * PhotoOptionFind(Tcl_Interp *interp, Tcl_Obj *obj);
439 static void DitherInstance(PhotoInstance *instancePtr, int x,
440 int y, int width, int height);
441 static void PhotoOptionCleanupProc(ClientData clientData,
442 Tcl_Interp *interp);
443
444 #undef MIN
445 #define MIN(a, b) ((a) < (b)? (a): (b))
446 #undef MAX
447 #define MAX(a, b) ((a) > (b)? (a): (b))
448
449 /*
450 *----------------------------------------------------------------------
451 *
452 * PhotoFormatThreadExitProc --
453 *
454 * Clean up the registered list of photo formats.
455 *
456 * Results:
457 * None.
458 *
459 * Side effects:
460 * The thread's linked lists of photo image formats is deleted.
461 *
462 *----------------------------------------------------------------------
463 */
464
465 static void
PhotoFormatThreadExitProc(ClientData clientData)466 PhotoFormatThreadExitProc(
467 ClientData clientData) /* not used */
468 {
469 Tk_PhotoImageFormat *freePtr;
470 ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
471 Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
472
473 while (tsdPtr->oldFormatList != NULL) {
474 freePtr = tsdPtr->oldFormatList;
475 tsdPtr->oldFormatList = tsdPtr->oldFormatList->nextPtr;
476 ckfree((char *) freePtr);
477 }
478 while (tsdPtr->formatList != NULL) {
479 freePtr = tsdPtr->formatList;
480 tsdPtr->formatList = tsdPtr->formatList->nextPtr;
481 ckfree((char *) freePtr->name);
482 ckfree((char *) freePtr);
483 }
484 }
485
486 /*
487 *----------------------------------------------------------------------
488 *
489 * Tk_CreateOldPhotoImageFormat, Tk_CreatePhotoImageFormat --
490 *
491 * This function is invoked by an image file handler to register a new
492 * photo image format and the functions that handle the new format. The
493 * function is typically invoked during Tcl_AppInit.
494 *
495 * Results:
496 * None.
497 *
498 * Side effects:
499 * The new image file format is entered into a table used in the photo
500 * image "read" and "write" subcommands.
501 *
502 *----------------------------------------------------------------------
503 */
504
505 void
Tk_CreateOldPhotoImageFormat(Tk_PhotoImageFormat * formatPtr)506 Tk_CreateOldPhotoImageFormat(
507 Tk_PhotoImageFormat *formatPtr)
508 /* Structure describing the format. All of the
509 * fields except "nextPtr" must be filled in
510 * by caller. */
511 {
512 Tk_PhotoImageFormat *copyPtr;
513 ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
514 Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
515
516 if (!tsdPtr->initialized) {
517 tsdPtr->initialized = 1;
518 Tcl_CreateThreadExitHandler(PhotoFormatThreadExitProc, NULL);
519 }
520 copyPtr = (Tk_PhotoImageFormat *) ckalloc(sizeof(Tk_PhotoImageFormat));
521 *copyPtr = *formatPtr;
522 copyPtr->nextPtr = tsdPtr->oldFormatList;
523 tsdPtr->oldFormatList = copyPtr;
524 }
525
526 void
Tk_CreatePhotoImageFormat(Tk_PhotoImageFormat * formatPtr)527 Tk_CreatePhotoImageFormat(
528 Tk_PhotoImageFormat *formatPtr)
529 /* Structure describing the format. All of the
530 * fields except "nextPtr" must be filled in
531 * by caller. */
532 {
533 Tk_PhotoImageFormat *copyPtr;
534 ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
535 Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
536
537 if (!tsdPtr->initialized) {
538 tsdPtr->initialized = 1;
539 Tcl_CreateThreadExitHandler(PhotoFormatThreadExitProc, NULL);
540 }
541 copyPtr = (Tk_PhotoImageFormat *) ckalloc(sizeof(Tk_PhotoImageFormat));
542 *copyPtr = *formatPtr;
543 if (isupper((unsigned char) *formatPtr->name)) {
544 copyPtr->nextPtr = tsdPtr->oldFormatList;
545 tsdPtr->oldFormatList = copyPtr;
546 } else {
547 /* for compatibility with aMSN: make a copy of formatPtr->name */
548 char *name = ckalloc(strlen(formatPtr->name) + 1);
549 strcpy(name, formatPtr->name);
550 copyPtr->name = name;
551 copyPtr->nextPtr = tsdPtr->formatList;
552 tsdPtr->formatList = copyPtr;
553 }
554 }
555
556 /*
557 *----------------------------------------------------------------------
558 *
559 * ImgPhotoCreate --
560 *
561 * This function is called by the Tk image code to create a new photo
562 * image.
563 *
564 * Results:
565 * A standard Tcl result.
566 *
567 * Side effects:
568 * The data structure for a new photo image is allocated and initialized.
569 *
570 *----------------------------------------------------------------------
571 */
572
573 static int
ImgPhotoCreate(Tcl_Interp * interp,char * name,int objc,Tcl_Obj * CONST objv[],Tk_ImageType * typePtr,Tk_ImageMaster master,ClientData * clientDataPtr)574 ImgPhotoCreate(
575 Tcl_Interp *interp, /* Interpreter for application containing
576 * image. */
577 char *name, /* Name to use for image. */
578 int objc, /* Number of arguments. */
579 Tcl_Obj *CONST objv[], /* Argument objects for options (doesn't
580 * include image name or type). */
581 Tk_ImageType *typePtr, /* Pointer to our type record (not used). */
582 Tk_ImageMaster master, /* Token for image, to be used by us in later
583 * callbacks. */
584 ClientData *clientDataPtr) /* Store manager's token for image here; it
585 * will be returned in later callbacks. */
586 {
587 PhotoMaster *masterPtr;
588
589 /*
590 * Allocate and initialize the photo image master record.
591 */
592
593 masterPtr = (PhotoMaster *) ckalloc(sizeof(PhotoMaster));
594 memset(masterPtr, 0, sizeof(PhotoMaster));
595 masterPtr->tkMaster = master;
596 masterPtr->interp = interp;
597 masterPtr->imageCmd = Tcl_CreateObjCommand(interp, name, ImgPhotoCmd,
598 (ClientData) masterPtr, ImgPhotoCmdDeletedProc);
599 masterPtr->palette = NULL;
600 masterPtr->pix32 = NULL;
601 masterPtr->instancePtr = NULL;
602 masterPtr->validRegion = TkCreateRegion();
603
604 /*
605 * Process configuration options given in the image create command.
606 */
607
608 if (ImgPhotoConfigureMaster(interp, masterPtr, objc, objv, 0) != TCL_OK) {
609 ImgPhotoDelete((ClientData) masterPtr);
610 return TCL_ERROR;
611 }
612
613 *clientDataPtr = (ClientData) masterPtr;
614 return TCL_OK;
615 }
616
617 /*
618 *----------------------------------------------------------------------
619 *
620 * ImgPhotoCmd --
621 *
622 * This function is invoked to process the Tcl command that corresponds
623 * to a photo image. See the user documentation for details on what it
624 * does.
625 *
626 * Results:
627 * A standard Tcl result.
628 *
629 * Side effects:
630 * See the user documentation.
631 *
632 *----------------------------------------------------------------------
633 */
634
635 static int
ImgPhotoCmd(ClientData clientData,Tcl_Interp * interp,int objc,Tcl_Obj * CONST objv[])636 ImgPhotoCmd(
637 ClientData clientData, /* Information about photo master. */
638 Tcl_Interp *interp, /* Current interpreter. */
639 int objc, /* Number of arguments. */
640 Tcl_Obj *CONST objv[]) /* Argument objects. */
641 {
642 static const char *photoOptions[] = {
643 "blank", "cget", "configure", "copy", "data", "get", "put",
644 "read", "redither", "transparency", "write", NULL
645 };
646 enum PhotoOptions {
647 PHOTO_BLANK, PHOTO_CGET, PHOTO_CONFIGURE, PHOTO_COPY, PHOTO_DATA,
648 PHOTO_GET, PHOTO_PUT, PHOTO_READ, PHOTO_REDITHER, PHOTO_TRANS,
649 PHOTO_WRITE
650 };
651
652 PhotoMaster *masterPtr = (PhotoMaster *) clientData;
653 int result, index, x, y, width, height, dataWidth, dataHeight, listObjc;
654 struct SubcommandOptions options;
655 Tcl_Obj **listObjv, **srcObjv;
656 unsigned char *pixelPtr;
657 Tk_PhotoImageBlock block;
658 Tk_Window tkwin;
659 Tk_PhotoImageFormat *imageFormat;
660 int imageWidth, imageHeight, matched, length, oldformat = 0;
661 Tcl_Channel chan;
662 Tk_PhotoHandle srcHandle;
663 ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
664 Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
665
666 if (objc < 2) {
667 Tcl_WrongNumArgs(interp, 1, objv, "option ?arg arg ...?");
668 return TCL_ERROR;
669 }
670
671 if (Tcl_GetIndexFromObj(interp, objv[1], photoOptions, "option", 0,
672 &index) != TCL_OK) {
673 Tcl_ObjCmdProc *proc;
674 proc = PhotoOptionFind(interp, objv[1]);
675 if (proc == NULL) {
676 return TCL_ERROR;
677 }
678 return proc(clientData, interp, objc, objv);
679 }
680
681 switch ((enum PhotoOptions) index) {
682 case PHOTO_BLANK:
683 /*
684 * photo blank command - just call Tk_PhotoBlank.
685 */
686
687 if (objc == 2) {
688 Tk_PhotoBlank(masterPtr);
689 return TCL_OK;
690 } else {
691 Tcl_WrongNumArgs(interp, 2, objv, NULL);
692 return TCL_ERROR;
693 }
694
695 case PHOTO_CGET: {
696 char *arg;
697
698 if (objc != 3) {
699 Tcl_WrongNumArgs(interp, 2, objv, "option");
700 return TCL_ERROR;
701 }
702 arg = Tcl_GetStringFromObj(objv[2], &length);
703 if (strncmp(arg,"-data", (unsigned) length) == 0) {
704 if (masterPtr->dataString) {
705 Tcl_SetObjResult(interp, masterPtr->dataString);
706 }
707 } else if (strncmp(arg,"-format", (unsigned) length) == 0) {
708 if (masterPtr->format) {
709 Tcl_SetObjResult(interp, masterPtr->format);
710 }
711 } else {
712 Tk_ConfigureValue(interp, Tk_MainWindow(interp), configSpecs,
713 (char *) masterPtr, Tcl_GetString(objv[2]), 0);
714 }
715 return TCL_OK;
716 }
717
718 case PHOTO_CONFIGURE:
719 /*
720 * photo configure command - handle this in the standard way.
721 */
722
723 if (objc == 2) {
724 Tcl_Obj *obj, *subobj;
725
726 result = Tk_ConfigureInfo(interp, Tk_MainWindow(interp),
727 configSpecs, (char *) masterPtr, NULL, 0);
728 if (result != TCL_OK) {
729 return result;
730 }
731 obj = Tcl_NewObj();
732 subobj = Tcl_NewStringObj("-data {} {} {}", 14);
733 if (masterPtr->dataString) {
734 Tcl_ListObjAppendElement(NULL, subobj, masterPtr->dataString);
735 } else {
736 Tcl_AppendStringsToObj(subobj, " {}", NULL);
737 }
738 Tcl_ListObjAppendElement(interp, obj, subobj);
739 subobj = Tcl_NewStringObj("-format {} {} {}", 16);
740 if (masterPtr->format) {
741 Tcl_ListObjAppendElement(NULL, subobj, masterPtr->format);
742 } else {
743 Tcl_AppendStringsToObj(subobj, " {}", NULL);
744 }
745 Tcl_ListObjAppendElement(interp, obj, subobj);
746 Tcl_ListObjAppendList(interp, obj, Tcl_GetObjResult(interp));
747 Tcl_SetObjResult(interp, obj);
748 return TCL_OK;
749
750 } else if (objc == 3) {
751 char *arg = Tcl_GetStringFromObj(objv[2], &length);
752
753 if (length > 1 && !strncmp(arg, "-data", (unsigned) length)) {
754 Tcl_AppendResult(interp, "-data {} {} {}", NULL);
755 if (masterPtr->dataString) {
756 Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp),
757 masterPtr->dataString);
758 } else {
759 Tcl_AppendResult(interp, " {}", NULL);
760 }
761 return TCL_OK;
762 } else if (length > 1 &&
763 !strncmp(arg, "-format", (unsigned) length)) {
764 Tcl_AppendResult(interp, "-format {} {} {}", NULL);
765 if (masterPtr->format) {
766 Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp),
767 masterPtr->format);
768 } else {
769 Tcl_AppendResult(interp, " {}", NULL);
770 }
771 return TCL_OK;
772 } else {
773 return Tk_ConfigureInfo(interp, Tk_MainWindow(interp),
774 configSpecs, (char *) masterPtr, arg, 0);
775 }
776 }
777 return ImgPhotoConfigureMaster(interp, masterPtr, objc-2, objv+2,
778 TK_CONFIG_ARGV_ONLY);
779
780 case PHOTO_COPY:
781 /*
782 * photo copy command - first parse options.
783 */
784
785 index = 2;
786 memset(&options, 0, sizeof(options));
787 options.zoomX = options.zoomY = 1;
788 options.subsampleX = options.subsampleY = 1;
789 options.name = NULL;
790 options.compositingRule = TK_PHOTO_COMPOSITE_OVERLAY;
791 if (ParseSubcommandOptions(&options, interp,
792 OPT_FROM | OPT_TO | OPT_ZOOM | OPT_SUBSAMPLE | OPT_SHRINK |
793 OPT_COMPOSITE, &index, objc, objv) != TCL_OK) {
794 return TCL_ERROR;
795 }
796 if (options.name == NULL || index < objc) {
797 Tcl_WrongNumArgs(interp, 2, objv,
798 "source-image ?-compositingrule rule? ?-from x1 y1 x2 y2? ?-to x1 y1 x2 y2? ?-zoom x y? ?-subsample x y?");
799 return TCL_ERROR;
800 }
801
802 /*
803 * Look for the source image and get a pointer to its image data.
804 * Check the values given for the -from option.
805 */
806
807 srcHandle = Tk_FindPhoto(interp, Tcl_GetString(options.name));
808 if (srcHandle == NULL) {
809 Tcl_AppendResult(interp, "image \"",
810 Tcl_GetString(options.name), "\" doesn't",
811 " exist or is not a photo image", NULL);
812 return TCL_ERROR;
813 }
814 Tk_PhotoGetImage(srcHandle, &block);
815 if ((options.fromX2 > block.width) || (options.fromY2 > block.height)
816 || (options.fromX2 > block.width)
817 || (options.fromY2 > block.height)) {
818 Tcl_AppendResult(interp, "coordinates for -from option extend ",
819 "outside source image", NULL);
820 return TCL_ERROR;
821 }
822
823 /*
824 * Hack to pass through the message that the place we're coming from
825 * has a simple alpha channel.
826 */
827
828 if (!(((PhotoMaster *) srcHandle)->flags & COMPLEX_ALPHA)) {
829 options.compositingRule |= SOURCE_IS_SIMPLE_ALPHA_PHOTO;
830 }
831
832 /*
833 * Fill in default values for unspecified parameters.
834 */
835
836 if (!(options.options & OPT_FROM) || (options.fromX2 < 0)) {
837 options.fromX2 = block.width;
838 options.fromY2 = block.height;
839 }
840 if (!(options.options & OPT_TO) || (options.toX2 < 0)) {
841 width = options.fromX2 - options.fromX;
842 if (options.subsampleX > 0) {
843 width = (width + options.subsampleX - 1) / options.subsampleX;
844 } else if (options.subsampleX == 0) {
845 width = 0;
846 } else {
847 width = (width - options.subsampleX - 1) / -options.subsampleX;
848 }
849 options.toX2 = options.toX + width * options.zoomX;
850
851 height = options.fromY2 - options.fromY;
852 if (options.subsampleY > 0) {
853 height = (height + options.subsampleY - 1)
854 / options.subsampleY;
855 } else if (options.subsampleY == 0) {
856 height = 0;
857 } else {
858 height = (height - options.subsampleY - 1)
859 / -options.subsampleY;
860 }
861 options.toY2 = options.toY + height * options.zoomY;
862 }
863
864 /*
865 * Set the destination image size if the -shrink option was specified.
866 */
867
868 if (options.options & OPT_SHRINK) {
869 if (ImgPhotoSetSize(masterPtr, options.toX2,
870 options.toY2) != TCL_OK) {
871 Tcl_ResetResult(interp);
872 Tcl_AppendResult(interp, TK_PHOTO_ALLOC_FAILURE_MESSAGE, NULL);
873 return TCL_ERROR;
874 }
875 }
876
877 /*
878 * Copy the image data over using Tk_PhotoPutZoomedBlock.
879 */
880
881 block.pixelPtr += options.fromX * block.pixelSize
882 + options.fromY * block.pitch;
883 block.width = options.fromX2 - options.fromX;
884 block.height = options.fromY2 - options.fromY;
885 return Tk_PhotoPutZoomedBlock(interp, (Tk_PhotoHandle) masterPtr,
886 &block, options.toX, options.toY, options.toX2 - options.toX,
887 options.toY2 - options.toY, options.zoomX, options.zoomY,
888 options.subsampleX, options.subsampleY,
889 options.compositingRule);
890
891 case PHOTO_DATA: {
892 char *data;
893
894 /*
895 * photo data command - first parse and check any options given.
896 */
897
898 Tk_ImageStringWriteProc *stringWriteProc = NULL;
899
900 index = 2;
901 memset(&options, 0, sizeof(options));
902 options.name = NULL;
903 options.format = NULL;
904 options.fromX = 0;
905 options.fromY = 0;
906 if (ParseSubcommandOptions(&options, interp,
907 OPT_FORMAT | OPT_FROM | OPT_GRAYSCALE | OPT_BACKGROUND,
908 &index, objc, objv) != TCL_OK) {
909 return TCL_ERROR;
910 }
911 if ((options.name != NULL) || (index < objc)) {
912 Tcl_WrongNumArgs(interp, 2, objv, "?options?");
913 return TCL_ERROR;
914 }
915 if ((options.fromX > masterPtr->width)
916 || (options.fromY > masterPtr->height)
917 || (options.fromX2 > masterPtr->width)
918 || (options.fromY2 > masterPtr->height)) {
919 Tcl_AppendResult(interp, "coordinates for -from option extend ",
920 "outside image", NULL);
921 return TCL_ERROR;
922 }
923
924 /*
925 * Fill in default values for unspecified parameters.
926 */
927
928 if (((options.options & OPT_FROM) == 0) || (options.fromX2 < 0)) {
929 options.fromX2 = masterPtr->width;
930 options.fromY2 = masterPtr->height;
931 }
932
933 /*
934 * Search for an appropriate image string format handler.
935 */
936
937 if (options.options & OPT_FORMAT) {
938 matched = 0;
939 for (imageFormat = tsdPtr->formatList; imageFormat != NULL;
940 imageFormat = imageFormat->nextPtr) {
941 if ((strncasecmp(Tcl_GetString(options.format),
942 imageFormat->name, strlen(imageFormat->name)) == 0)) {
943 matched = 1;
944 if (imageFormat->stringWriteProc != NULL) {
945 stringWriteProc = imageFormat->stringWriteProc;
946 break;
947 }
948 }
949 }
950 if (stringWriteProc == NULL) {
951 oldformat = 1;
952 for (imageFormat = tsdPtr->oldFormatList; imageFormat != NULL;
953 imageFormat = imageFormat->nextPtr) {
954 if ((strncasecmp(Tcl_GetString(options.format),
955 imageFormat->name,
956 strlen(imageFormat->name)) == 0)) {
957 matched = 1;
958 if (imageFormat->stringWriteProc != NULL) {
959 stringWriteProc = imageFormat->stringWriteProc;
960 break;
961 }
962 }
963 }
964 }
965 if (stringWriteProc == NULL) {
966 Tcl_AppendResult(interp, "image string format \"",
967 Tcl_GetString(options.format), "\" is ",
968 (matched ? "not supported" : "unknown"), NULL);
969 return TCL_ERROR;
970 }
971 } else {
972 stringWriteProc = ImgStringWrite;
973 }
974
975 /*
976 * Call the handler's string write function to write out the image.
977 */
978
979 data = ImgGetPhoto(masterPtr, &block, &options);
980
981 if (oldformat) {
982 Tcl_DString buffer;
983
984 Tcl_DStringInit(&buffer);
985 result = ((int (*) (Tcl_Interp *interp,
986 Tcl_DString *dataPtr, char *formatString,
987 Tk_PhotoImageBlock *blockPtr)) stringWriteProc)
988 (interp, &buffer, Tcl_GetString(options.format), &block);
989 if (result == TCL_OK) {
990 Tcl_DStringResult(interp, &buffer);
991 } else {
992 Tcl_DStringFree(&buffer);
993 }
994 } else {
995
996 result = ((int (*) (Tcl_Interp *interp,
997 Tcl_Obj *formatString, Tk_PhotoImageBlock *blockPtr,
998 void *dummy)) stringWriteProc)
999 (interp, options.format, &block, NULL);
1000 }
1001 if (options.background) {
1002 Tk_FreeColor(options.background);
1003 }
1004 if (data) {
1005 ckfree(data);
1006 }
1007 return result;
1008 }
1009
1010 case PHOTO_GET: {
1011 /*
1012 * photo get command - first parse and check parameters.
1013 */
1014
1015 char string[TCL_INTEGER_SPACE * 3];
1016
1017 if (objc != 4) {
1018 Tcl_WrongNumArgs(interp, 2, objv, "x y");
1019 return TCL_ERROR;
1020 }
1021 if ((Tcl_GetIntFromObj(interp, objv[2], &x) != TCL_OK)
1022 || (Tcl_GetIntFromObj(interp, objv[3], &y) != TCL_OK)) {
1023 return TCL_ERROR;
1024 }
1025 if ((x < 0) || (x >= masterPtr->width)
1026 || (y < 0) || (y >= masterPtr->height)) {
1027 Tcl_AppendResult(interp, Tcl_GetString(objv[0]), " get: ",
1028 "coordinates out of range", NULL);
1029 return TCL_ERROR;
1030 }
1031
1032 /*
1033 * Extract the value of the desired pixel and format it as a string.
1034 */
1035
1036 pixelPtr = masterPtr->pix32 + (y * masterPtr->width + x) * 4;
1037 sprintf(string, "%d %d %d", pixelPtr[0], pixelPtr[1],
1038 pixelPtr[2]);
1039 Tcl_AppendResult(interp, string, NULL);
1040 return TCL_OK;
1041 }
1042
1043 case PHOTO_PUT:
1044 /*
1045 * photo put command - first parse the options and colors specified.
1046 */
1047
1048 index = 2;
1049 memset(&options, 0, sizeof(options));
1050 options.name = NULL;
1051 if (ParseSubcommandOptions(&options, interp, OPT_TO|OPT_FORMAT,
1052 &index, objc, objv) != TCL_OK) {
1053 return TCL_ERROR;
1054 }
1055 if ((options.name == NULL) || (index < objc)) {
1056 Tcl_WrongNumArgs(interp, 2, objv, "data ?options?");
1057 return TCL_ERROR;
1058 }
1059
1060 if (MatchStringFormat(interp, options.name ? objv[2]:NULL,
1061 options.format, &imageFormat, &imageWidth,
1062 &imageHeight, &oldformat) == TCL_OK) {
1063 Tcl_Obj *format, *data;
1064
1065 if (((options.options & OPT_TO) == 0) || (options.toX2 < 0)) {
1066 options.toX2 = options.toX + imageWidth;
1067 options.toY2 = options.toY + imageHeight;
1068 }
1069 if (imageWidth > options.toX2 - options.toX) {
1070 imageWidth = options.toX2 - options.toX;
1071 }
1072 if (imageHeight > options.toY2 - options.toY) {
1073 imageHeight = options.toY2 - options.toY;
1074 }
1075 format = options.format;
1076 data = objv[2];
1077 if (oldformat) {
1078 if (format) {
1079 format = (Tcl_Obj *) Tcl_GetString(format);
1080 }
1081 data = (Tcl_Obj *) Tcl_GetString(data);
1082 }
1083 if ((*imageFormat->stringReadProc)(interp, data,
1084 format, (Tk_PhotoHandle) masterPtr,
1085 options.toX, options.toY, imageWidth, imageHeight,
1086 0, 0) != TCL_OK) {
1087 return TCL_ERROR;
1088 }
1089 masterPtr->flags |= IMAGE_CHANGED;
1090 return TCL_OK;
1091 }
1092 if (options.options & OPT_FORMAT) {
1093 return TCL_ERROR;
1094 }
1095 Tcl_ResetResult(interp);
1096 if (Tcl_ListObjGetElements(interp, options.name,
1097 &dataHeight, &srcObjv) != TCL_OK) {
1098 return TCL_ERROR;
1099 }
1100 tkwin = Tk_MainWindow(interp);
1101 block.pixelPtr = NULL;
1102 dataWidth = 0;
1103 pixelPtr = NULL;
1104 for (y = 0; y < dataHeight; ++y) {
1105 if (Tcl_ListObjGetElements(interp, srcObjv[y],
1106 &listObjc, &listObjv) != TCL_OK) {
1107 break;
1108 }
1109
1110 if (y == 0) {
1111 if (listObjc == 0) {
1112 /*
1113 * Lines must be non-empty...
1114 */
1115
1116 break;
1117 }
1118 dataWidth = listObjc;
1119 pixelPtr = (unsigned char *)
1120 ckalloc((unsigned) dataWidth * dataHeight * 3);
1121 block.pixelPtr = pixelPtr;
1122 } else if (listObjc != dataWidth) {
1123 Tcl_AppendResult(interp, "all elements of color list must",
1124 " have the same number of elements", NULL);
1125 break;
1126 }
1127
1128 for (x = 0; x < dataWidth; ++x) {
1129 char *colorString = Tcl_GetString(listObjv[x]);
1130 XColor color;
1131 int tmpr, tmpg, tmpb;
1132
1133 /*
1134 * We do not use Tk_GetColorFromObj() because we absolutely do
1135 * not want to invoke the fallback code.
1136 */
1137
1138 if (colorString[0] == '#') {
1139 if (isxdigit(UCHAR(colorString[1])) &&
1140 isxdigit(UCHAR(colorString[2])) &&
1141 isxdigit(UCHAR(colorString[3]))) {
1142 if (colorString[4] == '\0') {
1143 /* Got #rgb */
1144 sscanf(colorString+1, "%1x%1x%1x",
1145 &tmpr, &tmpg, &tmpb);
1146 *pixelPtr++ = tmpr * 0x11;
1147 *pixelPtr++ = tmpg * 0x11;
1148 *pixelPtr++ = tmpb * 0x11;
1149 continue;
1150 } else if (isxdigit(UCHAR(colorString[4])) &&
1151 isxdigit(UCHAR(colorString[5])) &&
1152 isxdigit(UCHAR(colorString[6])) &&
1153 colorString[7] == '\0') {
1154 /* Got #rrggbb */
1155 sscanf(colorString+1, "%2x%2x%2x",
1156 &tmpr, &tmpg, &tmpb);
1157 *pixelPtr++ = tmpr;
1158 *pixelPtr++ = tmpg;
1159 *pixelPtr++ = tmpb;
1160 continue;
1161 }
1162 }
1163 }
1164
1165 if (!TkParseColor(Tk_Display(tkwin), Tk_Colormap(tkwin),
1166 colorString, &color)) {
1167 Tcl_AppendResult(interp, "can't parse color \"",
1168 colorString, "\"", NULL);
1169 break;
1170 }
1171 *pixelPtr++ = color.red >> 8;
1172 *pixelPtr++ = color.green >> 8;
1173 *pixelPtr++ = color.blue >> 8;
1174 }
1175 if (x < dataWidth) {
1176 break;
1177 }
1178 }
1179 if (y < dataHeight || dataHeight == 0 || dataWidth == 0) {
1180 if (block.pixelPtr != NULL) {
1181 ckfree((char *) block.pixelPtr);
1182 }
1183 if (y < dataHeight) {
1184 return TCL_ERROR;
1185 }
1186 return TCL_OK;
1187 }
1188
1189 /*
1190 * Fill in default values for the -to option, then copy the block in
1191 * using Tk_PhotoPutBlock.
1192 */
1193
1194 if (!(options.options & OPT_TO) || (options.toX2 < 0)) {
1195 options.toX2 = options.toX + dataWidth;
1196 options.toY2 = options.toY + dataHeight;
1197 }
1198 block.width = dataWidth;
1199 block.height = dataHeight;
1200 block.pitch = dataWidth * 3;
1201 block.pixelSize = 3;
1202 block.offset[0] = 0;
1203 block.offset[1] = 1;
1204 block.offset[2] = 2;
1205 block.offset[3] = 0;
1206 result = Tk_PhotoPutBlock(interp, (ClientData)masterPtr, &block,
1207 options.toX, options.toY, options.toX2 - options.toX,
1208 options.toY2 - options.toY,
1209 TK_PHOTO_COMPOSITE_SET);
1210 ckfree((char *) block.pixelPtr);
1211 return result;
1212
1213 case PHOTO_READ: {
1214 Tcl_Obj *format;
1215
1216 /*
1217 * photo read command - first parse the options specified.
1218 */
1219
1220 index = 2;
1221 memset(&options, 0, sizeof(options));
1222 options.name = NULL;
1223 options.format = NULL;
1224 if (ParseSubcommandOptions(&options, interp,
1225 OPT_FORMAT | OPT_FROM | OPT_TO | OPT_SHRINK,
1226 &index, objc, objv) != TCL_OK) {
1227 return TCL_ERROR;
1228 }
1229 if ((options.name == NULL) || (index < objc)) {
1230 Tcl_WrongNumArgs(interp, 2, objv, "fileName ?options?");
1231 return TCL_ERROR;
1232 }
1233
1234 /*
1235 * Prevent file system access in safe interpreters.
1236 */
1237
1238 if (Tcl_IsSafe(interp)) {
1239 Tcl_AppendResult(interp, "can't get image from a file in a",
1240 " safe interpreter", NULL);
1241 return TCL_ERROR;
1242 }
1243
1244 /*
1245 * Open the image file and look for a handler for it.
1246 */
1247
1248 chan = Tcl_OpenFileChannel(interp,
1249 Tcl_GetString(options.name), "r", 0);
1250 if (chan == NULL) {
1251 return TCL_ERROR;
1252 }
1253 if (Tcl_SetChannelOption(interp, chan, "-translation", "binary")
1254 != TCL_OK) {
1255 Tcl_Close(NULL, chan);
1256 return TCL_ERROR;
1257 }
1258 if (Tcl_SetChannelOption(interp, chan, "-encoding", "binary")
1259 != TCL_OK) {
1260 Tcl_Close(NULL, chan);
1261 return TCL_ERROR;
1262 }
1263
1264 if (MatchFileFormat(interp, chan,
1265 Tcl_GetString(options.name), options.format, &imageFormat,
1266 &imageWidth, &imageHeight, &oldformat) != TCL_OK) {
1267 Tcl_Close(NULL, chan);
1268 return TCL_ERROR;
1269 }
1270
1271 /*
1272 * Check the values given for the -from option.
1273 */
1274
1275 if ((options.fromX > imageWidth) || (options.fromY > imageHeight)
1276 || (options.fromX2 > imageWidth)
1277 || (options.fromY2 > imageHeight)) {
1278 Tcl_AppendResult(interp, "coordinates for -from option extend ",
1279 "outside source image", NULL);
1280 Tcl_Close(NULL, chan);
1281 return TCL_ERROR;
1282 }
1283 if (((options.options & OPT_FROM) == 0) || (options.fromX2 < 0)) {
1284 width = imageWidth - options.fromX;
1285 height = imageHeight - options.fromY;
1286 } else {
1287 width = options.fromX2 - options.fromX;
1288 height = options.fromY2 - options.fromY;
1289 }
1290
1291 /*
1292 * If the -shrink option was specified, set the size of the image.
1293 */
1294
1295 if (options.options & OPT_SHRINK) {
1296 if (ImgPhotoSetSize(masterPtr, options.toX + width,
1297 options.toY + height) != TCL_OK) {
1298 Tcl_ResetResult(interp);
1299 Tcl_AppendResult(interp, TK_PHOTO_ALLOC_FAILURE_MESSAGE, NULL);
1300 return TCL_ERROR;
1301 }
1302 }
1303
1304 /*
1305 * Call the handler's file read function to read the data into the
1306 * image.
1307 */
1308
1309 format = options.format;
1310 if (oldformat && format) {
1311 format = (Tcl_Obj *) Tcl_GetString(format);
1312 }
1313 result = (*imageFormat->fileReadProc)(interp, chan,
1314 Tcl_GetString(options.name),
1315 format, (Tk_PhotoHandle) masterPtr, options.toX,
1316 options.toY, width, height, options.fromX, options.fromY);
1317 if (chan != NULL) {
1318 Tcl_Close(NULL, chan);
1319 }
1320 return result;
1321 }
1322
1323 case PHOTO_REDITHER:
1324 if (objc != 2) {
1325 Tcl_WrongNumArgs(interp, 2, objv, NULL);
1326 return TCL_ERROR;
1327 }
1328
1329 /*
1330 * Call Dither if any part of the image is not correctly dithered at
1331 * present.
1332 */
1333
1334 x = masterPtr->ditherX;
1335 y = masterPtr->ditherY;
1336 if (masterPtr->ditherX != 0) {
1337 Tk_DitherPhoto((Tk_PhotoHandle) masterPtr, x, y,
1338 masterPtr->width - x, 1);
1339 }
1340 if (masterPtr->ditherY < masterPtr->height) {
1341 x = 0;
1342 Tk_DitherPhoto((Tk_PhotoHandle)masterPtr, 0,
1343 masterPtr->ditherY, masterPtr->width,
1344 masterPtr->height - masterPtr->ditherY);
1345 }
1346
1347 if (y < masterPtr->height) {
1348 /*
1349 * Tell the core image code that part of the image has changed.
1350 */
1351
1352 Tk_ImageChanged(masterPtr->tkMaster, x, y,
1353 (masterPtr->width - x), (masterPtr->height - y),
1354 masterPtr->width, masterPtr->height);
1355 }
1356 return TCL_OK;
1357
1358 case PHOTO_TRANS: {
1359 static const char *photoTransOptions[] = {
1360 "get", "set", NULL
1361 };
1362 enum transOptions {
1363 PHOTO_TRANS_GET, PHOTO_TRANS_SET
1364 };
1365
1366 if (objc < 3) {
1367 Tcl_WrongNumArgs(interp, 2, objv, "option ?arg arg ...?");
1368 return TCL_ERROR;
1369 }
1370 if (Tcl_GetIndexFromObj(interp, objv[2], photoTransOptions, "option",
1371 0, &index) != TCL_OK) {
1372 return TCL_ERROR;
1373 }
1374
1375 switch ((enum transOptions) index) {
1376 case PHOTO_TRANS_GET: {
1377 XRectangle testBox;
1378 TkRegion testRegion;
1379
1380 if (objc != 5) {
1381 Tcl_WrongNumArgs(interp, 3, objv, "x y");
1382 return TCL_ERROR;
1383 }
1384 if ((Tcl_GetIntFromObj(interp, objv[3], &x) != TCL_OK)
1385 || (Tcl_GetIntFromObj(interp, objv[4], &y) != TCL_OK)) {
1386 return TCL_ERROR;
1387 }
1388 if ((x < 0) || (x >= masterPtr->width)
1389 || (y < 0) || (y >= masterPtr->height)) {
1390 Tcl_AppendResult(interp, Tcl_GetString(objv[0]),
1391 " transparency get: coordinates out of range", NULL);
1392 return TCL_ERROR;
1393 }
1394
1395 testBox.x = x;
1396 testBox.y = y;
1397 testBox.width = 1;
1398 testBox.height = 1;
1399 /* What a way to do a test! */
1400 testRegion = TkCreateRegion();
1401 TkUnionRectWithRegion(&testBox, testRegion, testRegion);
1402 TkIntersectRegion(testRegion, masterPtr->validRegion, testRegion);
1403 TkClipBox(testRegion, &testBox);
1404 TkDestroyRegion(testRegion);
1405
1406 Tcl_SetBooleanObj(Tcl_GetObjResult(interp),
1407 (testBox.width==0 && testBox.height==0));
1408 return TCL_OK;
1409 }
1410
1411 case PHOTO_TRANS_SET: {
1412 int transFlag;
1413 XRectangle setBox;
1414
1415 if (objc != 6) {
1416 Tcl_WrongNumArgs(interp, 3, objv, "x y boolean");
1417 return TCL_ERROR;
1418 }
1419 if ((Tcl_GetIntFromObj(interp, objv[3], &x) != TCL_OK)
1420 || (Tcl_GetIntFromObj(interp, objv[4], &y) != TCL_OK)
1421 || (Tcl_GetBooleanFromObj(interp, objv[5],
1422 &transFlag) != TCL_OK)) {
1423 return TCL_ERROR;
1424 }
1425 if ((x < 0) || (x >= masterPtr->width)
1426 || (y < 0) || (y >= masterPtr->height)) {
1427 Tcl_AppendResult(interp, Tcl_GetString(objv[0]),
1428 " transparency set: coordinates out of range", NULL);
1429 return TCL_ERROR;
1430 }
1431
1432 setBox.x = x;
1433 setBox.y = y;
1434 setBox.width = 1;
1435 setBox.height = 1;
1436 pixelPtr = masterPtr->pix32 + (y * masterPtr->width + x) * 4;
1437
1438 if (transFlag) {
1439 /*
1440 * Make pixel transparent.
1441 */
1442
1443 TkRegion clearRegion = TkCreateRegion();
1444
1445 TkUnionRectWithRegion(&setBox, clearRegion, clearRegion);
1446 TkSubtractRegion(masterPtr->validRegion, clearRegion,
1447 masterPtr->validRegion);
1448 TkDestroyRegion(clearRegion);
1449
1450 /*
1451 * Set the alpha value correctly.
1452 */
1453
1454 pixelPtr[3] = 0;
1455 } else {
1456 /*
1457 * Make pixel opaque.
1458 */
1459
1460 TkUnionRectWithRegion(&setBox, masterPtr->validRegion,
1461 masterPtr->validRegion);
1462 pixelPtr[3] = 255;
1463 }
1464
1465 /*
1466 * Inform the generic image code that the image
1467 * has (potentially) changed.
1468 */
1469
1470 Tk_ImageChanged(masterPtr->tkMaster, x, y, 1, 1,
1471 masterPtr->width, masterPtr->height);
1472 masterPtr->flags &= ~IMAGE_CHANGED;
1473 return TCL_OK;
1474 }
1475
1476 }
1477 Tcl_Panic("unexpected fallthrough");
1478 }
1479
1480 case PHOTO_WRITE: {
1481 char *data;
1482 Tcl_Obj *format;
1483
1484 /*
1485 * Prevent file system access in safe interpreters.
1486 */
1487
1488 if (Tcl_IsSafe(interp)) {
1489 Tcl_AppendResult(interp, "can't write image to a file in a",
1490 " safe interpreter", NULL);
1491 return TCL_ERROR;
1492 }
1493
1494 /*
1495 * photo write command - first parse and check any options given.
1496 */
1497
1498 index = 2;
1499 memset(&options, 0, sizeof(options));
1500 options.name = NULL;
1501 options.format = NULL;
1502 if (ParseSubcommandOptions(&options, interp,
1503 OPT_FORMAT | OPT_FROM | OPT_GRAYSCALE | OPT_BACKGROUND,
1504 &index, objc, objv) != TCL_OK) {
1505 return TCL_ERROR;
1506 }
1507 if ((options.name == NULL) || (index < objc)) {
1508 Tcl_WrongNumArgs(interp, 2, objv, "fileName ?options?");
1509 return TCL_ERROR;
1510 }
1511 if ((options.fromX > masterPtr->width)
1512 || (options.fromY > masterPtr->height)
1513 || (options.fromX2 > masterPtr->width)
1514 || (options.fromY2 > masterPtr->height)) {
1515 Tcl_AppendResult(interp, "coordinates for -from option extend ",
1516 "outside image", NULL);
1517 return TCL_ERROR;
1518 }
1519
1520 /*
1521 * Fill in default values for unspecified parameters.
1522 */
1523
1524 if (!(options.options & OPT_FROM) || (options.fromX2 < 0)) {
1525 options.fromX2 = masterPtr->width;
1526 options.fromY2 = masterPtr->height;
1527 }
1528
1529 /*
1530 * Search for an appropriate image file format handler, and give an
1531 * error if none is found.
1532 */
1533
1534 matched = 0;
1535 for (imageFormat = tsdPtr->formatList; imageFormat != NULL;
1536 imageFormat = imageFormat->nextPtr) {
1537 if ((options.format == NULL)
1538 || (strncasecmp(Tcl_GetString(options.format),
1539 imageFormat->name, strlen(imageFormat->name)) == 0)) {
1540 matched = 1;
1541 if (imageFormat->fileWriteProc != NULL) {
1542 break;
1543 }
1544 }
1545 }
1546 if (imageFormat == NULL) {
1547 oldformat = 1;
1548 for (imageFormat = tsdPtr->oldFormatList; imageFormat != NULL;
1549 imageFormat = imageFormat->nextPtr) {
1550 if ((options.format == NULL)
1551 || (strncasecmp(Tcl_GetString(options.format),
1552 imageFormat->name, strlen(imageFormat->name)) == 0)) {
1553 matched = 1;
1554 if (imageFormat->fileWriteProc != NULL) {
1555 break;
1556 }
1557 }
1558 }
1559 }
1560 if (imageFormat == NULL) {
1561 if (options.format == NULL) {
1562 Tcl_AppendResult(interp, "no available image file format ",
1563 "has file writing capability", NULL);
1564 } else if (!matched) {
1565 Tcl_AppendResult(interp, "image file format \"",
1566 Tcl_GetString(options.format),
1567 "\" is unknown", NULL);
1568 } else {
1569 Tcl_AppendResult(interp, "image file format \"",
1570 Tcl_GetString(options.format),
1571 "\" has no file writing capability", NULL);
1572 }
1573 return TCL_ERROR;
1574 }
1575
1576 /*
1577 * Call the handler's file write function to write out the image.
1578 */
1579
1580 data = ImgGetPhoto(masterPtr, &block, &options);
1581 format = options.format;
1582 if (oldformat && format) {
1583 format = (Tcl_Obj *) Tcl_GetString(options.format);
1584 }
1585 result = (*imageFormat->fileWriteProc)(interp,
1586 Tcl_GetString(options.name), format, &block);
1587 if (options.background) {
1588 Tk_FreeColor(options.background);
1589 }
1590 if (data) {
1591 ckfree(data);
1592 }
1593 return result;
1594 }
1595
1596 }
1597 Tcl_Panic("unexpected fallthrough");
1598 return TCL_ERROR; /* NOT REACHED */
1599 }
1600
1601 /*
1602 *----------------------------------------------------------------------
1603 *
1604 * ParseSubcommandOptions --
1605 *
1606 * This function is invoked to process one of the options which may be
1607 * specified for the photo image subcommands, namely, -from, -to, -zoom,
1608 * -subsample, -format, -shrink, and -compositingrule.
1609 *
1610 * Results:
1611 * A standard Tcl result.
1612 *
1613 * Side effects:
1614 * Fields in *optPtr get filled in.
1615 *
1616 *----------------------------------------------------------------------
1617 */
1618
1619 static int
ParseSubcommandOptions(struct SubcommandOptions * optPtr,Tcl_Interp * interp,int allowedOptions,int * optIndexPtr,int objc,Tcl_Obj * const objv[])1620 ParseSubcommandOptions(
1621 struct SubcommandOptions *optPtr,
1622 /* Information about the options specified and
1623 * the values given is returned here. */
1624 Tcl_Interp *interp, /* Interpreter to use for reporting errors. */
1625 int allowedOptions, /* Indicates which options are valid for the
1626 * current command. */
1627 int *optIndexPtr, /* Points to a variable containing the current
1628 * index in objv; this variable is updated by
1629 * this function. */
1630 int objc, /* Number of arguments in objv[]. */
1631 Tcl_Obj *const objv[]) /* Arguments to be parsed. */
1632 {
1633 int index, c, bit, currentBit, length;
1634 int values[4], numValues, maxValues, argIndex;
1635 char *option;
1636 const char *const *listPtr;
1637
1638 for (index = *optIndexPtr; index < objc; *optIndexPtr = ++index) {
1639 /*
1640 * We can have one value specified without an option; it goes into
1641 * optPtr->name.
1642 */
1643
1644 option = Tcl_GetStringFromObj(objv[index], &length);
1645 if (option[0] != '-') {
1646 if (optPtr->name == NULL) {
1647 optPtr->name = objv[index];
1648 continue;
1649 }
1650 break;
1651 }
1652
1653 /*
1654 * Work out which option this is.
1655 */
1656
1657 c = option[0];
1658 bit = 0;
1659 currentBit = 1;
1660 for (listPtr = optionNames; *listPtr != NULL; ++listPtr) {
1661 if ((c == *listPtr[0])
1662 && (strncmp(option, *listPtr, (size_t) length) == 0)) {
1663 if (bit != 0) {
1664 bit = 0; /* An ambiguous option. */
1665 break;
1666 }
1667 bit = currentBit;
1668 }
1669 currentBit <<= 1;
1670 }
1671
1672 /*
1673 * If this option is not recognized and allowed, put an error message
1674 * in the interpreter and return.
1675 */
1676
1677 if ((allowedOptions & bit) == 0) {
1678 Tcl_AppendResult(interp, "unrecognized option \"",
1679 Tcl_GetString(objv[index]),
1680 "\": must be ", NULL);
1681 bit = 1;
1682 for (listPtr = optionNames; *listPtr != NULL; ++listPtr) {
1683 if ((allowedOptions & bit) != 0) {
1684 if ((allowedOptions & (bit - 1)) != 0) {
1685 Tcl_AppendResult(interp, ", ", NULL);
1686 if ((allowedOptions & ~((bit << 1) - 1)) == 0) {
1687 Tcl_AppendResult(interp, "or ", NULL);
1688 }
1689 }
1690 Tcl_AppendResult(interp, *listPtr, NULL);
1691 }
1692 bit <<= 1;
1693 }
1694 return TCL_ERROR;
1695 }
1696
1697 /*
1698 * For the -from, -to, -zoom and -subsample options, parse the values
1699 * given. Report an error if too few or too many values are given.
1700 */
1701
1702 if (bit == OPT_BACKGROUND) {
1703 /*
1704 * The -background option takes a single XColor value.
1705 */
1706
1707 if (index + 1 < objc) {
1708 *optIndexPtr = ++index;
1709 optPtr->background = Tk_GetColor(interp, Tk_MainWindow(interp),
1710 Tk_GetUid(Tcl_GetString(objv[index])));
1711 if (!optPtr->background) {
1712 return TCL_ERROR;
1713 }
1714 } else {
1715 Tcl_AppendResult(interp, "the \"-background\" option ",
1716 "requires a value", NULL);
1717 return TCL_ERROR;
1718 }
1719 } else if (bit == OPT_FORMAT) {
1720 /*
1721 * The -format option takes a single string value. Note that
1722 * parsing this is outside the scope of this function.
1723 */
1724
1725 if (index + 1 < objc) {
1726 *optIndexPtr = ++index;
1727 optPtr->format = objv[index];
1728 } else {
1729 Tcl_AppendResult(interp, "the \"-format\" option ",
1730 "requires a value", NULL);
1731 return TCL_ERROR;
1732 }
1733 } else if (bit == OPT_COMPOSITE) {
1734 /*
1735 * The -compositingrule option takes a single value from a
1736 * well-known set.
1737 */
1738
1739 if (index + 1 < objc) {
1740 /*
1741 * Note that these must match the TK_PHOTO_COMPOSITE_*
1742 * constants.
1743 */
1744
1745 static const char *compositingRules[] = {
1746 "overlay", "set", NULL
1747 };
1748
1749 index++;
1750 if (Tcl_GetIndexFromObj(interp, objv[index], compositingRules,
1751 "compositing rule", 0, &optPtr->compositingRule)
1752 != TCL_OK) {
1753 return TCL_ERROR;
1754 }
1755 *optIndexPtr = index;
1756 } else {
1757 Tcl_AppendResult(interp, "the \"-compositingrule\" option ",
1758 "requires a value", NULL);
1759 return TCL_ERROR;
1760 }
1761 } else if ((bit != OPT_SHRINK) && (bit != OPT_GRAYSCALE)) {
1762 char *val;
1763 maxValues = ((bit == OPT_FROM) || (bit == OPT_TO))? 4: 2;
1764 argIndex = index + 1;
1765 for (numValues = 0; numValues < maxValues; ++numValues) {
1766 if (argIndex >= objc) {
1767 break;
1768 }
1769 val = Tcl_GetString(objv[argIndex]);
1770 if ((argIndex < objc) && (isdigit(UCHAR(val[0]))
1771 || ((val[0] == '-') && isdigit(UCHAR(val[1]))))) {
1772 if (Tcl_GetInt(interp, val, &values[numValues])
1773 != TCL_OK) {
1774 return TCL_ERROR;
1775 }
1776 } else {
1777 break;
1778 }
1779 ++argIndex;
1780 }
1781
1782 if (numValues == 0) {
1783 Tcl_AppendResult(interp, "the \"", option, "\" option ",
1784 "requires one ", maxValues == 2? "or two": "to four",
1785 " integer values", NULL);
1786 return TCL_ERROR;
1787 }
1788 *optIndexPtr = (index += numValues);
1789
1790 /*
1791 * Y values default to the corresponding X value if not specified.
1792 */
1793
1794 if (numValues == 1) {
1795 values[1] = values[0];
1796 }
1797 if (numValues == 3) {
1798 values[3] = values[2];
1799 }
1800
1801 /*
1802 * Check the values given and put them in the appropriate field of
1803 * the SubcommandOptions structure.
1804 */
1805
1806 switch (bit) {
1807 case OPT_FROM:
1808 if ((values[0] < 0) || (values[1] < 0) || ((numValues > 2)
1809 && ((values[2] < 0) || (values[3] < 0)))) {
1810 Tcl_AppendResult(interp, "value(s) for the -from",
1811 " option must be non-negative", NULL);
1812 return TCL_ERROR;
1813 }
1814 if (numValues <= 2) {
1815 optPtr->fromX = values[0];
1816 optPtr->fromY = values[1];
1817 optPtr->fromX2 = -1;
1818 optPtr->fromY2 = -1;
1819 } else {
1820 optPtr->fromX = MIN(values[0], values[2]);
1821 optPtr->fromY = MIN(values[1], values[3]);
1822 optPtr->fromX2 = MAX(values[0], values[2]);
1823 optPtr->fromY2 = MAX(values[1], values[3]);
1824 }
1825 break;
1826 case OPT_SUBSAMPLE:
1827 optPtr->subsampleX = values[0];
1828 optPtr->subsampleY = values[1];
1829 break;
1830 case OPT_TO:
1831 if ((values[0] < 0) || (values[1] < 0) || ((numValues > 2)
1832 && ((values[2] < 0) || (values[3] < 0)))) {
1833 Tcl_AppendResult(interp, "value(s) for the -to",
1834 " option must be non-negative", NULL);
1835 return TCL_ERROR;
1836 }
1837 if (numValues <= 2) {
1838 optPtr->toX = values[0];
1839 optPtr->toY = values[1];
1840 optPtr->toX2 = -1;
1841 optPtr->toY2 = -1;
1842 } else {
1843 optPtr->toX = MIN(values[0], values[2]);
1844 optPtr->toY = MIN(values[1], values[3]);
1845 optPtr->toX2 = MAX(values[0], values[2]);
1846 optPtr->toY2 = MAX(values[1], values[3]);
1847 }
1848 break;
1849 case OPT_ZOOM:
1850 if ((values[0] <= 0) || (values[1] <= 0)) {
1851 Tcl_AppendResult(interp, "value(s) for the -zoom",
1852 " option must be positive", NULL);
1853 return TCL_ERROR;
1854 }
1855 optPtr->zoomX = values[0];
1856 optPtr->zoomY = values[1];
1857 break;
1858 }
1859 }
1860
1861 /*
1862 * Remember that we saw this option.
1863 */
1864
1865 optPtr->options |= bit;
1866 }
1867
1868 return TCL_OK;
1869 }
1870
1871 /*
1872 *----------------------------------------------------------------------
1873 *
1874 * ImgPhotoConfigureMaster --
1875 *
1876 * This function is called when a photo image is created or reconfigured.
1877 * It processes configuration options and resets any instances of the
1878 * image.
1879 *
1880 * Results:
1881 * A standard Tcl return value. If TCL_ERROR is returned then an error
1882 * message is left in the masterPtr->interp's result.
1883 *
1884 * Side effects:
1885 * Existing instances of the image will be redisplayed to match the new
1886 * configuration options.
1887 *
1888 *----------------------------------------------------------------------
1889 */
1890
1891 static int
ImgPhotoConfigureMaster(Tcl_Interp * interp,PhotoMaster * masterPtr,int objc,Tcl_Obj * const objv[],int flags)1892 ImgPhotoConfigureMaster(
1893 Tcl_Interp *interp, /* Interpreter to use for reporting errors. */
1894 PhotoMaster *masterPtr, /* Pointer to data structure describing
1895 * overall photo image to (re)configure. */
1896 int objc, /* Number of entries in objv. */
1897 Tcl_Obj *const objv[], /* Pairs of configuration options for image. */
1898 int flags) /* Flags to pass to Tk_ConfigureWidget, such
1899 * as TK_CONFIG_ARGV_ONLY. */
1900 {
1901 PhotoInstance *instancePtr;
1902 const char *oldFileString, *oldPaletteString;
1903 Tcl_Obj *oldData, *data = NULL, *oldFormat, *format = NULL;
1904 Tcl_Obj *tempdata, *tempformat;
1905 int length, i, j, result, imageWidth, imageHeight, oldformat;
1906 double oldGamma;
1907 Tcl_Channel chan;
1908 Tk_PhotoImageFormat *imageFormat;
1909 const char **args;
1910
1911 args = (const char **) ckalloc((objc + 1) * sizeof(char *));
1912 for (i = 0, j = 0; i < objc; i++,j++) {
1913 args[j] = Tcl_GetStringFromObj(objv[i], &length);
1914 if ((length > 1) && (args[j][0] == '-')) {
1915 if ((args[j][1] == 'd') &&
1916 !strncmp(args[j], "-data", (size_t) length)) {
1917 if (++i < objc) {
1918 data = objv[i];
1919 j--;
1920 } else {
1921 Tcl_AppendResult(interp,
1922 "value for \"-data\" missing", NULL);
1923 return TCL_ERROR;
1924 }
1925 } else if ((args[j][1] == 'f') &&
1926 !strncmp(args[j], "-format", (size_t) length)) {
1927 if (++i < objc) {
1928 format = objv[i];
1929 j--;
1930 } else {
1931 Tcl_AppendResult(interp,
1932 "value for \"-format\" missing", NULL);
1933 return TCL_ERROR;
1934 }
1935 }
1936 }
1937 }
1938
1939 /*
1940 * Save the current values for fileString and dataString, so we can tell
1941 * if the user specifies them anew. IMPORTANT: if the format changes we
1942 * have to interpret "-file" and "-data" again as well! It might be that
1943 * the format string influences how "-data" or "-file" is interpreted.
1944 */
1945
1946 oldFileString = masterPtr->fileString;
1947 if (oldFileString == NULL) {
1948 oldData = masterPtr->dataString;
1949 if (oldData != NULL) {
1950 Tcl_IncrRefCount(oldData);
1951 }
1952 } else {
1953 oldData = NULL;
1954 }
1955 oldFormat = masterPtr->format;
1956 if (oldFormat != NULL) {
1957 Tcl_IncrRefCount(oldFormat);
1958 }
1959 oldPaletteString = masterPtr->palette;
1960 oldGamma = masterPtr->gamma;
1961
1962 /*
1963 * Process the configuration options specified.
1964 */
1965
1966 if (Tk_ConfigureWidget(interp, Tk_MainWindow(interp), configSpecs,
1967 j, args, (char *) masterPtr, flags) != TCL_OK) {
1968 ckfree((char *) args);
1969 goto errorExit;
1970 }
1971 ckfree((char *) args);
1972
1973 /*
1974 * Regard the empty string for -file, -data or -format as the null value.
1975 */
1976
1977 if ((masterPtr->fileString != NULL) && (masterPtr->fileString[0] == 0)) {
1978 ckfree(masterPtr->fileString);
1979 masterPtr->fileString = NULL;
1980 }
1981 if (data) {
1982 /*
1983 * Force into ByteArray format, which most (all) image handlers will
1984 * use anyway. Empty length means ignore the -data option.
1985 */
1986
1987 (void) Tcl_GetByteArrayFromObj(data, &length);
1988 if (length) {
1989 Tcl_IncrRefCount(data);
1990 } else {
1991 data = NULL;
1992 }
1993 if (masterPtr->dataString) {
1994 Tcl_DecrRefCount(masterPtr->dataString);
1995 }
1996 masterPtr->dataString = data;
1997 }
1998 if (format) {
1999 /*
2000 * Stringify to ignore -format "". It may come in as a list or other
2001 * object.
2002 */
2003
2004 (void) Tcl_GetStringFromObj(format, &length);
2005 if (length) {
2006 Tcl_IncrRefCount(format);
2007 } else {
2008 format = NULL;
2009 }
2010 if (masterPtr->format) {
2011 Tcl_DecrRefCount(masterPtr->format);
2012 }
2013 masterPtr->format = format;
2014 }
2015 /*
2016 * Set the image to the user-requested size, if any, and make sure storage
2017 * is correctly allocated for this image.
2018 */
2019
2020 if (ImgPhotoSetSize(masterPtr, masterPtr->width,
2021 masterPtr->height) != TCL_OK) {
2022 Tcl_ResetResult(interp);
2023 Tcl_AppendResult(interp, TK_PHOTO_ALLOC_FAILURE_MESSAGE, NULL);
2024 goto errorExit;
2025 }
2026
2027 /*
2028 * Read in the image from the file or string if the user has specified the
2029 * -file or -data option.
2030 */
2031
2032 if ((masterPtr->fileString != NULL)
2033 && ((masterPtr->fileString != oldFileString)
2034 || (masterPtr->format != oldFormat))) {
2035
2036 /*
2037 * Prevent file system access in a safe interpreter.
2038 */
2039
2040 if (Tcl_IsSafe(interp)) {
2041 Tcl_ResetResult(interp);
2042 Tcl_AppendResult(interp,
2043 "can't get image from a file in a safe interpreter", NULL);
2044 goto errorExit;
2045 }
2046
2047 chan = Tcl_OpenFileChannel(interp, masterPtr->fileString, "r", 0);
2048 if (chan == NULL) {
2049 goto errorExit;
2050 }
2051
2052 /*
2053 * -translation binary also sets -encoding binary
2054 */
2055
2056 if ((Tcl_SetChannelOption(interp, chan,
2057 "-translation", "binary") != TCL_OK) ||
2058 (MatchFileFormat(interp, chan, masterPtr->fileString,
2059 masterPtr->format, &imageFormat, &imageWidth,
2060 &imageHeight, &oldformat) != TCL_OK)) {
2061 Tcl_Close(NULL, chan);
2062 goto errorExit;
2063 }
2064 result = ImgPhotoSetSize(masterPtr, imageWidth, imageHeight);
2065 if (result != TCL_OK) {
2066 Tcl_Close(NULL, chan);
2067 Tcl_ResetResult(interp);
2068 Tcl_AppendResult(interp, TK_PHOTO_ALLOC_FAILURE_MESSAGE, NULL);
2069 goto errorExit;
2070 }
2071 tempformat = masterPtr->format;
2072 if (oldformat && tempformat) {
2073 tempformat = (Tcl_Obj *) Tcl_GetString(tempformat);
2074 }
2075 result = (*imageFormat->fileReadProc)(interp, chan,
2076 masterPtr->fileString, tempformat, (Tk_PhotoHandle) masterPtr,
2077 0, 0, imageWidth, imageHeight, 0, 0);
2078 Tcl_Close(NULL, chan);
2079 if (result != TCL_OK) {
2080 goto errorExit;
2081 }
2082
2083 Tcl_ResetResult(interp);
2084 masterPtr->flags |= IMAGE_CHANGED;
2085 }
2086
2087 if ((masterPtr->fileString == NULL) && (masterPtr->dataString != NULL)
2088 && ((masterPtr->dataString != oldData)
2089 || (masterPtr->format != oldFormat))) {
2090
2091 if (MatchStringFormat(interp, masterPtr->dataString,
2092 masterPtr->format, &imageFormat, &imageWidth,
2093 &imageHeight, &oldformat) != TCL_OK) {
2094 goto errorExit;
2095 }
2096 if (ImgPhotoSetSize(masterPtr, imageWidth, imageHeight) != TCL_OK) {
2097 Tcl_ResetResult(interp);
2098 Tcl_AppendResult(interp, TK_PHOTO_ALLOC_FAILURE_MESSAGE, NULL);
2099 goto errorExit;
2100 }
2101 tempformat = masterPtr->format;
2102 tempdata = masterPtr->dataString;
2103 if (oldformat) {
2104 if (tempformat) {
2105 tempformat = (Tcl_Obj *) Tcl_GetString(tempformat);
2106 }
2107 tempdata = (Tcl_Obj *) Tcl_GetString(tempdata);
2108 }
2109 if ((*imageFormat->stringReadProc)(interp, tempdata,
2110 tempformat, (Tk_PhotoHandle) masterPtr,
2111 0, 0, imageWidth, imageHeight, 0, 0) != TCL_OK) {
2112 goto errorExit;
2113 }
2114
2115 Tcl_ResetResult(interp);
2116 masterPtr->flags |= IMAGE_CHANGED;
2117 }
2118
2119 /*
2120 * Enforce a reasonable value for gamma.
2121 */
2122
2123 if (masterPtr->gamma <= 0) {
2124 masterPtr->gamma = 1.0;
2125 }
2126
2127 if ((masterPtr->gamma != oldGamma)
2128 || (masterPtr->palette != oldPaletteString)) {
2129 masterPtr->flags |= IMAGE_CHANGED;
2130 }
2131
2132 /*
2133 * Cycle through all of the instances of this image, regenerating the
2134 * information for each instance. Then force the image to be redisplayed
2135 * everywhere that it is used.
2136 */
2137
2138 for (instancePtr = masterPtr->instancePtr; instancePtr != NULL;
2139 instancePtr = instancePtr->nextPtr) {
2140 ImgPhotoConfigureInstance(instancePtr);
2141 }
2142
2143 /*
2144 * Inform the generic image code that the image has (potentially) changed.
2145 */
2146
2147 Tk_ImageChanged(masterPtr->tkMaster, 0, 0, masterPtr->width,
2148 masterPtr->height, masterPtr->width, masterPtr->height);
2149 masterPtr->flags &= ~IMAGE_CHANGED;
2150
2151 if (oldData != NULL) {
2152 Tcl_DecrRefCount(oldData);
2153 }
2154 if (oldFormat != NULL) {
2155 Tcl_DecrRefCount(oldFormat);
2156 }
2157
2158 ToggleComplexAlphaIfNeeded(masterPtr);
2159
2160 return TCL_OK;
2161
2162 errorExit:
2163 if (oldData != NULL) {
2164 Tcl_DecrRefCount(oldData);
2165 }
2166 if (oldFormat != NULL) {
2167 Tcl_DecrRefCount(oldFormat);
2168 }
2169 return TCL_ERROR;
2170 }
2171
2172 /*
2173 *----------------------------------------------------------------------
2174 *
2175 * ImgPhotoConfigureInstance --
2176 *
2177 * This function is called to create displaying information for a photo
2178 * image instance based on the configuration information in the master.
2179 * It is invoked both when new instances are created and when the master
2180 * is reconfigured.
2181 *
2182 * Results:
2183 * None.
2184 *
2185 * Side effects:
2186 * Generates errors via Tcl_BackgroundError if there are problems in
2187 * setting up the instance.
2188 *
2189 *----------------------------------------------------------------------
2190 */
2191
2192 static void
ImgPhotoConfigureInstance(PhotoInstance * instancePtr)2193 ImgPhotoConfigureInstance(
2194 PhotoInstance *instancePtr) /* Instance to reconfigure. */
2195 {
2196 PhotoMaster *masterPtr = instancePtr->masterPtr;
2197 XImage *imagePtr;
2198 int bitsPerPixel;
2199 ColorTable *colorTablePtr;
2200 XRectangle validBox;
2201
2202 /*
2203 * If the -palette configuration option has been set for the master, use
2204 * the value specified for our palette, but only if it is a valid palette
2205 * for our windows. Use the gamma value specified the master.
2206 */
2207
2208 if ((masterPtr->palette && masterPtr->palette[0])
2209 && IsValidPalette(instancePtr, masterPtr->palette)) {
2210 instancePtr->palette = masterPtr->palette;
2211 } else {
2212 instancePtr->palette = instancePtr->defaultPalette;
2213 }
2214 instancePtr->gamma = masterPtr->gamma;
2215
2216 /*
2217 * If we don't currently have a color table, or if the one we have no
2218 * longer applies (e.g. because our palette or gamma has changed), get a
2219 * new one.
2220 */
2221
2222 colorTablePtr = instancePtr->colorTablePtr;
2223 if ((colorTablePtr == NULL)
2224 || (instancePtr->colormap != colorTablePtr->id.colormap)
2225 || (instancePtr->palette != colorTablePtr->id.palette)
2226 || (instancePtr->gamma != colorTablePtr->id.gamma)) {
2227 /*
2228 * Free up our old color table, and get a new one.
2229 */
2230
2231 if (colorTablePtr != NULL) {
2232 colorTablePtr->liveRefCount -= 1;
2233 FreeColorTable(colorTablePtr, 0);
2234 }
2235 GetColorTable(instancePtr);
2236
2237 /*
2238 * Create a new XImage structure for sending data to the X server, if
2239 * necessary.
2240 */
2241
2242 if (instancePtr->colorTablePtr->flags & BLACK_AND_WHITE) {
2243 bitsPerPixel = 1;
2244 } else {
2245 bitsPerPixel = instancePtr->visualInfo.depth;
2246 }
2247
2248 if ((instancePtr->imagePtr == NULL)
2249 || (instancePtr->imagePtr->bits_per_pixel != bitsPerPixel)) {
2250 if (instancePtr->imagePtr != NULL) {
2251 XDestroyImage(instancePtr->imagePtr);
2252 }
2253 imagePtr = XCreateImage(instancePtr->display,
2254 instancePtr->visualInfo.visual, (unsigned) bitsPerPixel,
2255 (bitsPerPixel > 1? ZPixmap: XYBitmap), 0, NULL,
2256 1, 1, 32, 0);
2257 instancePtr->imagePtr = imagePtr;
2258
2259 /*
2260 * We create images using the local host's endianness, rather than
2261 * the endianness of the server; otherwise we would have to
2262 * byte-swap any 16 or 32 bit values that we store in the image
2263 * if the server's endianness is different from ours.
2264 */
2265
2266 if (imagePtr != NULL) {
2267 #ifdef WORDS_BIGENDIAN
2268 imagePtr->byte_order = MSBFirst;
2269 #else
2270 imagePtr->byte_order = LSBFirst;
2271 #endif
2272 _XInitImageFuncPtrs(imagePtr);
2273 }
2274 }
2275 }
2276
2277 /*
2278 * If the user has specified a width and/or height for the master which is
2279 * different from our current width/height, set the size to the values
2280 * specified by the user. If we have no pixmap, we do this also, since it
2281 * has the side effect of allocating a pixmap for us.
2282 */
2283
2284 if ((instancePtr->pixels == None) || (instancePtr->error == NULL)
2285 || (instancePtr->width != masterPtr->width)
2286 || (instancePtr->height != masterPtr->height)) {
2287 ImgPhotoInstanceSetSize(instancePtr);
2288 }
2289
2290 /*
2291 * Redither this instance if necessary.
2292 */
2293
2294 if ((masterPtr->flags & IMAGE_CHANGED)
2295 || (instancePtr->colorTablePtr != colorTablePtr)) {
2296 TkClipBox(masterPtr->validRegion, &validBox);
2297 if ((validBox.width > 0) && (validBox.height > 0)) {
2298 DitherInstance(instancePtr, validBox.x, validBox.y,
2299 validBox.width, validBox.height);
2300 }
2301 }
2302 }
2303
2304 /*
2305 *----------------------------------------------------------------------
2306 *
2307 * ImgPhotoGet --
2308 *
2309 * This function is called for each use of a photo image in a widget.
2310 *
2311 * Results:
2312 * The return value is a token for the instance, which is passed back to
2313 * us in calls to ImgPhotoDisplay and ImgPhotoFree.
2314 *
2315 * Side effects:
2316 * A data structure is set up for the instance (or, an existing instance
2317 * is re-used for the new one).
2318 *
2319 *----------------------------------------------------------------------
2320 */
2321
2322 static ClientData
ImgPhotoGet(Tk_Window tkwin,ClientData masterData)2323 ImgPhotoGet(
2324 Tk_Window tkwin, /* Window in which the instance will be
2325 * used. */
2326 ClientData masterData) /* Pointer to our master structure for the
2327 * image. */
2328 {
2329 PhotoMaster *masterPtr = (PhotoMaster *) masterData;
2330 PhotoInstance *instancePtr;
2331 Colormap colormap;
2332 int mono, nRed, nGreen, nBlue, numVisuals;
2333 XVisualInfo visualInfo, *visInfoPtr;
2334 char buf[TCL_INTEGER_SPACE * 3];
2335 XColor *white, *black;
2336 XGCValues gcValues;
2337
2338 /*
2339 * Table of "best" choices for palette for PseudoColor displays with
2340 * between 3 and 15 bits/pixel.
2341 */
2342
2343 static const int paletteChoice[13][3] = {
2344 /* #red, #green, #blue */
2345 {2, 2, 2, /* 3 bits, 8 colors */},
2346 {2, 3, 2, /* 4 bits, 12 colors */},
2347 {3, 4, 2, /* 5 bits, 24 colors */},
2348 {4, 5, 3, /* 6 bits, 60 colors */},
2349 {5, 6, 4, /* 7 bits, 120 colors */},
2350 {7, 7, 4, /* 8 bits, 198 colors */},
2351 {8, 10, 6, /* 9 bits, 480 colors */},
2352 {10, 12, 8, /* 10 bits, 960 colors */},
2353 {14, 15, 9, /* 11 bits, 1890 colors */},
2354 {16, 20, 12, /* 12 bits, 3840 colors */},
2355 {20, 24, 16, /* 13 bits, 7680 colors */},
2356 {26, 30, 20, /* 14 bits, 15600 colors */},
2357 {32, 32, 30, /* 15 bits, 30720 colors */}
2358 };
2359
2360 /*
2361 * See if there is already an instance for windows using the same
2362 * colormap. If so then just re-use it.
2363 */
2364
2365 colormap = Tk_Colormap(tkwin);
2366 for (instancePtr = masterPtr->instancePtr; instancePtr != NULL;
2367 instancePtr = instancePtr->nextPtr) {
2368 if ((colormap == instancePtr->colormap)
2369 && (Tk_Display(tkwin) == instancePtr->display)) {
2370 /*
2371 * Re-use this instance.
2372 */
2373
2374 if (instancePtr->refCount == 0) {
2375 /*
2376 * We are resurrecting this instance.
2377 */
2378
2379 Tcl_CancelIdleCall(DisposeInstance, (ClientData) instancePtr);
2380 if (instancePtr->colorTablePtr != NULL) {
2381 FreeColorTable(instancePtr->colorTablePtr, 0);
2382 }
2383 GetColorTable(instancePtr);
2384 }
2385 instancePtr->refCount++;
2386 return (ClientData) instancePtr;
2387 }
2388 }
2389
2390 /*
2391 * The image isn't already in use in a window with the same colormap. Make
2392 * a new instance of the image.
2393 */
2394
2395 instancePtr = (PhotoInstance *) ckalloc(sizeof(PhotoInstance));
2396 instancePtr->masterPtr = masterPtr;
2397 instancePtr->display = Tk_Display(tkwin);
2398 instancePtr->colormap = Tk_Colormap(tkwin);
2399 Tk_PreserveColormap(instancePtr->display, instancePtr->colormap);
2400 instancePtr->refCount = 1;
2401 instancePtr->colorTablePtr = NULL;
2402 instancePtr->pixels = None;
2403 instancePtr->error = NULL;
2404 instancePtr->width = 0;
2405 instancePtr->height = 0;
2406 instancePtr->imagePtr = 0;
2407 instancePtr->nextPtr = masterPtr->instancePtr;
2408 masterPtr->instancePtr = instancePtr;
2409
2410 /*
2411 * Obtain information about the visual and decide on the default palette.
2412 */
2413
2414 visualInfo.screen = Tk_ScreenNumber(tkwin);
2415 visualInfo.visualid = XVisualIDFromVisual(Tk_Visual(tkwin));
2416 visInfoPtr = XGetVisualInfo(Tk_Display(tkwin),
2417 VisualScreenMask | VisualIDMask, &visualInfo, &numVisuals);
2418 if (visInfoPtr == NULL) {
2419 Tcl_Panic("ImgPhotoGet couldn't find visual for window");
2420 }
2421
2422 nRed = 2;
2423 nGreen = nBlue = 0;
2424 mono = 1;
2425 instancePtr->visualInfo = *visInfoPtr;
2426 switch (visInfoPtr->class) {
2427 case DirectColor:
2428 case TrueColor:
2429 nRed = 1 << CountBits(visInfoPtr->red_mask);
2430 nGreen = 1 << CountBits(visInfoPtr->green_mask);
2431 nBlue = 1 << CountBits(visInfoPtr->blue_mask);
2432 mono = 0;
2433 break;
2434 case PseudoColor:
2435 case StaticColor:
2436 if (visInfoPtr->depth > 15) {
2437 nRed = 32;
2438 nGreen = 32;
2439 nBlue = 32;
2440 mono = 0;
2441 } else if (visInfoPtr->depth >= 3) {
2442 const int *ip = paletteChoice[visInfoPtr->depth - 3];
2443
2444 nRed = ip[0];
2445 nGreen = ip[1];
2446 nBlue = ip[2];
2447 mono = 0;
2448 }
2449 break;
2450 case GrayScale:
2451 case StaticGray:
2452 nRed = 1 << visInfoPtr->depth;
2453 break;
2454 }
2455 XFree((char *) visInfoPtr);
2456
2457 if (mono) {
2458 sprintf(buf, "%d", nRed);
2459 } else {
2460 sprintf(buf, "%d/%d/%d", nRed, nGreen, nBlue);
2461 }
2462 instancePtr->defaultPalette = Tk_GetUid(buf);
2463
2464 /*
2465 * Make a GC with background = black and foreground = white.
2466 */
2467
2468 white = Tk_GetColor(masterPtr->interp, tkwin, "white");
2469 black = Tk_GetColor(masterPtr->interp, tkwin, "black");
2470 gcValues.foreground = (white != NULL)? white->pixel:
2471 WhitePixelOfScreen(Tk_Screen(tkwin));
2472 gcValues.background = (black != NULL)? black->pixel:
2473 BlackPixelOfScreen(Tk_Screen(tkwin));
2474 Tk_FreeColor(white);
2475 Tk_FreeColor(black);
2476 gcValues.graphics_exposures = False;
2477 instancePtr->gc = Tk_GetGC(tkwin,
2478 GCForeground|GCBackground|GCGraphicsExposures, &gcValues);
2479
2480 /*
2481 * Set configuration options and finish the initialization of the
2482 * instance. This will also dither the image if necessary.
2483 */
2484
2485 ImgPhotoConfigureInstance(instancePtr);
2486
2487 /*
2488 * If this is the first instance, must set the size of the image.
2489 */
2490
2491 if (instancePtr->nextPtr == NULL) {
2492 Tk_ImageChanged(masterPtr->tkMaster, 0, 0, 0, 0,
2493 masterPtr->width, masterPtr->height);
2494 }
2495
2496 return (ClientData) instancePtr;
2497 }
2498
2499 /*
2500 *----------------------------------------------------------------------
2501 *
2502 * ToggleComplexAlphaIfNeeded --
2503 *
2504 * This function is called when an image is modified to check if any
2505 * partially transparent pixels exist, which requires blending instead of
2506 * straight copy.
2507 *
2508 * Results:
2509 * None.
2510 *
2511 * Side effects:
2512 * (Re)sets COMPLEX_ALPHA flag of master.
2513 *
2514 *----------------------------------------------------------------------
2515 */
2516
2517 static int
ToggleComplexAlphaIfNeeded(PhotoMaster * mPtr)2518 ToggleComplexAlphaIfNeeded(
2519 PhotoMaster *mPtr)
2520 {
2521 size_t len = MAX(mPtr->userWidth, mPtr->width) *
2522 MAX(mPtr->userHeight, mPtr->height) * 4;
2523 unsigned char *c = mPtr->pix32;
2524 unsigned char *end = c + len;
2525
2526 /*
2527 * Set the COMPLEX_ALPHA flag if we have an image with partially
2528 * transparent bits.
2529 */
2530
2531 mPtr->flags &= ~COMPLEX_ALPHA;
2532 c += 3; /* Start at first alpha byte. */
2533 for (; c < end; c += 4) {
2534 if (*c && *c != 255) {
2535 mPtr->flags |= COMPLEX_ALPHA;
2536 break;
2537 }
2538 }
2539 return (mPtr->flags & COMPLEX_ALPHA);
2540 }
2541
2542 /*
2543 *----------------------------------------------------------------------
2544 *
2545 * ImgPhotoBlendComplexAlpha --
2546 *
2547 * This function is called when an image with partially transparent
2548 * pixels must be drawn over another image. It blends the photo data onto
2549 * a local copy of the surface that we are drawing on, *including* the
2550 * pixels drawn by everything that should be drawn underneath the image.
2551 *
2552 * Much of this code has hard-coded values in for speed because this
2553 * routine is performance critical for complex image drawing.
2554 *
2555 * Results:
2556 * None.
2557 *
2558 * Side effects:
2559 * Background image passed in gets drawn over with image data.
2560 *
2561 * Notes:
2562 * This should work on all platforms that set mask and shift data
2563 * properly from the visualInfo. RGB is really only a 24+ bpp version
2564 * whereas RGB15 is the correct version and works for 15bpp+, but it
2565 * slower, so it's only used for 15bpp+.
2566 *
2567 * Note that Win32 pre-defines those operations that we really need.
2568 *
2569 *----------------------------------------------------------------------
2570 */
2571
2572 #ifndef __WIN32__
2573 #define GetRValue(rgb) (UCHAR(((rgb) & red_mask) >> red_shift))
2574 #define GetGValue(rgb) (UCHAR(((rgb) & green_mask) >> green_shift))
2575 #define GetBValue(rgb) (UCHAR(((rgb) & blue_mask) >> blue_shift))
2576 #define RGB(r, g, b) ((unsigned)( \
2577 (UCHAR(r) << red_shift) | \
2578 (UCHAR(g) << green_shift) | \
2579 (UCHAR(b) << blue_shift) ))
2580 #define RGB15(r, g, b) ((unsigned)( \
2581 (((r) * red_mask / 255) & red_mask) | \
2582 (((g) * green_mask / 255) & green_mask) | \
2583 (((b) * blue_mask / 255) & blue_mask) ))
2584 #endif /* !__WIN32__ */
2585
2586 static void
ImgPhotoBlendComplexAlpha(XImage * bgImg,PhotoInstance * iPtr,int xOffset,int yOffset,int width,int height)2587 ImgPhotoBlendComplexAlpha(
2588 XImage *bgImg, /* Background image to draw on. */
2589 PhotoInstance *iPtr, /* Image instance to draw. */
2590 int xOffset, int yOffset, /* X & Y offset into image instance to
2591 * draw. */
2592 int width, int height) /* Width & height of image to draw. */
2593 {
2594 int x, y, line;
2595 unsigned long pixel;
2596 unsigned char r, g, b, alpha, unalpha, *masterPtr;
2597 unsigned char *alphaAr = iPtr->masterPtr->pix32;
2598
2599 /*
2600 * This blending is an integer version of the Source-Over compositing rule
2601 * (see Porter&Duff, "Compositing Digital Images", proceedings of SIGGRAPH
2602 * 1984) that has been hard-coded (for speed) to work with targetting a
2603 * solid surface.
2604 *
2605 * The 'unalpha' field must be 255-alpha; it is separated out to encourage
2606 * more efficient compilation.
2607 */
2608
2609 #define ALPHA_BLEND(bgPix, imgPix, alpha, unalpha) \
2610 ((bgPix * unalpha + imgPix * alpha) / 255)
2611
2612 /*
2613 * We have to get the mask and shift info from the visual on non-Win32 so
2614 * that the macros Get*Value(), RGB() and RGB15() work correctly. This
2615 * might be cached for better performance.
2616 */
2617
2618 #ifndef __WIN32__
2619 unsigned long red_mask, green_mask, blue_mask;
2620 unsigned long red_shift, green_shift, blue_shift;
2621 Visual *visual = iPtr->visualInfo.visual;
2622
2623 red_mask = visual->red_mask;
2624 green_mask = visual->green_mask;
2625 blue_mask = visual->blue_mask;
2626 red_shift = 0;
2627 green_shift = 0;
2628 blue_shift = 0;
2629 while ((0x0001 & (red_mask >> red_shift)) == 0) {
2630 red_shift++;
2631 }
2632 while ((0x0001 & (green_mask >> green_shift)) == 0) {
2633 green_shift++;
2634 }
2635 while ((0x0001 & (blue_mask >> blue_shift)) == 0) {
2636 blue_shift++;
2637 }
2638 #endif /* !__WIN32__ */
2639
2640 /*
2641 * Only UNIX requires the special case for <24bpp. It varies with 3 extra
2642 * shifts and uses RGB15. The 24+bpp version could also then be further
2643 * optimized.
2644 */
2645
2646 #if !(defined(__WIN32__) || defined(MAC_OSX_TK))
2647 if (bgImg->depth < 24) {
2648 unsigned char red_mlen, green_mlen, blue_mlen;
2649
2650 red_mlen = 8 - CountBits(red_mask >> red_shift);
2651 green_mlen = 8 - CountBits(green_mask >> green_shift);
2652 blue_mlen = 8 - CountBits(blue_mask >> blue_shift);
2653 for (y = 0; y < height; y++) {
2654 line = (y + yOffset) * iPtr->masterPtr->width;
2655 for (x = 0; x < width; x++) {
2656 masterPtr = alphaAr + ((line + x + xOffset) * 4);
2657 alpha = masterPtr[3];
2658
2659 /*
2660 * Ignore pixels that are fully transparent
2661 */
2662
2663 if (alpha) {
2664 /*
2665 * We could perhaps be more efficient than XGetPixel for
2666 * 24 and 32 bit displays, but this seems "fast enough".
2667 */
2668
2669 r = masterPtr[0];
2670 g = masterPtr[1];
2671 b = masterPtr[2];
2672 if (alpha != 255) {
2673 /*
2674 * Only blend pixels that have some transparency
2675 */
2676
2677 unsigned char ra, ga, ba;
2678
2679 pixel = XGetPixel(bgImg, x, y);
2680 ra = GetRValue(pixel) << red_mlen;
2681 ga = GetGValue(pixel) << green_mlen;
2682 ba = GetBValue(pixel) << blue_mlen;
2683 unalpha = 255 - alpha; /* Calculate once. */
2684 r = ALPHA_BLEND(ra, r, alpha, unalpha);
2685 g = ALPHA_BLEND(ga, g, alpha, unalpha);
2686 b = ALPHA_BLEND(ba, b, alpha, unalpha);
2687 }
2688 XPutPixel(bgImg, x, y, RGB15(r, g, b));
2689 }
2690 }
2691 }
2692 return;
2693 }
2694 #endif /* !__WIN32__ && !MAC_OSX_TK */
2695
2696 for (y = 0; y < height; y++) {
2697 line = (y + yOffset) * iPtr->masterPtr->width;
2698 for (x = 0; x < width; x++) {
2699 masterPtr = alphaAr + ((line + x + xOffset) * 4);
2700 alpha = masterPtr[3];
2701
2702 /*
2703 * Ignore pixels that are fully transparent
2704 */
2705
2706 if (alpha) {
2707 /*
2708 * We could perhaps be more efficient than XGetPixel for 24
2709 * and 32 bit displays, but this seems "fast enough".
2710 */
2711
2712 r = masterPtr[0];
2713 g = masterPtr[1];
2714 b = masterPtr[2];
2715 if (alpha != 255) {
2716 /*
2717 * Only blend pixels that have some transparency
2718 */
2719
2720 unsigned char ra, ga, ba;
2721
2722 pixel = XGetPixel(bgImg, x, y);
2723 ra = GetRValue(pixel);
2724 ga = GetGValue(pixel);
2725 ba = GetBValue(pixel);
2726 unalpha = 255 - alpha; /* Calculate once. */
2727 r = ALPHA_BLEND(ra, r, alpha, unalpha);
2728 g = ALPHA_BLEND(ga, g, alpha, unalpha);
2729 b = ALPHA_BLEND(ba, b, alpha, unalpha);
2730 }
2731 XPutPixel(bgImg, x, y, RGB(r, g, b));
2732 }
2733 }
2734 }
2735 #undef ALPHA_BLEND
2736 }
2737
2738 /*
2739 *----------------------------------------------------------------------
2740 *
2741 * ImgPhotoDisplay --
2742 *
2743 * This function is invoked to draw a photo image.
2744 *
2745 * Results:
2746 * None.
2747 *
2748 * Side effects:
2749 * A portion of the image gets rendered in a pixmap or window.
2750 *
2751 *----------------------------------------------------------------------
2752 */
2753
2754 static void
ImgPhotoDisplay(ClientData clientData,Display * display,Drawable drawable,int imageX,int imageY,int width,int height,int drawableX,int drawableY)2755 ImgPhotoDisplay(
2756 ClientData clientData, /* Pointer to PhotoInstance structure for
2757 * instance to be displayed. */
2758 Display *display, /* Display on which to draw image. */
2759 Drawable drawable, /* Pixmap or window in which to draw image. */
2760 int imageX, int imageY, /* Upper-left corner of region within image to
2761 * draw. */
2762 int width, int height, /* Dimensions of region within image to
2763 * draw. */
2764 int drawableX,int drawableY)/* Coordinates within drawable that correspond
2765 * to imageX and imageY. */
2766 {
2767 PhotoInstance *instancePtr = (PhotoInstance *) clientData;
2768 XVisualInfo visInfo = instancePtr->visualInfo;
2769
2770 /*
2771 * If there's no pixmap, it means that an error occurred while creating
2772 * the image instance so it can't be displayed.
2773 */
2774
2775 if (instancePtr->pixels == None) {
2776 return;
2777 }
2778
2779 if ((instancePtr->masterPtr->flags & COMPLEX_ALPHA)
2780 && visInfo.depth >= 15
2781 && (visInfo.class == DirectColor || visInfo.class == TrueColor)) {
2782 Tk_ErrorHandler handler;
2783 XImage *bgImg = NULL;
2784
2785 /*
2786 * Create an error handler to suppress the case where the input was
2787 * not properly constrained, which can cause an X error. [Bug 979239]
2788 */
2789
2790 handler = Tk_CreateErrorHandler(display, -1, -1, -1, NULL,
2791 (ClientData) NULL);
2792
2793 /*
2794 * Pull the current background from the display to blend with
2795 */
2796
2797 bgImg = XGetImage(display, drawable, drawableX, drawableY,
2798 (unsigned int)width, (unsigned int)height, AllPlanes, ZPixmap);
2799 if (bgImg == NULL) {
2800 Tk_DeleteErrorHandler(handler);
2801 /* We failed to get the image so draw without blending alpha. It's the best we can do */
2802 goto fallBack;
2803 }
2804
2805 ImgPhotoBlendComplexAlpha(bgImg, instancePtr, imageX, imageY, width,
2806 height);
2807
2808 /*
2809 * Color info is unimportant as we only do this operation for depth >=
2810 * 15.
2811 */
2812
2813 TkPutImage(NULL, 0, display, drawable, instancePtr->gc,
2814 bgImg, 0, 0, drawableX, drawableY,
2815 (unsigned int) width, (unsigned int) height);
2816 XDestroyImage(bgImg);
2817 Tk_DeleteErrorHandler(handler);
2818 } else {
2819 /*
2820 * masterPtr->region describes which parts of the image contain valid
2821 * data. We set this region as the clip mask for the gc, setting its
2822 * origin appropriately, and use it when drawing the image.
2823 */
2824
2825 fallBack:
2826 TkSetRegion(display, instancePtr->gc,
2827 instancePtr->masterPtr->validRegion);
2828 XSetClipOrigin(display, instancePtr->gc, drawableX - imageX,
2829 drawableY - imageY);
2830 XCopyArea(display, instancePtr->pixels, drawable, instancePtr->gc,
2831 imageX, imageY, (unsigned) width, (unsigned) height,
2832 drawableX, drawableY);
2833 XSetClipMask(display, instancePtr->gc, None);
2834 XSetClipOrigin(display, instancePtr->gc, 0, 0);
2835 }
2836 XFlush(display);
2837 }
2838
2839 /*
2840 *----------------------------------------------------------------------
2841 *
2842 * ImgPhotoFree --
2843 *
2844 * This function is called when a widget ceases to use a particular
2845 * instance of an image. We don't actually get rid of the instance until
2846 * later because we may be about to get this instance again.
2847 *
2848 * Results:
2849 * None.
2850 *
2851 * Side effects:
2852 * Internal data structures get cleaned up, later.
2853 *
2854 *----------------------------------------------------------------------
2855 */
2856
2857 static void
ImgPhotoFree(ClientData clientData,Display * display)2858 ImgPhotoFree(
2859 ClientData clientData, /* Pointer to PhotoInstance structure for
2860 * instance to be displayed. */
2861 Display *display) /* Display containing window that used
2862 * image. */
2863 {
2864 PhotoInstance *instancePtr = (PhotoInstance *) clientData;
2865 ColorTable *colorPtr;
2866
2867 instancePtr->refCount -= 1;
2868 if (instancePtr->refCount > 0) {
2869 return;
2870 }
2871
2872 /*
2873 * There are no more uses of the image within this widget. Decrement the
2874 * count of live uses of its color table, so that its colors can be
2875 * reclaimed if necessary, and set up an idle call to free the instance
2876 * structure.
2877 */
2878
2879 colorPtr = instancePtr->colorTablePtr;
2880 if (colorPtr != NULL) {
2881 colorPtr->liveRefCount -= 1;
2882 }
2883
2884 Tcl_DoWhenIdle(DisposeInstance, (ClientData) instancePtr);
2885 }
2886
2887 /*
2888 *----------------------------------------------------------------------
2889 *
2890 * ImgPhotoDelete --
2891 *
2892 * This function is called by the image code to delete the master
2893 * structure for an image.
2894 *
2895 * Results:
2896 * None.
2897 *
2898 * Side effects:
2899 * Resources associated with the image get freed.
2900 *
2901 *----------------------------------------------------------------------
2902 */
2903
2904 static void
ImgPhotoDelete(ClientData masterData)2905 ImgPhotoDelete(
2906 ClientData masterData) /* Pointer to PhotoMaster structure for image.
2907 * Must not have any more instances. */
2908 {
2909 PhotoMaster *masterPtr = (PhotoMaster *) masterData;
2910 PhotoInstance *instancePtr;
2911
2912 while ((instancePtr = masterPtr->instancePtr) != NULL) {
2913 if (instancePtr->refCount > 0) {
2914 Tcl_Panic("tried to delete photo image when instances still exist");
2915 }
2916 Tcl_CancelIdleCall(DisposeInstance, (ClientData) instancePtr);
2917 DisposeInstance((ClientData) instancePtr);
2918 }
2919 masterPtr->tkMaster = NULL;
2920 if (masterPtr->imageCmd != NULL) {
2921 Tcl_DeleteCommandFromToken(masterPtr->interp, masterPtr->imageCmd);
2922 }
2923 if (masterPtr->pix32 != NULL) {
2924 ckfree((char *) masterPtr->pix32);
2925 }
2926 if (masterPtr->validRegion != NULL) {
2927 TkDestroyRegion(masterPtr->validRegion);
2928 }
2929 if (masterPtr->dataString != NULL) {
2930 Tcl_DecrRefCount(masterPtr->dataString);
2931 }
2932 if (masterPtr->format != NULL) {
2933 Tcl_DecrRefCount(masterPtr->format);
2934 }
2935 Tk_FreeOptions(configSpecs, (char *) masterPtr, NULL, 0);
2936 ckfree((char *) masterPtr);
2937 }
2938
2939 /*
2940 *----------------------------------------------------------------------
2941 *
2942 * ImgPhotoCmdDeletedProc --
2943 *
2944 * This function is invoked when the image command for an image is
2945 * deleted. It deletes the image.
2946 *
2947 * Results:
2948 * None.
2949 *
2950 * Side effects:
2951 * The image is deleted.
2952 *
2953 *----------------------------------------------------------------------
2954 */
2955
2956 static void
ImgPhotoCmdDeletedProc(ClientData clientData)2957 ImgPhotoCmdDeletedProc(
2958 ClientData clientData) /* Pointer to PhotoMaster structure for
2959 * image. */
2960 {
2961 PhotoMaster *masterPtr = (PhotoMaster *) clientData;
2962
2963 masterPtr->imageCmd = NULL;
2964 if (masterPtr->tkMaster != NULL) {
2965 Tk_DeleteImage(masterPtr->interp, Tk_NameOfImage(masterPtr->tkMaster));
2966 }
2967 }
2968
2969 /*
2970 *----------------------------------------------------------------------
2971 *
2972 * ImgPhotoSetSize --
2973 *
2974 * This function reallocates the image storage and instance pixmaps for a
2975 * photo image, as necessary, to change the image's size to `width' x
2976 * `height' pixels.
2977 *
2978 * Results:
2979 * TCL_OK if successful, TCL_ERROR if failure occurred (currently just
2980 * with memory allocation.)
2981 *
2982 * Side effects:
2983 * Storage gets reallocated, for the master and all its instances.
2984 *
2985 *----------------------------------------------------------------------
2986 */
2987
2988 static int
ImgPhotoSetSize(PhotoMaster * masterPtr,int width,int height)2989 ImgPhotoSetSize(
2990 PhotoMaster *masterPtr,
2991 int width, int height)
2992 {
2993 unsigned char *newPix32 = NULL;
2994 int h, offset, pitch;
2995 unsigned char *srcPtr, *destPtr;
2996 XRectangle validBox, clipBox;
2997 TkRegion clipRegion;
2998 PhotoInstance *instancePtr;
2999
3000 if (masterPtr->userWidth > 0) {
3001 width = masterPtr->userWidth;
3002 }
3003 if (masterPtr->userHeight > 0) {
3004 height = masterPtr->userHeight;
3005 }
3006
3007 pitch = width * 4;
3008
3009 /*
3010 * Test if we're going to (re)allocate the main buffer now, so that any
3011 * failures will leave the photo unchanged.
3012 */
3013
3014 if ((width != masterPtr->width) || (height != masterPtr->height)
3015 || (masterPtr->pix32 == NULL)) {
3016 /*
3017 * Not a u-long, but should be one.
3018 */
3019
3020 unsigned /*long*/ newPixSize = (unsigned /*long*/) (height * pitch);
3021
3022 /*
3023 * Some mallocs() really hate allocating zero bytes. [Bug 619544]
3024 */
3025
3026 if (newPixSize == 0) {
3027 newPix32 = NULL;
3028 } else {
3029 newPix32 = (unsigned char *) attemptckalloc(newPixSize);
3030 if (newPix32 == NULL) {
3031 return TCL_ERROR;
3032 }
3033 }
3034 }
3035
3036 /*
3037 * We have to trim the valid region if it is currently larger than the new
3038 * image size.
3039 */
3040
3041 TkClipBox(masterPtr->validRegion, &validBox);
3042 if ((validBox.x + validBox.width > width)
3043 || (validBox.y + validBox.height > height)) {
3044 clipBox.x = 0;
3045 clipBox.y = 0;
3046 clipBox.width = width;
3047 clipBox.height = height;
3048 clipRegion = TkCreateRegion();
3049 TkUnionRectWithRegion(&clipBox, clipRegion, clipRegion);
3050 TkIntersectRegion(masterPtr->validRegion, clipRegion,
3051 masterPtr->validRegion);
3052 TkDestroyRegion(clipRegion);
3053 TkClipBox(masterPtr->validRegion, &validBox);
3054 }
3055
3056 /*
3057 * Use the reallocated storage (allocation above) for the 32-bit image and
3058 * copy over valid regions. Note that this test is true precisely when the
3059 * allocation has already been done.
3060 */
3061
3062 if (newPix32 != NULL) {
3063 /*
3064 * Zero the new array. The dithering code shouldn't read the areas
3065 * outside validBox, but they might be copied to another photo image
3066 * or written to a file.
3067 */
3068
3069 if ((masterPtr->pix32 != NULL)
3070 && ((width == masterPtr->width) || (width == validBox.width))) {
3071 if (validBox.y > 0) {
3072 memset(newPix32, 0, (size_t) (validBox.y * pitch));
3073 }
3074 h = validBox.y + validBox.height;
3075 if (h < height) {
3076 memset(newPix32 + h*pitch, 0, (size_t) ((height - h) * pitch));
3077 }
3078 } else {
3079 memset(newPix32, 0, (size_t) (height * pitch));
3080 }
3081
3082 if (masterPtr->pix32 != NULL) {
3083 /*
3084 * Copy the common area over to the new array array and free the
3085 * old array.
3086 */
3087
3088 if (width == masterPtr->width) {
3089
3090 /*
3091 * The region to be copied is contiguous.
3092 */
3093
3094 offset = validBox.y * pitch;
3095 memcpy(newPix32 + offset, masterPtr->pix32 + offset,
3096 (size_t) (validBox.height * pitch));
3097
3098 } else if ((validBox.width > 0) && (validBox.height > 0)) {
3099 /*
3100 * Area to be copied is not contiguous - copy line by line.
3101 */
3102
3103 destPtr = newPix32 + (validBox.y * width + validBox.x) * 4;
3104 srcPtr = masterPtr->pix32 + (validBox.y * masterPtr->width
3105 + validBox.x) * 4;
3106 for (h = validBox.height; h > 0; h--) {
3107 memcpy(destPtr, srcPtr, (size_t) (validBox.width * 4));
3108 destPtr += width * 4;
3109 srcPtr += masterPtr->width * 4;
3110 }
3111 }
3112
3113 ckfree((char *) masterPtr->pix32);
3114 }
3115
3116 masterPtr->pix32 = newPix32;
3117 masterPtr->width = width;
3118 masterPtr->height = height;
3119
3120 /*
3121 * Dithering will be correct up to the end of the last pre-existing
3122 * complete scanline.
3123 */
3124
3125 if ((validBox.x > 0) || (validBox.y > 0)) {
3126 masterPtr->ditherX = 0;
3127 masterPtr->ditherY = 0;
3128 } else if (validBox.width == width) {
3129 if ((int) validBox.height < masterPtr->ditherY) {
3130 masterPtr->ditherX = 0;
3131 masterPtr->ditherY = validBox.height;
3132 }
3133 } else if ((masterPtr->ditherY > 0)
3134 || ((int) validBox.width < masterPtr->ditherX)) {
3135 masterPtr->ditherX = validBox.width;
3136 masterPtr->ditherY = 0;
3137 }
3138 }
3139
3140 ToggleComplexAlphaIfNeeded(masterPtr);
3141
3142 /*
3143 * Now adjust the sizes of the pixmaps for all of the instances.
3144 */
3145
3146 for (instancePtr = masterPtr->instancePtr; instancePtr != NULL;
3147 instancePtr = instancePtr->nextPtr) {
3148 ImgPhotoInstanceSetSize(instancePtr);
3149 }
3150
3151 return TCL_OK;
3152 }
3153
3154 /*
3155 *----------------------------------------------------------------------
3156 *
3157 * ImgPhotoInstanceSetSize --
3158 *
3159 * This function reallocates the instance pixmap and dithering error
3160 * array for a photo instance, as necessary, to change the image's size
3161 * to `width' x `height' pixels.
3162 *
3163 * Results:
3164 * None.
3165 *
3166 * Side effects:
3167 * Storage gets reallocated, here and in the X server.
3168 *
3169 *----------------------------------------------------------------------
3170 */
3171
3172 static void
ImgPhotoInstanceSetSize(PhotoInstance * instancePtr)3173 ImgPhotoInstanceSetSize(
3174 PhotoInstance *instancePtr) /* Instance whose size is to be changed. */
3175 {
3176 PhotoMaster *masterPtr;
3177 schar *newError, *errSrcPtr, *errDestPtr;
3178 int h, offset;
3179 XRectangle validBox;
3180 Pixmap newPixmap;
3181
3182 masterPtr = instancePtr->masterPtr;
3183 TkClipBox(masterPtr->validRegion, &validBox);
3184
3185 if ((instancePtr->width != masterPtr->width)
3186 || (instancePtr->height != masterPtr->height)
3187 || (instancePtr->pixels == None)) {
3188 newPixmap = Tk_GetPixmap(instancePtr->display,
3189 RootWindow(instancePtr->display,
3190 instancePtr->visualInfo.screen),
3191 (masterPtr->width > 0) ? masterPtr->width: 1,
3192 (masterPtr->height > 0) ? masterPtr->height: 1,
3193 instancePtr->visualInfo.depth);
3194 if (!newPixmap) {
3195 Tcl_Panic("Fail to create pixmap with Tk_GetPixmap in ImgPhotoInstanceSetSize.\n");
3196 }
3197
3198 /*
3199 * The following is a gross hack needed to properly support colormaps
3200 * under Windows. Before the pixels can be copied to the pixmap, the
3201 * relevent colormap must be associated with the drawable. Normally we
3202 * can infer this association from the window that was used to create
3203 * the pixmap. However, in this case we're using the root window, so
3204 * we have to be more explicit.
3205 */
3206
3207 TkSetPixmapColormap(newPixmap, instancePtr->colormap);
3208
3209 if (instancePtr->pixels != None) {
3210 /*
3211 * Copy any common pixels from the old pixmap and free it.
3212 */
3213
3214 XCopyArea(instancePtr->display, instancePtr->pixels, newPixmap,
3215 instancePtr->gc, validBox.x, validBox.y,
3216 validBox.width, validBox.height, validBox.x, validBox.y);
3217 Tk_FreePixmap(instancePtr->display, instancePtr->pixels);
3218 }
3219 instancePtr->pixels = newPixmap;
3220 }
3221
3222 if ((instancePtr->width != masterPtr->width)
3223 || (instancePtr->height != masterPtr->height)
3224 || (instancePtr->error == NULL)) {
3225
3226 if (masterPtr->height > 0 && masterPtr->width > 0) {
3227 newError = (schar *) ckalloc((unsigned)
3228 masterPtr->height * masterPtr->width * 3 * sizeof(schar));
3229
3230 /*
3231 * Zero the new array so that we don't get bogus error values
3232 * propagating into areas we dither later.
3233 */
3234
3235 if ((instancePtr->error != NULL)
3236 && ((instancePtr->width == masterPtr->width)
3237 || (validBox.width == masterPtr->width))) {
3238 if (validBox.y > 0) {
3239 memset(newError, 0, (size_t)
3240 validBox.y * masterPtr->width * 3 * sizeof(schar));
3241 }
3242 h = validBox.y + validBox.height;
3243 if (h < masterPtr->height) {
3244 memset(newError + h*masterPtr->width*3, 0,
3245 (size_t) (masterPtr->height - h)
3246 * masterPtr->width * 3 * sizeof(schar));
3247 }
3248 } else {
3249 memset(newError, 0, (size_t)
3250 masterPtr->height * masterPtr->width *3*sizeof(schar));
3251 }
3252 } else {
3253 newError = NULL;
3254 }
3255
3256 if (instancePtr->error != NULL) {
3257 /*
3258 * Copy the common area over to the new array and free the old
3259 * array.
3260 */
3261
3262 if (masterPtr->width == instancePtr->width) {
3263 offset = validBox.y * masterPtr->width * 3;
3264 memcpy(newError + offset, instancePtr->error + offset,
3265 (size_t) (validBox.height
3266 * masterPtr->width * 3 * sizeof(schar)));
3267
3268 } else if (validBox.width > 0 && validBox.height > 0) {
3269 errDestPtr = newError +
3270 (validBox.y * masterPtr->width + validBox.x) * 3;
3271 errSrcPtr = instancePtr->error +
3272 (validBox.y * instancePtr->width + validBox.x) * 3;
3273
3274 for (h = validBox.height; h > 0; --h) {
3275 memcpy(errDestPtr, errSrcPtr,
3276 validBox.width * 3 * sizeof(schar));
3277 errDestPtr += masterPtr->width * 3;
3278 errSrcPtr += instancePtr->width * 3;
3279 }
3280 }
3281 ckfree((char *) instancePtr->error);
3282 }
3283
3284 instancePtr->error = newError;
3285 }
3286
3287 instancePtr->width = masterPtr->width;
3288 instancePtr->height = masterPtr->height;
3289 }
3290
3291 /*
3292 *----------------------------------------------------------------------
3293 *
3294 * IsValidPalette --
3295 *
3296 * This function is called to check whether a value given for the
3297 * -palette option is valid for a particular instance of a photo image.
3298 *
3299 * Results:
3300 * A boolean value: 1 if the palette is acceptable, 0 otherwise.
3301 *
3302 * Side effects:
3303 * None.
3304 *
3305 *----------------------------------------------------------------------
3306 */
3307
3308 static int
IsValidPalette(PhotoInstance * instancePtr,const char * palette)3309 IsValidPalette(
3310 PhotoInstance *instancePtr, /* Instance to which the palette specification
3311 * is to be applied. */
3312 const char *palette) /* Palette specification string. */
3313 {
3314 int nRed, nGreen, nBlue, mono, numColors;
3315 char *endp;
3316
3317 /*
3318 * First parse the specification: it must be of the form %d or %d/%d/%d.
3319 */
3320
3321 nRed = strtol(palette, &endp, 10);
3322 if ((endp == palette) || ((*endp != 0) && (*endp != '/'))
3323 || (nRed < 2) || (nRed > 256)) {
3324 return 0;
3325 }
3326
3327 if (*endp == 0) {
3328 mono = 1;
3329 nGreen = nBlue = nRed;
3330 } else {
3331 palette = endp + 1;
3332 nGreen = strtol(palette, &endp, 10);
3333 if ((endp == palette) || (*endp != '/') || (nGreen < 2)
3334 || (nGreen > 256)) {
3335 return 0;
3336 }
3337 palette = endp + 1;
3338 nBlue = strtol(palette, &endp, 10);
3339 if ((endp == palette) || (*endp != 0) || (nBlue < 2)
3340 || (nBlue > 256)) {
3341 return 0;
3342 }
3343 mono = 0;
3344 }
3345
3346 switch (instancePtr->visualInfo.class) {
3347 case DirectColor:
3348 case TrueColor:
3349 if ((nRed > (1 << CountBits(instancePtr->visualInfo.red_mask)))
3350 || (nGreen>(1<<CountBits(instancePtr->visualInfo.green_mask)))
3351 || (nBlue>(1<<CountBits(instancePtr->visualInfo.blue_mask)))) {
3352 return 0;
3353 }
3354 break;
3355 case PseudoColor:
3356 case StaticColor:
3357 numColors = nRed;
3358 if (!mono) {
3359 numColors *= nGreen*nBlue;
3360 }
3361 if (numColors > (1 << instancePtr->visualInfo.depth)) {
3362 return 0;
3363 }
3364 break;
3365 case GrayScale:
3366 case StaticGray:
3367 if (!mono || (nRed > (1 << instancePtr->visualInfo.depth))) {
3368 return 0;
3369 }
3370 break;
3371 }
3372
3373 return 1;
3374 }
3375
3376 /*
3377 *----------------------------------------------------------------------
3378 *
3379 * CountBits --
3380 *
3381 * This function counts how many bits are set to 1 in `mask'.
3382 *
3383 * Results:
3384 * The integer number of bits.
3385 *
3386 * Side effects:
3387 * None.
3388 *
3389 *----------------------------------------------------------------------
3390 */
3391
3392 static int
CountBits(pixel mask)3393 CountBits(
3394 pixel mask) /* Value to count the 1 bits in. */
3395 {
3396 int n;
3397
3398 for (n=0 ; mask!=0 ; mask&=mask-1) {
3399 n++;
3400 }
3401 return n;
3402 }
3403
3404 /*
3405 *----------------------------------------------------------------------
3406 *
3407 * GetColorTable --
3408 *
3409 * This function is called to allocate a table of colormap information
3410 * for an instance of a photo image. Only one such table is allocated for
3411 * all photo instances using the same display, colormap, palette and
3412 * gamma values, so that the application need only request a set of
3413 * colors from the X server once for all such photo widgets. This
3414 * function maintains a hash table to find previously-allocated
3415 * ColorTables.
3416 *
3417 * Results:
3418 * None.
3419 *
3420 * Side effects:
3421 * A new ColorTable may be allocated and placed in the hash table, and
3422 * have colors allocated for it.
3423 *
3424 *----------------------------------------------------------------------
3425 */
3426
3427 static void
GetColorTable(PhotoInstance * instancePtr)3428 GetColorTable(
3429 PhotoInstance *instancePtr) /* Instance needing a color table. */
3430 {
3431 ColorTable *colorPtr;
3432 Tcl_HashEntry *entry;
3433 ColorTableId id;
3434 int isNew;
3435
3436 /*
3437 * Look for an existing ColorTable in the hash table.
3438 */
3439
3440 memset(&id, 0, sizeof(id));
3441 id.display = instancePtr->display;
3442 id.colormap = instancePtr->colormap;
3443 id.palette = instancePtr->palette;
3444 id.gamma = instancePtr->gamma;
3445 if (!imgPhotoColorHashInitialized) {
3446 Tcl_InitHashTable(&imgPhotoColorHash, N_COLOR_HASH);
3447 imgPhotoColorHashInitialized = 1;
3448 }
3449 entry = Tcl_CreateHashEntry(&imgPhotoColorHash, (char *) &id, &isNew);
3450
3451 if (!isNew) {
3452 /*
3453 * Re-use the existing entry.
3454 */
3455
3456 colorPtr = (ColorTable *) Tcl_GetHashValue(entry);
3457 } else {
3458 /*
3459 * No color table currently available; need to make one.
3460 */
3461
3462 colorPtr = (ColorTable *) ckalloc(sizeof(ColorTable));
3463
3464 /*
3465 * The following line of code should not normally be needed due to the
3466 * assignment in the following line. However, it compensates for bugs
3467 * in some compilers (HP, for example) where sizeof(ColorTable) is 24
3468 * but the assignment only copies 20 bytes, leaving 4 bytes
3469 * uninitialized; these cause problems when using the id for lookups
3470 * in imgPhotoColorHash, and can result in core dumps.
3471 */
3472
3473 memset(&colorPtr->id, 0, sizeof(ColorTableId));
3474 colorPtr->id = id;
3475 Tk_PreserveColormap(colorPtr->id.display, colorPtr->id.colormap);
3476 colorPtr->flags = 0;
3477 colorPtr->refCount = 0;
3478 colorPtr->liveRefCount = 0;
3479 colorPtr->numColors = 0;
3480 colorPtr->visualInfo = instancePtr->visualInfo;
3481 colorPtr->pixelMap = NULL;
3482 Tcl_SetHashValue(entry, colorPtr);
3483 }
3484
3485 colorPtr->refCount++;
3486 colorPtr->liveRefCount++;
3487 instancePtr->colorTablePtr = colorPtr;
3488 if (colorPtr->flags & DISPOSE_PENDING) {
3489 Tcl_CancelIdleCall(DisposeColorTable, (ClientData) colorPtr);
3490 colorPtr->flags &= ~DISPOSE_PENDING;
3491 }
3492
3493 /*
3494 * Allocate colors for this color table if necessary.
3495 */
3496
3497 if ((colorPtr->numColors == 0)
3498 && ((colorPtr->flags & BLACK_AND_WHITE) == 0)) {
3499 AllocateColors(colorPtr);
3500 }
3501 }
3502
3503 /*
3504 *----------------------------------------------------------------------
3505 *
3506 * FreeColorTable --
3507 *
3508 * This function is called when an instance ceases using a color table.
3509 *
3510 * Results:
3511 * None.
3512 *
3513 * Side effects:
3514 * If no other instances are using this color table, a when-idle handler
3515 * is registered to free up the color table and the colors allocated for
3516 * it.
3517 *
3518 *----------------------------------------------------------------------
3519 */
3520
3521 static void
FreeColorTable(ColorTable * colorPtr,int force)3522 FreeColorTable(
3523 ColorTable *colorPtr, /* Pointer to the color table which is no
3524 * longer required by an instance. */
3525 int force) /* Force free to happen immediately. */
3526 {
3527 colorPtr->refCount--;
3528 if (colorPtr->refCount > 0) {
3529 return;
3530 }
3531
3532 if (force) {
3533 if ((colorPtr->flags & DISPOSE_PENDING) != 0) {
3534 Tcl_CancelIdleCall(DisposeColorTable, (ClientData) colorPtr);
3535 colorPtr->flags &= ~DISPOSE_PENDING;
3536 }
3537 DisposeColorTable((ClientData) colorPtr);
3538 } else if ((colorPtr->flags & DISPOSE_PENDING) == 0) {
3539 Tcl_DoWhenIdle(DisposeColorTable, (ClientData) colorPtr);
3540 colorPtr->flags |= DISPOSE_PENDING;
3541 }
3542 }
3543
3544 /*
3545 *----------------------------------------------------------------------
3546 *
3547 * AllocateColors --
3548 *
3549 * This function allocates the colors required by a color table, and sets
3550 * up the fields in the color table data structure which are used in
3551 * dithering.
3552 *
3553 * Results:
3554 * None.
3555 *
3556 * Side effects:
3557 * Colors are allocated from the X server. Fields in the color table data
3558 * structure are updated.
3559 *
3560 *----------------------------------------------------------------------
3561 */
3562
3563 static void
AllocateColors(ColorTable * colorPtr)3564 AllocateColors(
3565 ColorTable *colorPtr) /* Pointer to the color table requiring colors
3566 * to be allocated. */
3567 {
3568 int i, r, g, b, rMult, mono;
3569 int numColors, nRed, nGreen, nBlue;
3570 double fr, fg, fb, igam;
3571 XColor *colors;
3572 unsigned long *pixels;
3573
3574 /*
3575 * 16-bit intensity value for i/n of full intensity.
3576 */
3577 #define CFRAC(i, n) ((i) * 65535 / (n))
3578
3579 /* As for CFRAC, but apply exponent of g. */
3580 #define CGFRAC(i, n, g) ((int)(65535 * pow((double)(i) / (n), (g))))
3581
3582 /*
3583 * First parse the palette specification to get the required number of
3584 * shades of each primary.
3585 */
3586
3587 mono = sscanf(colorPtr->id.palette, "%d/%d/%d", &nRed, &nGreen, &nBlue)
3588 <= 1;
3589 igam = 1.0 / colorPtr->id.gamma;
3590
3591 /*
3592 * Each time around this loop, we reduce the number of colors we're trying
3593 * to allocate until we succeed in allocating all of the colors we need.
3594 */
3595
3596 for (;;) {
3597 /*
3598 * If we are using 1 bit/pixel, we don't need to allocate any colors
3599 * (we just use the foreground and background colors in the GC).
3600 */
3601
3602 if (mono && (nRed <= 2)) {
3603 colorPtr->flags |= BLACK_AND_WHITE;
3604 return;
3605 }
3606
3607 /*
3608 * Calculate the RGB coordinates of the colors we want to allocate and
3609 * store them in *colors.
3610 */
3611
3612 if ((colorPtr->visualInfo.class == DirectColor)
3613 || (colorPtr->visualInfo.class == TrueColor)) {
3614
3615 /*
3616 * Direct/True Color: allocate shades of red, green, blue
3617 * independently.
3618 */
3619
3620 if (mono) {
3621 numColors = nGreen = nBlue = nRed;
3622 } else {
3623 numColors = MAX(MAX(nRed, nGreen), nBlue);
3624 }
3625 colors = (XColor *) ckalloc(numColors * sizeof(XColor));
3626
3627 for (i = 0; i < numColors; ++i) {
3628 if (igam == 1.0) {
3629 colors[i].red = CFRAC(i, nRed - 1);
3630 colors[i].green = CFRAC(i, nGreen - 1);
3631 colors[i].blue = CFRAC(i, nBlue - 1);
3632 } else {
3633 colors[i].red = CGFRAC(i, nRed - 1, igam);
3634 colors[i].green = CGFRAC(i, nGreen - 1, igam);
3635 colors[i].blue = CGFRAC(i, nBlue - 1, igam);
3636 }
3637 }
3638 } else {
3639 /*
3640 * PseudoColor, StaticColor, GrayScale or StaticGray visual: we
3641 * have to allocate each color in the color cube separately.
3642 */
3643
3644 numColors = (mono) ? nRed: (nRed * nGreen * nBlue);
3645 colors = (XColor *) ckalloc(numColors * sizeof(XColor));
3646
3647 if (!mono) {
3648 /*
3649 * Color display using a PseudoColor or StaticColor visual.
3650 */
3651
3652 i = 0;
3653 for (r = 0; r < nRed; ++r) {
3654 for (g = 0; g < nGreen; ++g) {
3655 for (b = 0; b < nBlue; ++b) {
3656 if (igam == 1.0) {
3657 colors[i].red = CFRAC(r, nRed - 1);
3658 colors[i].green = CFRAC(g, nGreen - 1);
3659 colors[i].blue = CFRAC(b, nBlue - 1);
3660 } else {
3661 colors[i].red = CGFRAC(r, nRed - 1, igam);
3662 colors[i].green = CGFRAC(g, nGreen - 1, igam);
3663 colors[i].blue = CGFRAC(b, nBlue - 1, igam);
3664 }
3665 i++;
3666 }
3667 }
3668 }
3669 } else {
3670 /*
3671 * Monochrome display - allocate the shades of grey we want.
3672 */
3673
3674 for (i = 0; i < numColors; ++i) {
3675 if (igam == 1.0) {
3676 r = CFRAC(i, numColors - 1);
3677 } else {
3678 r = CGFRAC(i, numColors - 1, igam);
3679 }
3680 colors[i].red = colors[i].green = colors[i].blue = r;
3681 }
3682 }
3683 }
3684
3685 /*
3686 * Now try to allocate the colors we've calculated.
3687 */
3688
3689 pixels = (unsigned long *) ckalloc(numColors * sizeof(unsigned long));
3690 for (i = 0; i < numColors; ++i) {
3691 if (!XAllocColor(colorPtr->id.display, colorPtr->id.colormap,
3692 &colors[i])) {
3693 /*
3694 * Can't get all the colors we want in the default colormap;
3695 * first try freeing colors from other unused color tables.
3696 */
3697
3698 if (!ReclaimColors(&colorPtr->id, numColors - i)
3699 || !XAllocColor(colorPtr->id.display,
3700 colorPtr->id.colormap, &colors[i])) {
3701 /*
3702 * Still can't allocate the color.
3703 */
3704
3705 break;
3706 }
3707 }
3708 pixels[i] = colors[i].pixel;
3709 }
3710
3711 /*
3712 * If we didn't get all of the colors, reduce the resolution of the
3713 * color cube, free the ones we got, and try again.
3714 */
3715
3716 if (i >= numColors) {
3717 break;
3718 }
3719 XFreeColors(colorPtr->id.display, colorPtr->id.colormap, pixels, i, 0);
3720 ckfree((char *) colors);
3721 ckfree((char *) pixels);
3722
3723 if (!mono) {
3724 if ((nRed == 2) && (nGreen == 2) && (nBlue == 2)) {
3725 /*
3726 * Fall back to 1-bit monochrome display.
3727 */
3728
3729 mono = 1;
3730 } else {
3731 /*
3732 * Reduce the number of shades of each primary to about 3/4 of
3733 * the previous value. This should reduce the total number of
3734 * colors required to about half the previous value for
3735 * PseudoColor displays.
3736 */
3737
3738 nRed = (nRed * 3 + 2) / 4;
3739 nGreen = (nGreen * 3 + 2) / 4;
3740 nBlue = (nBlue * 3 + 2) / 4;
3741 }
3742 } else {
3743 /*
3744 * Reduce the number of shades of gray to about 1/2.
3745 */
3746
3747 nRed = nRed / 2;
3748 }
3749 }
3750
3751 /*
3752 * We have allocated all of the necessary colors: fill in various fields
3753 * of the ColorTable record.
3754 */
3755
3756 if (!mono) {
3757 colorPtr->flags |= COLOR_WINDOW;
3758
3759 /*
3760 * The following is a hairy hack. We only want to index into the
3761 * pixelMap on colormap displays. However, if the display is on
3762 * Windows, then we actually want to store the index not the value
3763 * since we will be passing the color table into the TkPutImage call.
3764 */
3765
3766 #ifndef __WIN32__
3767 if ((colorPtr->visualInfo.class != DirectColor)
3768 && (colorPtr->visualInfo.class != TrueColor)) {
3769 colorPtr->flags |= MAP_COLORS;
3770 }
3771 #endif /* __WIN32__ */
3772 }
3773
3774 colorPtr->numColors = numColors;
3775 colorPtr->pixelMap = pixels;
3776
3777 /*
3778 * Set up quantization tables for dithering.
3779 */
3780
3781 rMult = nGreen * nBlue;
3782 for (i = 0; i < 256; ++i) {
3783 r = (i * (nRed - 1) + 127) / 255;
3784 if (mono) {
3785 fr = (double) colors[r].red / 65535.0;
3786 if (colorPtr->id.gamma != 1.0 ) {
3787 fr = pow(fr, colorPtr->id.gamma);
3788 }
3789 colorPtr->colorQuant[0][i] = (int)(fr * 255.99);
3790 colorPtr->redValues[i] = colors[r].pixel;
3791 } else {
3792 g = (i * (nGreen - 1) + 127) / 255;
3793 b = (i * (nBlue - 1) + 127) / 255;
3794 if ((colorPtr->visualInfo.class == DirectColor)
3795 || (colorPtr->visualInfo.class == TrueColor)) {
3796 colorPtr->redValues[i] =
3797 colors[r].pixel & colorPtr->visualInfo.red_mask;
3798 colorPtr->greenValues[i] =
3799 colors[g].pixel & colorPtr->visualInfo.green_mask;
3800 colorPtr->blueValues[i] =
3801 colors[b].pixel & colorPtr->visualInfo.blue_mask;
3802 } else {
3803 r *= rMult;
3804 g *= nBlue;
3805 colorPtr->redValues[i] = r;
3806 colorPtr->greenValues[i] = g;
3807 colorPtr->blueValues[i] = b;
3808 }
3809 fr = (double) colors[r].red / 65535.0;
3810 fg = (double) colors[g].green / 65535.0;
3811 fb = (double) colors[b].blue / 65535.0;
3812 if (colorPtr->id.gamma != 1.0) {
3813 fr = pow(fr, colorPtr->id.gamma);
3814 fg = pow(fg, colorPtr->id.gamma);
3815 fb = pow(fb, colorPtr->id.gamma);
3816 }
3817 colorPtr->colorQuant[0][i] = (int)(fr * 255.99);
3818 colorPtr->colorQuant[1][i] = (int)(fg * 255.99);
3819 colorPtr->colorQuant[2][i] = (int)(fb * 255.99);
3820 }
3821 }
3822
3823 ckfree((char *) colors);
3824 }
3825
3826 /*
3827 *----------------------------------------------------------------------
3828 *
3829 * DisposeColorTable --
3830 *
3831 * Release a color table and its associated resources.
3832 *
3833 * Results:
3834 * None.
3835 *
3836 * Side effects:
3837 * The colors in the argument color table are freed, as is the color
3838 * table structure itself. The color table is removed from the hash table
3839 * which is used to locate color tables.
3840 *
3841 *----------------------------------------------------------------------
3842 */
3843
3844 static void
DisposeColorTable(ClientData clientData)3845 DisposeColorTable(
3846 ClientData clientData) /* Pointer to the ColorTable whose
3847 * colors are to be released. */
3848 {
3849 ColorTable *colorPtr = (ColorTable *) clientData;
3850 Tcl_HashEntry *entry;
3851
3852 if (colorPtr->pixelMap != NULL) {
3853 if (colorPtr->numColors > 0) {
3854 XFreeColors(colorPtr->id.display, colorPtr->id.colormap,
3855 colorPtr->pixelMap, colorPtr->numColors, 0);
3856 Tk_FreeColormap(colorPtr->id.display, colorPtr->id.colormap);
3857 }
3858 ckfree((char *) colorPtr->pixelMap);
3859 }
3860
3861 entry = Tcl_FindHashEntry(&imgPhotoColorHash, (char *) &colorPtr->id);
3862 if (entry == NULL) {
3863 Tcl_Panic("DisposeColorTable couldn't find hash entry");
3864 }
3865 Tcl_DeleteHashEntry(entry);
3866
3867 ckfree((char *) colorPtr);
3868 }
3869
3870 /*
3871 *----------------------------------------------------------------------
3872 *
3873 * ReclaimColors --
3874 *
3875 * This function is called to try to free up colors in the colormap used
3876 * by a color table. It looks for other color tables with the same
3877 * colormap and with a zero live reference count, and frees their colors.
3878 * It only does so if there is the possibility of freeing up at least
3879 * `numColors' colors.
3880 *
3881 * Results:
3882 * The return value is TRUE if any colors were freed, FALSE otherwise.
3883 *
3884 * Side effects:
3885 * ColorTables which are not currently in use may lose their color
3886 * allocations.
3887 *
3888 *----------------------------------------------------------------------
3889 */
3890
3891 static int
ReclaimColors(ColorTableId * id,int numColors)3892 ReclaimColors(
3893 ColorTableId *id, /* Pointer to information identifying
3894 * the color table which needs more colors. */
3895 int numColors) /* Number of colors required. */
3896 {
3897 Tcl_HashSearch srch;
3898 Tcl_HashEntry *entry;
3899 ColorTable *colorPtr;
3900 int nAvail = 0;
3901
3902 /*
3903 * First scan through the color hash table to get an upper bound on how
3904 * many colors we might be able to free.
3905 */
3906
3907 entry = Tcl_FirstHashEntry(&imgPhotoColorHash, &srch);
3908 while (entry != NULL) {
3909 colorPtr = (ColorTable *) Tcl_GetHashValue(entry);
3910 if ((colorPtr->id.display == id->display)
3911 && (colorPtr->id.colormap == id->colormap)
3912 && (colorPtr->liveRefCount == 0 )&& (colorPtr->numColors != 0)
3913 && ((colorPtr->id.palette != id->palette)
3914 || (colorPtr->id.gamma != id->gamma))) {
3915 /*
3916 * We could take this guy's colors off him.
3917 */
3918
3919 nAvail += colorPtr->numColors;
3920 }
3921 entry = Tcl_NextHashEntry(&srch);
3922 }
3923
3924 /*
3925 * nAvail is an (over)estimate of the number of colors we could free.
3926 */
3927
3928 if (nAvail < numColors) {
3929 return 0;
3930 }
3931
3932 /*
3933 * Scan through a second time freeing colors.
3934 */
3935
3936 entry = Tcl_FirstHashEntry(&imgPhotoColorHash, &srch);
3937 while ((entry != NULL) && (numColors > 0)) {
3938 colorPtr = (ColorTable *) Tcl_GetHashValue(entry);
3939 if ((colorPtr->id.display == id->display)
3940 && (colorPtr->id.colormap == id->colormap)
3941 && (colorPtr->liveRefCount == 0) && (colorPtr->numColors != 0)
3942 && ((colorPtr->id.palette != id->palette)
3943 || (colorPtr->id.gamma != id->gamma))) {
3944 /*
3945 * Free the colors that this ColorTable has.
3946 */
3947
3948 XFreeColors(colorPtr->id.display, colorPtr->id.colormap,
3949 colorPtr->pixelMap, colorPtr->numColors, 0);
3950 numColors -= colorPtr->numColors;
3951 colorPtr->numColors = 0;
3952 ckfree((char *) colorPtr->pixelMap);
3953 colorPtr->pixelMap = NULL;
3954 }
3955
3956 entry = Tcl_NextHashEntry(&srch);
3957 }
3958 return 1; /* We freed some colors. */
3959 }
3960
3961 /*
3962 *----------------------------------------------------------------------
3963 *
3964 * DisposeInstance --
3965 *
3966 * This function is called to finally free up an instance of a photo
3967 * image which is no longer required.
3968 *
3969 * Results:
3970 * None.
3971 *
3972 * Side effects:
3973 * The instance data structure and the resources it references are freed.
3974 *
3975 *----------------------------------------------------------------------
3976 */
3977
3978 static void
DisposeInstance(ClientData clientData)3979 DisposeInstance(
3980 ClientData clientData) /* Pointer to the instance whose resources are
3981 * to be released. */
3982 {
3983 PhotoInstance *instancePtr = (PhotoInstance *) clientData;
3984 PhotoInstance *prevPtr;
3985
3986 if (instancePtr->pixels != None) {
3987 Tk_FreePixmap(instancePtr->display, instancePtr->pixels);
3988 }
3989 if (instancePtr->gc != None) {
3990 Tk_FreeGC(instancePtr->display, instancePtr->gc);
3991 }
3992 if (instancePtr->imagePtr != NULL) {
3993 XDestroyImage(instancePtr->imagePtr);
3994 }
3995 if (instancePtr->error != NULL) {
3996 ckfree((char *) instancePtr->error);
3997 }
3998 if (instancePtr->colorTablePtr != NULL) {
3999 FreeColorTable(instancePtr->colorTablePtr, 1);
4000 }
4001
4002 if (instancePtr->masterPtr->instancePtr == instancePtr) {
4003 instancePtr->masterPtr->instancePtr = instancePtr->nextPtr;
4004 } else {
4005 for (prevPtr = instancePtr->masterPtr->instancePtr;
4006 prevPtr->nextPtr != instancePtr; prevPtr = prevPtr->nextPtr) {
4007 /* Empty loop body. */
4008 }
4009 prevPtr->nextPtr = instancePtr->nextPtr;
4010 }
4011 Tk_FreeColormap(instancePtr->display, instancePtr->colormap);
4012 ckfree((char *) instancePtr);
4013 }
4014
4015 /*
4016 *----------------------------------------------------------------------
4017 *
4018 * MatchFileFormat --
4019 *
4020 * This function is called to find a photo image file format handler
4021 * which can parse the image data in the given file. If a user-specified
4022 * format string is provided, only handlers whose names match a prefix of
4023 * the format string are tried.
4024 *
4025 * Results:
4026 * A standard TCL return value. If the return value is TCL_OK, a pointer
4027 * to the image format record is returned in *imageFormatPtr, and the
4028 * width and height of the image are returned in *widthPtr and
4029 * *heightPtr.
4030 *
4031 * Side effects:
4032 * None.
4033 *
4034 *----------------------------------------------------------------------
4035 */
4036
4037 static int
MatchFileFormat(Tcl_Interp * interp,Tcl_Channel chan,char * fileName,Tcl_Obj * formatObj,Tk_PhotoImageFormat ** imageFormatPtr,int * widthPtr,int * heightPtr,int * oldformat)4038 MatchFileFormat(
4039 Tcl_Interp *interp, /* Interpreter to use for reporting errors. */
4040 Tcl_Channel chan, /* The image file, open for reading. */
4041 char *fileName, /* The name of the image file. */
4042 Tcl_Obj *formatObj, /* User-specified format string, or NULL. */
4043 Tk_PhotoImageFormat **imageFormatPtr,
4044 /* A pointer to the photo image format record
4045 * is returned here. */
4046 int *widthPtr, int *heightPtr,
4047 /* The dimensions of the image are returned
4048 * here. */
4049 int *oldformat) /* Returns 1 if the old image API is used. */
4050 {
4051 int matched = 0, useoldformat = 0;
4052 Tk_PhotoImageFormat *formatPtr;
4053 ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
4054 Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
4055 char *formatString = NULL;
4056
4057 if (formatObj) {
4058 formatString = Tcl_GetString(formatObj);
4059 }
4060
4061 /*
4062 * Scan through the table of file format handlers to find one which can
4063 * handle the image.
4064 */
4065
4066 for (formatPtr = tsdPtr->formatList; formatPtr != NULL;
4067 formatPtr = formatPtr->nextPtr) {
4068 if (formatObj != NULL) {
4069 if (strncasecmp(formatString,
4070 formatPtr->name, strlen(formatPtr->name)) != 0) {
4071 continue;
4072 }
4073 matched = 1;
4074 if (formatPtr->fileMatchProc == NULL) {
4075 Tcl_AppendResult(interp, "-file option isn't supported for ",
4076 formatString, " images", NULL);
4077 return TCL_ERROR;
4078 }
4079 }
4080 if (formatPtr->fileMatchProc != NULL) {
4081 (void) Tcl_Seek(chan, Tcl_LongAsWide(0L), SEEK_SET);
4082
4083 if ((*formatPtr->fileMatchProc)(chan, fileName, formatObj,
4084 widthPtr, heightPtr, interp)) {
4085 if (*widthPtr < 1) {
4086 *widthPtr = 1;
4087 }
4088 if (*heightPtr < 1) {
4089 *heightPtr = 1;
4090 }
4091 break;
4092 }
4093 }
4094 }
4095 if (formatPtr == NULL) {
4096 useoldformat = 1;
4097 for (formatPtr = tsdPtr->oldFormatList; formatPtr != NULL;
4098 formatPtr = formatPtr->nextPtr) {
4099 if (formatString != NULL) {
4100 if (strncasecmp(formatString,
4101 formatPtr->name, strlen(formatPtr->name)) != 0) {
4102 continue;
4103 }
4104 matched = 1;
4105 if (formatPtr->fileMatchProc == NULL) {
4106 Tcl_AppendResult(interp, "-file option isn't supported",
4107 " for ", formatString, " images", NULL);
4108 return TCL_ERROR;
4109 }
4110 }
4111 if (formatPtr->fileMatchProc != NULL) {
4112 (void) Tcl_Seek(chan, Tcl_LongAsWide(0L), SEEK_SET);
4113 if ((*formatPtr->fileMatchProc)(chan, fileName, (Tcl_Obj *)
4114 formatString, widthPtr, heightPtr, interp)) {
4115 if (*widthPtr < 1) {
4116 *widthPtr = 1;
4117 }
4118 if (*heightPtr < 1) {
4119 *heightPtr = 1;
4120 }
4121 break;
4122 }
4123 }
4124 }
4125 }
4126
4127 if (formatPtr == NULL) {
4128 if ((formatObj != NULL) && !matched) {
4129 Tcl_AppendResult(interp, "image file format \"", formatString,
4130 "\" is not supported", NULL);
4131 } else {
4132 Tcl_AppendResult(interp,
4133 "couldn't recognize data in image file \"", fileName, "\"",
4134 NULL);
4135 }
4136 return TCL_ERROR;
4137 }
4138
4139 *imageFormatPtr = formatPtr;
4140 *oldformat = useoldformat;
4141 (void) Tcl_Seek(chan, Tcl_LongAsWide(0L), SEEK_SET);
4142 return TCL_OK;
4143 }
4144
4145 /*
4146 *----------------------------------------------------------------------
4147 *
4148 * MatchStringFormat --
4149 *
4150 * This function is called to find a photo image file format handler
4151 * which can parse the image data in the given string. If a
4152 * user-specified format string is provided, only handlers whose names
4153 * match a prefix of the format string are tried.
4154 *
4155 * Results:
4156 * A standard TCL return value. If the return value is TCL_OK, a pointer
4157 * to the image format record is returned in *imageFormatPtr, and the
4158 * width and height of the image are returned in *widthPtr and
4159 * *heightPtr.
4160 *
4161 * Side effects:
4162 * None.
4163 *
4164 *----------------------------------------------------------------------
4165 */
4166
4167 static int
MatchStringFormat(Tcl_Interp * interp,Tcl_Obj * data,Tcl_Obj * formatObj,Tk_PhotoImageFormat ** imageFormatPtr,int * widthPtr,int * heightPtr,int * oldformat)4168 MatchStringFormat(
4169 Tcl_Interp *interp, /* Interpreter to use for reporting errors. */
4170 Tcl_Obj *data, /* Object containing the image data. */
4171 Tcl_Obj *formatObj, /* User-specified format string, or NULL. */
4172 Tk_PhotoImageFormat **imageFormatPtr,
4173 /* A pointer to the photo image format record
4174 * is returned here. */
4175 int *widthPtr, int *heightPtr,
4176 /* The dimensions of the image are returned
4177 * here. */
4178 int *oldformat) /* Returns 1 if the old image API is used. */
4179 {
4180 int matched = 0, useoldformat = 0;
4181 Tk_PhotoImageFormat *formatPtr;
4182 ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
4183 Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
4184 char *formatString = NULL;
4185
4186 if (formatObj) {
4187 formatString = Tcl_GetString(formatObj);
4188 }
4189
4190 /*
4191 * Scan through the table of file format handlers to find one which can
4192 * handle the image.
4193 */
4194
4195 for (formatPtr = tsdPtr->formatList; formatPtr != NULL;
4196 formatPtr = formatPtr->nextPtr) {
4197 if (formatObj != NULL) {
4198 if (strncasecmp(formatString,
4199 formatPtr->name, strlen(formatPtr->name)) != 0) {
4200 continue;
4201 }
4202 matched = 1;
4203 if (formatPtr->stringMatchProc == NULL) {
4204 Tcl_AppendResult(interp, "-data option isn't supported for ",
4205 formatString, " images", NULL);
4206 return TCL_ERROR;
4207 }
4208 }
4209 if ((formatPtr->stringMatchProc != NULL)
4210 && (formatPtr->stringReadProc != NULL)
4211 && (*formatPtr->stringMatchProc)(data, formatObj,
4212 widthPtr, heightPtr, interp)) {
4213 break;
4214 }
4215 }
4216
4217 if (formatPtr == NULL) {
4218 useoldformat = 1;
4219 for (formatPtr = tsdPtr->oldFormatList; formatPtr != NULL;
4220 formatPtr = formatPtr->nextPtr) {
4221 if (formatObj != NULL) {
4222 if (strncasecmp(formatString,
4223 formatPtr->name, strlen(formatPtr->name)) != 0) {
4224 continue;
4225 }
4226 matched = 1;
4227 if (formatPtr->stringMatchProc == NULL) {
4228 Tcl_AppendResult(interp, "-data option isn't supported",
4229 " for ", formatString, " images", NULL);
4230 return TCL_ERROR;
4231 }
4232 }
4233 if ((formatPtr->stringMatchProc != NULL)
4234 && (formatPtr->stringReadProc != NULL)
4235 && (*formatPtr->stringMatchProc)(
4236 (Tcl_Obj *) Tcl_GetString(data),
4237 (Tcl_Obj *) formatString,
4238 widthPtr, heightPtr, interp)) {
4239 break;
4240 }
4241 }
4242 }
4243 if (formatPtr == NULL) {
4244 if ((formatObj != NULL) && !matched) {
4245 Tcl_AppendResult(interp, "image format \"", formatString,
4246 "\" is not supported", NULL);
4247 } else {
4248 Tcl_AppendResult(interp, "couldn't recognize image data", NULL);
4249 }
4250 return TCL_ERROR;
4251 }
4252
4253 *imageFormatPtr = formatPtr;
4254 *oldformat = useoldformat;
4255 return TCL_OK;
4256 }
4257
4258 /*
4259 *----------------------------------------------------------------------
4260 *
4261 * Tk_FindPhoto --
4262 *
4263 * This function is called to get an opaque handle (actually a
4264 * PhotoMaster *) for a given image, which can be used in subsequent
4265 * calls to Tk_PhotoPutBlock, etc. The `name' parameter is the name of
4266 * the image.
4267 *
4268 * Results:
4269 * The handle for the photo image, or NULL if there is no photo image
4270 * with the name given.
4271 *
4272 * Side effects:
4273 * None.
4274 *
4275 *----------------------------------------------------------------------
4276 */
4277
4278 Tk_PhotoHandle
Tk_FindPhoto(Tcl_Interp * interp,CONST char * imageName)4279 Tk_FindPhoto(
4280 Tcl_Interp *interp, /* Interpreter (application) in which image
4281 * exists. */
4282 CONST char *imageName) /* Name of the desired photo image. */
4283 {
4284 ClientData clientData;
4285 Tk_ImageType *typePtr;
4286
4287 clientData = Tk_GetImageMasterData(interp, imageName, &typePtr);
4288 if ((typePtr == NULL) || (typePtr->name != tkPhotoImageType.name)) {
4289 return NULL;
4290 }
4291 return (Tk_PhotoHandle) clientData;
4292 }
4293
4294 /*
4295 *----------------------------------------------------------------------
4296 *
4297 * Tk_PhotoPutBlock --
4298 *
4299 * This function is called to put image data into a photo image.
4300 *
4301 * Results:
4302 * A standard Tcl result code.
4303 *
4304 * Side effects:
4305 * The image data is stored. The image may be expanded. The Tk image code
4306 * is informed that the image has changed. If the result code is
4307 * TCL_ERROR, an error message will be placed in the interpreter (if
4308 * non-NULL).
4309 *
4310 *----------------------------------------------------------------------
4311 */
4312
4313 int
Tk_PhotoPutBlock(Tcl_Interp * interp,Tk_PhotoHandle handle,register Tk_PhotoImageBlock * blockPtr,int x,int y,int width,int height,int compRule)4314 Tk_PhotoPutBlock(
4315 Tcl_Interp *interp, /* Interpreter for passing back error
4316 * messages, or NULL. */
4317 Tk_PhotoHandle handle, /* Opaque handle for the photo image to be
4318 * updated. */
4319 register Tk_PhotoImageBlock *blockPtr,
4320 /* Pointer to a structure describing the pixel
4321 * data to be copied into the image. */
4322 int x, int y, /* Coordinates of the top-left pixel to be
4323 * updated in the image. */
4324 int width, int height, /* Dimensions of the area of the image to be
4325 * updated. */
4326 int compRule) /* Compositing rule to use when processing
4327 * transparent pixels. */
4328 {
4329 register PhotoMaster *masterPtr;
4330 int xEnd, yEnd, greenOffset, blueOffset, alphaOffset;
4331 int wLeft, hLeft, wCopy, hCopy, pitch;
4332 unsigned char *srcPtr, *srcLinePtr, *destPtr, *destLinePtr;
4333 int sourceIsSimplePhoto = compRule & SOURCE_IS_SIMPLE_ALPHA_PHOTO;
4334 XRectangle rect;
4335
4336 masterPtr = (PhotoMaster *) handle;
4337 compRule &= ~SOURCE_IS_SIMPLE_ALPHA_PHOTO;
4338
4339 if ((masterPtr->userWidth != 0) && ((x + width) > masterPtr->userWidth)) {
4340 width = masterPtr->userWidth - x;
4341 }
4342 if ((masterPtr->userHeight != 0)
4343 && ((y + height) > masterPtr->userHeight)) {
4344 height = masterPtr->userHeight - y;
4345 }
4346 if ((width <= 0) || (height <= 0)) {
4347 return TCL_OK;
4348 }
4349
4350 xEnd = x + width;
4351 yEnd = y + height;
4352 if ((xEnd > masterPtr->width) || (yEnd > masterPtr->height)) {
4353 int sameSrc = (blockPtr->pixelPtr == masterPtr->pix32);
4354
4355 if (ImgPhotoSetSize(masterPtr, MAX(xEnd, masterPtr->width),
4356 MAX(yEnd, masterPtr->height)) == TCL_ERROR) {
4357 if (interp != NULL) {
4358 Tcl_ResetResult(interp);
4359 Tcl_AppendResult(interp, TK_PHOTO_ALLOC_FAILURE_MESSAGE, NULL);
4360 }
4361 return TCL_ERROR;
4362 }
4363 if (sameSrc) {
4364 blockPtr->pixelPtr = masterPtr->pix32;
4365 blockPtr->pitch = masterPtr->width * 4;
4366 }
4367 }
4368
4369 if ((y < masterPtr->ditherY) || ((y == masterPtr->ditherY)
4370 && (x < masterPtr->ditherX))) {
4371 /*
4372 * The dithering isn't correct past the start of this block.
4373 */
4374
4375 masterPtr->ditherX = x;
4376 masterPtr->ditherY = y;
4377 }
4378
4379 /*
4380 * If this image block could have different red, green and blue
4381 * components, mark it as a color image.
4382 */
4383
4384 greenOffset = blockPtr->offset[1] - blockPtr->offset[0];
4385 blueOffset = blockPtr->offset[2] - blockPtr->offset[0];
4386 alphaOffset = blockPtr->offset[3];
4387 if ((alphaOffset >= blockPtr->pixelSize) || (alphaOffset < 0)) {
4388 alphaOffset = 0;
4389 sourceIsSimplePhoto = 1;
4390 } else {
4391 alphaOffset -= blockPtr->offset[0];
4392 }
4393 if ((greenOffset != 0) || (blueOffset != 0)) {
4394 masterPtr->flags |= COLOR_IMAGE;
4395 }
4396
4397 /*
4398 * Copy the data into our local 32-bit/pixel array. If we can do it with a
4399 * single memmove, we do.
4400 */
4401
4402 destLinePtr = masterPtr->pix32 + (y * masterPtr->width + x) * 4;
4403 pitch = masterPtr->width * 4;
4404
4405 /*
4406 * Test to see if we can do the whole write in a single copy. This test is
4407 * probably too restrictive. We should also be able to do a memmove if
4408 * pixelSize == 3 and alphaOffset == 0. Maybe other cases too.
4409 */
4410
4411 if ((blockPtr->pixelSize == 4)
4412 && (greenOffset == 1) && (blueOffset == 2) && (alphaOffset == 3)
4413 && (width <= blockPtr->width) && (height <= blockPtr->height)
4414 && ((height == 1) || ((x == 0) && (width == masterPtr->width)
4415 && (blockPtr->pitch == pitch)))
4416 && (compRule == TK_PHOTO_COMPOSITE_SET)) {
4417 memmove(destLinePtr, blockPtr->pixelPtr + blockPtr->offset[0],
4418 (size_t) (height * width * 4));
4419
4420 /*
4421 * We know there's an alpha offset and we're setting the data, so skip
4422 * directly to the point when we recompute the photo validity region.
4423 */
4424
4425 goto recalculateValidRegion;
4426 }
4427
4428 /*
4429 * Copy and merge pixels according to the compositing rule.
4430 */
4431
4432 for (hLeft = height; hLeft > 0;) {
4433 int pixelSize = blockPtr->pixelSize;
4434 int compRuleSet = (compRule == TK_PHOTO_COMPOSITE_SET);
4435
4436 srcLinePtr = blockPtr->pixelPtr + blockPtr->offset[0];
4437 hCopy = MIN(hLeft, blockPtr->height);
4438 hLeft -= hCopy;
4439 for (; hCopy > 0; --hCopy) {
4440 /*
4441 * If the layout of the source line matches our memory layout and
4442 * we're setting, we can just copy the bytes directly, which is
4443 * much faster.
4444 */
4445
4446 if ((pixelSize == 4) && (greenOffset == 1)
4447 && (blueOffset == 2) && (alphaOffset == 3)
4448 && (width <= blockPtr->width)
4449 && compRuleSet) {
4450 memcpy(destLinePtr, srcLinePtr, (size_t) (width * 4));
4451 srcLinePtr += blockPtr->pitch;
4452 destLinePtr += pitch;
4453 continue;
4454 }
4455
4456 /*
4457 * Have to copy the slow way.
4458 */
4459
4460 destPtr = destLinePtr;
4461 for (wLeft = width; wLeft > 0;) {
4462 wCopy = MIN(wLeft, blockPtr->width);
4463 wLeft -= wCopy;
4464 srcPtr = srcLinePtr;
4465
4466 /*
4467 * But we might be lucky and be able to use fairly fast loops.
4468 * It's worth checking...
4469 */
4470
4471 if (alphaOffset == 0) {
4472 /*
4473 * This is the non-alpha case, so can still be fairly
4474 * fast. Note that in the non-alpha-source case, the
4475 * compositing rule doesn't apply.
4476 */
4477
4478 for (; wCopy>0 ; --wCopy, srcPtr+=pixelSize) {
4479 *destPtr++ = srcPtr[0];
4480 *destPtr++ = srcPtr[greenOffset];
4481 *destPtr++ = srcPtr[blueOffset];
4482 *destPtr++ = 255;
4483 }
4484 continue;
4485 } else if (compRuleSet) {
4486 /*
4487 * This is the SET compositing rule, which just replaces
4488 * what was there before with the new data. This is
4489 * another fairly fast case. No point in doing a memcpy();
4490 * the order of channels is probably wrong.
4491 */
4492
4493 for (; wCopy>0 ; --wCopy, srcPtr+=pixelSize) {
4494 *destPtr++ = srcPtr[0];
4495 *destPtr++ = srcPtr[greenOffset];
4496 *destPtr++ = srcPtr[blueOffset];
4497 *destPtr++ = srcPtr[alphaOffset];
4498 }
4499 continue;
4500 }
4501
4502 /*
4503 * Bother; need to consider the alpha value of each pixel to
4504 * know what to do.
4505 */
4506
4507 for (; wCopy>0 ; --wCopy, srcPtr+=pixelSize) {
4508 int alpha = srcPtr[alphaOffset];
4509
4510 if (alpha == 255 || !destPtr[3]) {
4511 /*
4512 * Either the source is 100% opaque, or the
4513 * destination is entirely blank. In all cases, we
4514 * just set the destination to the source.
4515 */
4516
4517 *destPtr++ = srcPtr[0];
4518 *destPtr++ = srcPtr[greenOffset];
4519 *destPtr++ = srcPtr[blueOffset];
4520 *destPtr++ = alpha;
4521 continue;
4522 }
4523
4524 /*
4525 * Can still skip doing work if the source is 100%
4526 * transparent at this point.
4527 */
4528
4529 if (alpha) {
4530 int Alpha = destPtr[3];
4531
4532 /*
4533 * OK, there's real work to be done. Luckily, there's
4534 * a substantial literature on what to do in this
4535 * case. In particular, Porter and Duff have done a
4536 * taxonomy of compositing rules, and the right one is
4537 * the "Source Over" rule. This code implements that.
4538 */
4539
4540 destPtr[0] = PD_SRC_OVER(srcPtr[0], alpha, destPtr[0],
4541 Alpha);
4542 destPtr[1] = PD_SRC_OVER(srcPtr[greenOffset], alpha,
4543 destPtr[1], Alpha);
4544 destPtr[2] = PD_SRC_OVER(srcPtr[blueOffset], alpha,
4545 destPtr[2], Alpha);
4546 destPtr[3] = PD_SRC_OVER_ALPHA(alpha, Alpha);
4547 }
4548
4549 destPtr += 4;
4550 }
4551 }
4552 srcLinePtr += blockPtr->pitch;
4553 destLinePtr += pitch;
4554 }
4555 }
4556
4557 /*
4558 * Add this new block to the region which specifies which data is valid.
4559 */
4560
4561 if (alphaOffset) {
4562 /*
4563 * This block is grossly inefficient. For each row in the image, it
4564 * finds each continguous string of nontransparent pixels, then marks
4565 * those areas as valid in the validRegion mask. This makes drawing
4566 * very efficient, because of the way we use X: we just say, here's
4567 * your mask, and here's your data. We need not worry about the
4568 * current background color, etc. But this costs us a lot on the image
4569 * setup. Still, image setup only happens once, whereas the drawing
4570 * happens many times, so this might be the best way to go.
4571 *
4572 * An alternative might be to not set up this mask, and instead, at
4573 * drawing time, for each transparent pixel, set its color to the
4574 * color of the background behind that pixel. This is what I suspect
4575 * most of programs do. However, they don't have to deal with the
4576 * canvas, which could have many different background colors.
4577 * Determining the correct bg color for a given pixel might be
4578 * expensive.
4579 */
4580
4581 if (compRule != TK_PHOTO_COMPOSITE_OVERLAY) {
4582 TkRegion workRgn;
4583
4584 /*
4585 * Don't need this when using the OVERLAY compositing rule, which
4586 * always strictly increases the valid region.
4587 */
4588
4589 recalculateValidRegion:
4590 workRgn = TkCreateRegion();
4591 rect.x = x;
4592 rect.y = y;
4593 rect.width = width;
4594 rect.height = height;
4595 TkUnionRectWithRegion(&rect, workRgn, workRgn);
4596 TkSubtractRegion(masterPtr->validRegion, workRgn,
4597 masterPtr->validRegion);
4598 TkDestroyRegion(workRgn);
4599 }
4600
4601 /*
4602 * Factorize out the main part of the building of the region data to
4603 * allow for more efficient per-platform implementations. [Bug 919066]
4604 */
4605
4606 TkpBuildRegionFromAlphaData(masterPtr->validRegion, (unsigned) x,
4607 (unsigned) y, (unsigned) width, (unsigned) height,
4608 masterPtr->pix32 + (y * masterPtr->width + x) * 4 + 3,
4609 4, (unsigned) masterPtr->width * 4);
4610 } else {
4611 rect.x = x;
4612 rect.y = y;
4613 rect.width = width;
4614 rect.height = height;
4615 TkUnionRectWithRegion(&rect, masterPtr->validRegion,
4616 masterPtr->validRegion);
4617 }
4618
4619 /*
4620 * Check if display code needs alpha blending...
4621 */
4622
4623 if (!sourceIsSimplePhoto && (width == 1) && (height == 1)) {
4624 /*
4625 * Optimize the single pixel case if we can. This speeds up code that
4626 * builds up large simple-alpha images by single pixels. We don't
4627 * negate COMPLEX_ALPHA in this case. [Bug 1409140]
4628 */
4629
4630 if (!(masterPtr->flags & COMPLEX_ALPHA)) {
4631 unsigned char newAlpha;
4632
4633 destLinePtr = masterPtr->pix32 + (y * masterPtr->width + x) * 4;
4634 newAlpha = destLinePtr[3];
4635
4636 if (newAlpha && newAlpha != 255) {
4637 masterPtr->flags |= COMPLEX_ALPHA;
4638 }
4639 }
4640 } else if ((alphaOffset != 0) || (masterPtr->flags & COMPLEX_ALPHA)) {
4641 /*
4642 * Check for partial transparency if alpha pixels are specified, or
4643 * rescan if we already knew such pixels existed. To restrict this
4644 * Toggle to only checking the changed pixels requires knowing where
4645 * the alpha pixels are.
4646 */
4647
4648 ToggleComplexAlphaIfNeeded(masterPtr);
4649 }
4650
4651 /*
4652 * Update each instance.
4653 */
4654
4655 Tk_DitherPhoto((Tk_PhotoHandle)masterPtr, x, y, width, height);
4656
4657 /*
4658 * Tell the core image code that this image has changed.
4659 */
4660
4661 Tk_ImageChanged(masterPtr->tkMaster, x, y, width, height,
4662 masterPtr->width, masterPtr->height);
4663 return TCL_OK;
4664 }
4665
4666 /*
4667 *----------------------------------------------------------------------
4668 *
4669 * Tk_PhotoPutZoomedBlock --
4670 *
4671 * This function is called to put image data into a photo image, with
4672 * possible subsampling and/or zooming of the pixels.
4673 *
4674 * Results:
4675 * None.
4676 *
4677 * Side effects:
4678 * The image data is stored. The image may be expanded. The Tk image code
4679 * is informed that the image has changed.
4680 *
4681 *----------------------------------------------------------------------
4682 */
4683
4684 int
Tk_PhotoPutZoomedBlock(Tcl_Interp * interp,Tk_PhotoHandle handle,register Tk_PhotoImageBlock * blockPtr,int x,int y,int width,int height,int zoomX,int zoomY,int subsampleX,int subsampleY,int compRule)4685 Tk_PhotoPutZoomedBlock(
4686 Tcl_Interp *interp, /* Interpreter for passing back error
4687 * messages, or NULL. */
4688 Tk_PhotoHandle handle, /* Opaque handle for the photo image to be
4689 * updated. */
4690 register Tk_PhotoImageBlock *blockPtr,
4691 /* Pointer to a structure describing the pixel
4692 * data to be copied into the image. */
4693 int x, int y, /* Coordinates of the top-left pixel to be
4694 * updated in the image. */
4695 int width, int height, /* Dimensions of the area of the image to be
4696 * updated. */
4697 int zoomX, int zoomY, /* Zoom factors for the X and Y axes. */
4698 int subsampleX, int subsampleY,
4699 /* Subsampling factors for the X and Y
4700 * axes. */
4701 int compRule) /* Compositing rule to use when processing
4702 * transparent pixels. */
4703 {
4704 register PhotoMaster *masterPtr = (PhotoMaster *) handle;
4705 int xEnd, yEnd, greenOffset, blueOffset, alphaOffset;
4706 int wLeft, hLeft, wCopy, hCopy, blockWid, blockHt;
4707 unsigned char *srcPtr, *srcLinePtr, *srcOrigPtr, *destPtr, *destLinePtr;
4708 int pitch, xRepeat, yRepeat, blockXSkip, blockYSkip, sourceIsSimplePhoto;
4709 XRectangle rect;
4710
4711 if (zoomX==1 && zoomY==1 && subsampleX==1 && subsampleY==1) {
4712 return Tk_PhotoPutBlock(interp, handle, blockPtr, x, y, width, height,
4713 compRule);
4714 }
4715
4716 sourceIsSimplePhoto = compRule & SOURCE_IS_SIMPLE_ALPHA_PHOTO;
4717 compRule &= ~SOURCE_IS_SIMPLE_ALPHA_PHOTO;
4718
4719 if (zoomX <= 0 || zoomY <= 0) {
4720 return TCL_OK;
4721 }
4722 if ((masterPtr->userWidth != 0) && ((x + width) > masterPtr->userWidth)) {
4723 width = masterPtr->userWidth - x;
4724 }
4725 if ((masterPtr->userHeight != 0)
4726 && ((y + height) > masterPtr->userHeight)) {
4727 height = masterPtr->userHeight - y;
4728 }
4729 if (width <= 0 || height <= 0) {
4730 return TCL_OK;
4731 }
4732
4733 xEnd = x + width;
4734 yEnd = y + height;
4735 if ((xEnd > masterPtr->width) || (yEnd > masterPtr->height)) {
4736 int sameSrc = (blockPtr->pixelPtr == masterPtr->pix32);
4737 if (ImgPhotoSetSize(masterPtr, MAX(xEnd, masterPtr->width),
4738 MAX(yEnd, masterPtr->height)) == TCL_ERROR) {
4739 if (interp != NULL) {
4740 Tcl_ResetResult(interp);
4741 Tcl_AppendResult(interp, TK_PHOTO_ALLOC_FAILURE_MESSAGE, NULL);
4742 }
4743 return TCL_ERROR;
4744 }
4745 if (sameSrc) {
4746 blockPtr->pixelPtr = masterPtr->pix32;
4747 blockPtr->pitch = masterPtr->width * 4;
4748 }
4749 }
4750
4751 if ((y < masterPtr->ditherY) || ((y == masterPtr->ditherY)
4752 && (x < masterPtr->ditherX))) {
4753 /*
4754 * The dithering isn't correct past the start of this block.
4755 */
4756
4757 masterPtr->ditherX = x;
4758 masterPtr->ditherY = y;
4759 }
4760
4761 /*
4762 * If this image block could have different red, green and blue
4763 * components, mark it as a color image.
4764 */
4765
4766 greenOffset = blockPtr->offset[1] - blockPtr->offset[0];
4767 blueOffset = blockPtr->offset[2] - blockPtr->offset[0];
4768 alphaOffset = blockPtr->offset[3];
4769 if ((alphaOffset >= blockPtr->pixelSize) || (alphaOffset < 0)) {
4770 alphaOffset = 0;
4771 sourceIsSimplePhoto = 1;
4772 } else {
4773 alphaOffset -= blockPtr->offset[0];
4774 }
4775 if ((greenOffset != 0) || (blueOffset != 0)) {
4776 masterPtr->flags |= COLOR_IMAGE;
4777 }
4778
4779 /*
4780 * Work out what area the pixel data in the block expands to after
4781 * subsampling and zooming.
4782 */
4783
4784 blockXSkip = subsampleX * blockPtr->pixelSize;
4785 blockYSkip = subsampleY * blockPtr->pitch;
4786 if (subsampleX > 0) {
4787 blockWid = ((blockPtr->width + subsampleX - 1) / subsampleX) * zoomX;
4788 } else if (subsampleX == 0) {
4789 blockWid = width;
4790 } else {
4791 blockWid = ((blockPtr->width - subsampleX - 1) / -subsampleX) * zoomX;
4792 }
4793 if (subsampleY > 0) {
4794 blockHt = ((blockPtr->height + subsampleY - 1) / subsampleY) * zoomY;
4795 } else if (subsampleY == 0) {
4796 blockHt = height;
4797 } else {
4798 blockHt = ((blockPtr->height - subsampleY - 1) / -subsampleY) * zoomY;
4799 }
4800
4801 /*
4802 * Copy the data into our local 32-bit/pixel array.
4803 */
4804
4805 destLinePtr = masterPtr->pix32 + (y * masterPtr->width + x) * 4;
4806 srcOrigPtr = blockPtr->pixelPtr + blockPtr->offset[0];
4807 if (subsampleX < 0) {
4808 srcOrigPtr += (blockPtr->width - 1) * blockPtr->pixelSize;
4809 }
4810 if (subsampleY < 0) {
4811 srcOrigPtr += (blockPtr->height - 1) * blockPtr->pitch;
4812 }
4813
4814 pitch = masterPtr->width * 4;
4815 for (hLeft = height; hLeft > 0; ) {
4816 hCopy = MIN(hLeft, blockHt);
4817 hLeft -= hCopy;
4818 yRepeat = zoomY;
4819 srcLinePtr = srcOrigPtr;
4820 for (; hCopy > 0; --hCopy) {
4821 destPtr = destLinePtr;
4822 for (wLeft = width; wLeft > 0;) {
4823 wCopy = MIN(wLeft, blockWid);
4824 wLeft -= wCopy;
4825 srcPtr = srcLinePtr;
4826 for (; wCopy > 0; wCopy -= zoomX) {
4827 for (xRepeat = MIN(wCopy, zoomX); xRepeat > 0; xRepeat--) {
4828 int alpha = srcPtr[alphaOffset];/* Source alpha. */
4829
4830 /*
4831 * Common case (solid pixels) first
4832 */
4833
4834 if (!alphaOffset || (alpha == 255)) {
4835 *destPtr++ = srcPtr[0];
4836 *destPtr++ = srcPtr[greenOffset];
4837 *destPtr++ = srcPtr[blueOffset];
4838 *destPtr++ = 255;
4839 continue;
4840 }
4841
4842 if (compRule==TK_PHOTO_COMPOSITE_SET || !destPtr[3]) {
4843 /*
4844 * Either this is the SET rule (we overwrite
4845 * whatever is there) or the destination is
4846 * entirely blank. In both cases, we just set the
4847 * destination to the source.
4848 */
4849
4850 *destPtr++ = srcPtr[0];
4851 *destPtr++ = srcPtr[greenOffset];
4852 *destPtr++ = srcPtr[blueOffset];
4853 *destPtr++ = alpha;
4854 } else if (alpha) {
4855 int Alpha = destPtr[3]; /* Destination
4856 * alpha. */
4857
4858 destPtr[0] = PD_SRC_OVER(srcPtr[0], alpha,
4859 destPtr[0], Alpha);
4860 destPtr[1] = PD_SRC_OVER(srcPtr[greenOffset],alpha,
4861 destPtr[1], Alpha);
4862 destPtr[2] = PD_SRC_OVER(srcPtr[blueOffset], alpha,
4863 destPtr[2], Alpha);
4864 destPtr[3] = PD_SRC_OVER_ALPHA(alpha, Alpha);
4865
4866 destPtr += 4;
4867 } else {
4868 destPtr += 4;
4869 }
4870 }
4871 srcPtr += blockXSkip;
4872 }
4873 }
4874 destLinePtr += pitch;
4875 yRepeat--;
4876 if (yRepeat <= 0) {
4877 srcLinePtr += blockYSkip;
4878 yRepeat = zoomY;
4879 }
4880 }
4881 }
4882
4883 /*
4884 * Recompute the region of data for which we have valid pixels to plot.
4885 */
4886
4887 if (alphaOffset) {
4888 if (compRule != TK_PHOTO_COMPOSITE_OVERLAY) {
4889 /*
4890 * Don't need this when using the OVERLAY compositing rule, which
4891 * always strictly increases the valid region.
4892 */
4893
4894 TkRegion workRgn = TkCreateRegion();
4895
4896 rect.x = x;
4897 rect.y = y;
4898 rect.width = width;
4899 rect.height = 1;
4900 TkUnionRectWithRegion(&rect, workRgn, workRgn);
4901 TkSubtractRegion(masterPtr->validRegion, workRgn,
4902 masterPtr->validRegion);
4903 TkDestroyRegion(workRgn);
4904 }
4905
4906 TkpBuildRegionFromAlphaData(masterPtr->validRegion,
4907 (unsigned)x, (unsigned)y, (unsigned)width, (unsigned)height,
4908 &masterPtr->pix32[(y * masterPtr->width + x) * 4 + 3], 4,
4909 (unsigned) masterPtr->width * 4);
4910 } else {
4911 rect.x = x;
4912 rect.y = y;
4913 rect.width = width;
4914 rect.height = height;
4915 TkUnionRectWithRegion(&rect, masterPtr->validRegion,
4916 masterPtr->validRegion);
4917 }
4918
4919 /*
4920 * Check if display code needs alpha blending...
4921 */
4922
4923 if (!sourceIsSimplePhoto && (width == 1) && (height == 1)) {
4924 /*
4925 * Optimize the single pixel case if we can. This speeds up code that
4926 * builds up large simple-alpha images by single pixels. We don't
4927 * negate COMPLEX_ALPHA in this case. [Bug 1409140]
4928 */
4929 if (!(masterPtr->flags & COMPLEX_ALPHA)) {
4930 unsigned char newAlpha;
4931
4932 destLinePtr = masterPtr->pix32 + (y * masterPtr->width + x) * 4;
4933 newAlpha = destLinePtr[3];
4934
4935 if (newAlpha && newAlpha != 255) {
4936 masterPtr->flags |= COMPLEX_ALPHA;
4937 }
4938 }
4939 } else if ((alphaOffset != 0) || (masterPtr->flags & COMPLEX_ALPHA)) {
4940 /*
4941 * Check for partial transparency if alpha pixels are specified, or
4942 * rescan if we already knew such pixels existed. To restrict this
4943 * Toggle to only checking the changed pixels requires knowing where
4944 * the alpha pixels are.
4945 */
4946 ToggleComplexAlphaIfNeeded(masterPtr);
4947 }
4948
4949 /*
4950 * Update each instance.
4951 */
4952
4953 Tk_DitherPhoto((Tk_PhotoHandle) masterPtr, x, y, width, height);
4954
4955 /*
4956 * Tell the core image code that this image has changed.
4957 */
4958
4959 Tk_ImageChanged(masterPtr->tkMaster, x, y, width, height, masterPtr->width,
4960 masterPtr->height);
4961 return TCL_OK;
4962 }
4963
4964 /*
4965 *----------------------------------------------------------------------
4966 *
4967 * Tk_DitherPhoto --
4968 *
4969 * This function is called to update an area of each instance's pixmap by
4970 * dithering the corresponding area of the image master.
4971 *
4972 * Results:
4973 * None.
4974 *
4975 * Side effects:
4976 * The pixmap of each instance of this image gets updated. The fields in
4977 * *masterPtr indicating which area of the image is correctly dithered
4978 * get updated.
4979 *
4980 *----------------------------------------------------------------------
4981 */
4982
4983 void
Tk_DitherPhoto(Tk_PhotoHandle photo,int x,int y,int width,int height)4984 Tk_DitherPhoto(
4985 Tk_PhotoHandle photo, /* Image master whose instances are to be
4986 * updated. */
4987 int x, int y, /* Coordinates of the top-left pixel in the
4988 * area to be dithered. */
4989 int width, int height) /* Dimensions of the area to be dithered. */
4990 {
4991 PhotoMaster *masterPtr = (PhotoMaster *) photo;
4992 PhotoInstance *instancePtr;
4993
4994 if ((width <= 0) || (height <= 0)) {
4995 return;
4996 }
4997
4998 for (instancePtr = masterPtr->instancePtr; instancePtr != NULL;
4999 instancePtr = instancePtr->nextPtr) {
5000 DitherInstance(instancePtr, x, y, width, height);
5001 }
5002
5003 /*
5004 * Work out whether this block will be correctly dithered and whether it
5005 * will extend the correctly dithered region.
5006 */
5007
5008 if (((y < masterPtr->ditherY)
5009 || ((y == masterPtr->ditherY) && (x <= masterPtr->ditherX)))
5010 && ((y + height) > (masterPtr->ditherY))) {
5011 /*
5012 * This block starts inside (or immediately after) the correctly
5013 * dithered region, so the first scan line at least will be right.
5014 * Furthermore this block extends into scanline masterPtr->ditherY.
5015 */
5016
5017 if ((x == 0) && (width == masterPtr->width)) {
5018 /*
5019 * We are doing the full width, therefore the dithering will be
5020 * correct to the end.
5021 */
5022
5023 masterPtr->ditherX = 0;
5024 masterPtr->ditherY = y + height;
5025 } else {
5026 /*
5027 * We are doing partial scanlines, therefore the
5028 * correctly-dithered region will be extended by at most one scan
5029 * line.
5030 */
5031
5032 if (x <= masterPtr->ditherX) {
5033 masterPtr->ditherX = x + width;
5034 if (masterPtr->ditherX >= masterPtr->width) {
5035 masterPtr->ditherX = 0;
5036 masterPtr->ditherY++;
5037 }
5038 }
5039 }
5040 }
5041 }
5042
5043 /*
5044 *----------------------------------------------------------------------
5045 *
5046 * DitherInstance --
5047 *
5048 * This function is called to update an area of an instance's pixmap by
5049 * dithering the corresponding area of the master.
5050 *
5051 * Results:
5052 * None.
5053 *
5054 * Side effects:
5055 * The instance's pixmap gets updated.
5056 *
5057 *----------------------------------------------------------------------
5058 */
5059
5060 static void
DitherInstance(PhotoInstance * instancePtr,int xStart,int yStart,int width,int height)5061 DitherInstance(
5062 PhotoInstance *instancePtr, /* The instance to be updated. */
5063 int xStart, int yStart, /* Coordinates of the top-left pixel in the
5064 * block to be dithered. */
5065 int width, int height) /* Dimensions of the block to be dithered. */
5066 {
5067 PhotoMaster *masterPtr = instancePtr->masterPtr;
5068 ColorTable *colorPtr = instancePtr->colorTablePtr;
5069 XImage *imagePtr;
5070 int nLines, bigEndian, i, c, x, y, xEnd, doDithering = 1;
5071 int bitsPerPixel, bytesPerLine, lineLength;
5072 unsigned char *srcLinePtr;
5073 schar *errLinePtr;
5074 pixel firstBit, word, mask;
5075
5076 /*
5077 * Turn dithering off in certain cases where it is not needed (TrueColor,
5078 * DirectColor with many colors).
5079 */
5080
5081 if ((colorPtr->visualInfo.class == DirectColor)
5082 || (colorPtr->visualInfo.class == TrueColor)) {
5083 int nRed, nGreen, nBlue, result;
5084
5085 result = sscanf(colorPtr->id.palette, "%d/%d/%d", &nRed,
5086 &nGreen, &nBlue);
5087 if ((nRed >= 256)
5088 && ((result == 1) || ((nGreen >= 256) && (nBlue >= 256)))) {
5089 doDithering = 0;
5090 }
5091 }
5092
5093 /*
5094 * First work out how many lines to do at a time, then how many bytes
5095 * we'll need for pixel storage, and allocate it.
5096 */
5097
5098 nLines = (MAX_PIXELS + width - 1) / width;
5099 if (nLines < 1) {
5100 nLines = 1;
5101 }
5102 if (nLines > height ) {
5103 nLines = height;
5104 }
5105
5106 imagePtr = instancePtr->imagePtr;
5107 if (imagePtr == NULL) {
5108 return; /* We must be really tight on memory. */
5109 }
5110 bitsPerPixel = imagePtr->bits_per_pixel;
5111 bytesPerLine = ((bitsPerPixel * width + 31) >> 3) & ~3;
5112 imagePtr->width = width;
5113 imagePtr->height = nLines;
5114 imagePtr->bytes_per_line = bytesPerLine;
5115 imagePtr->data = (char *)
5116 ckalloc((unsigned) (imagePtr->bytes_per_line * nLines));
5117 bigEndian = imagePtr->bitmap_bit_order == MSBFirst;
5118 firstBit = bigEndian? (1 << (imagePtr->bitmap_unit - 1)): 1;
5119
5120 lineLength = masterPtr->width * 3;
5121 srcLinePtr = masterPtr->pix32 + (yStart * masterPtr->width + xStart) * 4;
5122 errLinePtr = instancePtr->error + yStart * lineLength + xStart * 3;
5123 xEnd = xStart + width;
5124
5125 /*
5126 * Loop over the image, doing at most nLines lines before updating the
5127 * screen image.
5128 */
5129
5130 for (; height > 0; height -= nLines) {
5131 unsigned char *dstLinePtr = (unsigned char *) imagePtr->data;
5132 int yEnd;
5133
5134 if (nLines > height) {
5135 nLines = height;
5136 }
5137 yEnd = yStart + nLines;
5138 for (y = yStart; y < yEnd; ++y) {
5139 unsigned char *srcPtr = srcLinePtr;
5140 schar *errPtr = errLinePtr;
5141 unsigned char *destBytePtr = dstLinePtr;
5142 pixel *destLongPtr = (pixel *) dstLinePtr;
5143
5144 if (colorPtr->flags & COLOR_WINDOW) {
5145 /*
5146 * Color window. We dither the three components independently,
5147 * using Floyd-Steinberg dithering, which propagates errors
5148 * from the quantization of pixels to the pixels below and to
5149 * the right.
5150 */
5151
5152 for (x = xStart; x < xEnd; ++x) {
5153 int col[3];
5154
5155 if (doDithering) {
5156 for (i = 0; i < 3; ++i) {
5157 /*
5158 * Compute the error propagated into this pixel
5159 * for this component. If e[x,y] is the array of
5160 * quantization error values, we compute
5161 * 7/16 * e[x-1,y] + 1/16 * e[x-1,y-1]
5162 * + 5/16 * e[x,y-1] + 3/16 * e[x+1,y-1]
5163 * and round it to an integer.
5164 *
5165 * The expression ((c + 2056) >> 4) - 128 computes
5166 * round(c / 16), and works correctly on machines
5167 * without a sign-extending right shift.
5168 */
5169
5170 c = (x > 0) ? errPtr[-3] * 7: 0;
5171 if (y > 0) {
5172 if (x > 0) {
5173 c += errPtr[-lineLength-3];
5174 }
5175 c += errPtr[-lineLength] * 5;
5176 if ((x + 1) < masterPtr->width) {
5177 c += errPtr[-lineLength+3] * 3;
5178 }
5179 }
5180
5181 /*
5182 * Add the propagated error to the value of this
5183 * component, quantize it, and store the
5184 * quantization error.
5185 */
5186
5187 c = ((c + 2056) >> 4) - 128 + *srcPtr++;
5188 if (c < 0) {
5189 c = 0;
5190 } else if (c > 255) {
5191 c = 255;
5192 }
5193 col[i] = colorPtr->colorQuant[i][c];
5194 *errPtr++ = c - col[i];
5195 }
5196 } else {
5197 /*
5198 * Output is virtually continuous in this case, so
5199 * don't bother dithering.
5200 */
5201
5202 col[0] = *srcPtr++;
5203 col[1] = *srcPtr++;
5204 col[2] = *srcPtr++;
5205 }
5206 srcPtr++;
5207
5208 /*
5209 * Translate the quantized component values into an X
5210 * pixel value, and store it in the image.
5211 */
5212
5213 i = colorPtr->redValues[col[0]]
5214 + colorPtr->greenValues[col[1]]
5215 + colorPtr->blueValues[col[2]];
5216 if (colorPtr->flags & MAP_COLORS) {
5217 i = colorPtr->pixelMap[i];
5218 }
5219 switch (bitsPerPixel) {
5220 case NBBY:
5221 *destBytePtr++ = i;
5222 break;
5223 #ifndef __WIN32__
5224 /*
5225 * This case is not valid for Windows because the
5226 * image format is different from the pixel format in
5227 * Win32. Eventually we need to fix the image code in
5228 * Tk to use the Windows native image ordering. This
5229 * would speed up the image code for all of the common
5230 * sizes.
5231 */
5232
5233 case NBBY * sizeof(pixel):
5234 *destLongPtr++ = i;
5235 break;
5236 #endif
5237 default:
5238 XPutPixel(imagePtr, x - xStart, y - yStart,
5239 (unsigned) i);
5240 }
5241 }
5242
5243 } else if (bitsPerPixel > 1) {
5244 /*
5245 * Multibit monochrome window. The operation here is similar
5246 * to the color window case above, except that there is only
5247 * one component. If the master image is in color, use the
5248 * luminance computed as
5249 * 0.344 * red + 0.5 * green + 0.156 * blue.
5250 */
5251
5252 for (x = xStart; x < xEnd; ++x) {
5253 c = (x > 0) ? errPtr[-1] * 7: 0;
5254 if (y > 0) {
5255 if (x > 0) {
5256 c += errPtr[-lineLength-1];
5257 }
5258 c += errPtr[-lineLength] * 5;
5259 if (x + 1 < masterPtr->width) {
5260 c += errPtr[-lineLength+1] * 3;
5261 }
5262 }
5263 c = ((c + 2056) >> 4) - 128;
5264
5265 if ((masterPtr->flags & COLOR_IMAGE) == 0) {
5266 c += srcPtr[0];
5267 } else {
5268 c += (unsigned)(srcPtr[0] * 11 + srcPtr[1] * 16
5269 + srcPtr[2] * 5 + 16) >> 5;
5270 }
5271 srcPtr += 4;
5272
5273 if (c < 0) {
5274 c = 0;
5275 } else if (c > 255) {
5276 c = 255;
5277 }
5278 i = colorPtr->colorQuant[0][c];
5279 *errPtr++ = c - i;
5280 i = colorPtr->redValues[i];
5281 switch (bitsPerPixel) {
5282 case NBBY:
5283 *destBytePtr++ = i;
5284 break;
5285 #ifndef __WIN32__
5286 /*
5287 * This case is not valid for Windows because the
5288 * image format is different from the pixel format in
5289 * Win32. Eventually we need to fix the image code in
5290 * Tk to use the Windows native image ordering. This
5291 * would speed up the image code for all of the common
5292 * sizes.
5293 */
5294
5295 case NBBY * sizeof(pixel):
5296 *destLongPtr++ = i;
5297 break;
5298 #endif
5299 default:
5300 XPutPixel(imagePtr, x - xStart, y - yStart,
5301 (unsigned) i);
5302 }
5303 }
5304 } else {
5305 /*
5306 * 1-bit monochrome window. This is similar to the multibit
5307 * monochrome case above, except that the quantization is
5308 * simpler (we only have black = 0 and white = 255), and we
5309 * produce an XY-Bitmap.
5310 */
5311
5312 word = 0;
5313 mask = firstBit;
5314 for (x = xStart; x < xEnd; ++x) {
5315 /*
5316 * If we have accumulated a whole word, store it in the
5317 * image and start a new word.
5318 */
5319
5320 if (mask == 0) {
5321 *destLongPtr++ = word;
5322 mask = firstBit;
5323 word = 0;
5324 }
5325
5326 c = (x > 0) ? errPtr[-1] * 7: 0;
5327 if (y > 0) {
5328 if (x > 0) {
5329 c += errPtr[-lineLength-1];
5330 }
5331 c += errPtr[-lineLength] * 5;
5332 if (x + 1 < masterPtr->width) {
5333 c += errPtr[-lineLength+1] * 3;
5334 }
5335 }
5336 c = ((c + 2056) >> 4) - 128;
5337
5338 if ((masterPtr->flags & COLOR_IMAGE) == 0) {
5339 c += srcPtr[0];
5340 } else {
5341 c += (unsigned)(srcPtr[0] * 11 + srcPtr[1] * 16
5342 + srcPtr[2] * 5 + 16) >> 5;
5343 }
5344 srcPtr += 4;
5345
5346 if (c < 0) {
5347 c = 0;
5348 } else if (c > 255) {
5349 c = 255;
5350 }
5351 if (c >= 128) {
5352 word |= mask;
5353 *errPtr++ = c - 255;
5354 } else {
5355 *errPtr++ = c;
5356 }
5357 mask = bigEndian? (mask >> 1): (mask << 1);
5358 }
5359 *destLongPtr = word;
5360 }
5361 srcLinePtr += masterPtr->width * 4;
5362 errLinePtr += lineLength;
5363 dstLinePtr += bytesPerLine;
5364 }
5365
5366 /*
5367 * Update the pixmap for this instance with the block of pixels that
5368 * we have just computed.
5369 */
5370
5371 TkPutImage(colorPtr->pixelMap, colorPtr->numColors,
5372 instancePtr->display, instancePtr->pixels,
5373 instancePtr->gc, imagePtr, 0, 0, xStart, yStart,
5374 (unsigned) width, (unsigned) nLines);
5375 yStart = yEnd;
5376 }
5377
5378 ckfree(imagePtr->data);
5379 imagePtr->data = NULL;
5380 }
5381
5382 /*
5383 *----------------------------------------------------------------------
5384 *
5385 * Tk_PhotoBlank --
5386 *
5387 * This function is called to clear an entire photo image.
5388 *
5389 * Results:
5390 * None.
5391 *
5392 * Side effects:
5393 * The valid region for the image is set to the null region. The generic
5394 * image code is notified that the image has changed.
5395 *
5396 *----------------------------------------------------------------------
5397 */
5398
5399 void
Tk_PhotoBlank(Tk_PhotoHandle handle)5400 Tk_PhotoBlank(
5401 Tk_PhotoHandle handle) /* Handle for the image to be blanked. */
5402 {
5403 PhotoMaster *masterPtr = (PhotoMaster *) handle;
5404 PhotoInstance *instancePtr;
5405
5406 masterPtr->ditherX = masterPtr->ditherY = 0;
5407 masterPtr->flags = 0;
5408
5409 /*
5410 * The image has valid data nowhere.
5411 */
5412
5413 if (masterPtr->validRegion != NULL) {
5414 TkDestroyRegion(masterPtr->validRegion);
5415 }
5416 masterPtr->validRegion = TkCreateRegion();
5417
5418 /*
5419 * Clear out the 32-bit pixel storage array. Clear out the dithering error
5420 * arrays for each instance.
5421 */
5422
5423 memset(masterPtr->pix32, 0,
5424 (size_t) (masterPtr->width * masterPtr->height * 4));
5425 for (instancePtr = masterPtr->instancePtr; instancePtr != NULL;
5426 instancePtr = instancePtr->nextPtr) {
5427 if (instancePtr->error) {
5428 memset(instancePtr->error, 0,
5429 (size_t) (masterPtr->width * masterPtr->height
5430 * 3 * sizeof(schar)));
5431 }
5432 }
5433
5434 /*
5435 * Tell the core image code that this image has changed.
5436 */
5437
5438 Tk_ImageChanged(masterPtr->tkMaster, 0, 0, masterPtr->width,
5439 masterPtr->height, masterPtr->width, masterPtr->height);
5440 }
5441
5442 /*
5443 *----------------------------------------------------------------------
5444 *
5445 * Tk_PhotoExpand --
5446 *
5447 * This function is called to request that a photo image be expanded if
5448 * necessary to be at least `width' pixels wide and `height' pixels high.
5449 * If the user has declared a definite image size (using the -width and
5450 * -height configuration options) then this call has no effect.
5451 *
5452 * Results:
5453 * None.
5454 *
5455 * Side effects:
5456 * The size of the photo image may change; if so the generic image code
5457 * is informed.
5458 *
5459 *----------------------------------------------------------------------
5460 */
5461
5462 int
Tk_PhotoExpand(Tcl_Interp * interp,Tk_PhotoHandle handle,int width,int height)5463 Tk_PhotoExpand(
5464 Tcl_Interp *interp, /* Interpreter for passing back error
5465 * messages, or NULL. */
5466 Tk_PhotoHandle handle, /* Handle for the image to be expanded. */
5467 int width, int height) /* Desired minimum dimensions of the image. */
5468 {
5469 PhotoMaster *masterPtr = (PhotoMaster *) handle;
5470
5471 if (width <= masterPtr->width) {
5472 width = masterPtr->width;
5473 }
5474 if (height <= masterPtr->height) {
5475 height = masterPtr->height;
5476 }
5477 if ((width != masterPtr->width) || (height != masterPtr->height)) {
5478 if (ImgPhotoSetSize(masterPtr, MAX(width, masterPtr->width),
5479 MAX(height, masterPtr->height)) == TCL_ERROR) {
5480 if (interp != NULL) {
5481 Tcl_ResetResult(interp);
5482 Tcl_AppendResult(interp, TK_PHOTO_ALLOC_FAILURE_MESSAGE, NULL);
5483 }
5484 return TCL_ERROR;
5485 }
5486 Tk_ImageChanged(masterPtr->tkMaster, 0, 0, 0, 0, masterPtr->width,
5487 masterPtr->height);
5488 }
5489 return TCL_OK;
5490 }
5491
5492 /*
5493 *----------------------------------------------------------------------
5494 *
5495 * Tk_PhotoGetSize --
5496 *
5497 * This function is called to obtain the current size of a photo image.
5498 *
5499 * Results:
5500 * The image's width and height are returned in *widthp and *heightp.
5501 *
5502 * Side effects:
5503 * None.
5504 *
5505 *----------------------------------------------------------------------
5506 */
5507
5508 void
Tk_PhotoGetSize(Tk_PhotoHandle handle,int * widthPtr,int * heightPtr)5509 Tk_PhotoGetSize(
5510 Tk_PhotoHandle handle, /* Handle for the image whose dimensions are
5511 * requested. */
5512 int *widthPtr, int *heightPtr)
5513 /* The dimensions of the image are returned
5514 * here. */
5515 {
5516 PhotoMaster *masterPtr = (PhotoMaster *) handle;
5517
5518 *widthPtr = masterPtr->width;
5519 *heightPtr = masterPtr->height;
5520 }
5521
5522 /*
5523 *----------------------------------------------------------------------
5524 *
5525 * Tk_PhotoSetSize --
5526 *
5527 * This function is called to set size of a photo image. This call is
5528 * equivalent to using the -width and -height configuration options.
5529 *
5530 * Results:
5531 * None.
5532 *
5533 * Side effects:
5534 * The size of the image may change; if so the generic image code is
5535 * informed.
5536 *
5537 *----------------------------------------------------------------------
5538 */
5539
5540 int
Tk_PhotoSetSize(Tcl_Interp * interp,Tk_PhotoHandle handle,int width,int height)5541 Tk_PhotoSetSize(
5542 Tcl_Interp *interp, /* Interpreter for passing back error
5543 * messages, or NULL. */
5544 Tk_PhotoHandle handle, /* Handle for the image whose size is to be
5545 * set. */
5546 int width, int height) /* New dimensions for the image. */
5547 {
5548 PhotoMaster *masterPtr = (PhotoMaster *) handle;
5549
5550 masterPtr->userWidth = width;
5551 masterPtr->userHeight = height;
5552 if (ImgPhotoSetSize(masterPtr, ((width > 0) ? width: masterPtr->width),
5553 ((height > 0) ? height: masterPtr->height)) == TCL_ERROR) {
5554 if (interp != NULL) {
5555 Tcl_ResetResult(interp);
5556 Tcl_AppendResult(interp, TK_PHOTO_ALLOC_FAILURE_MESSAGE, NULL);
5557 }
5558 return TCL_ERROR;
5559 }
5560 Tk_ImageChanged(masterPtr->tkMaster, 0, 0, 0, 0,
5561 masterPtr->width, masterPtr->height);
5562 return TCL_OK;
5563 }
5564
5565 /*
5566 *----------------------------------------------------------------------
5567 *
5568 * TkGetPhotoValidRegion --
5569 *
5570 * This function is called to get the part of the photo where there is
5571 * valid data. Or, conversely, the part of the photo which is
5572 * transparent.
5573 *
5574 * Results:
5575 * A TkRegion value that indicates the current area of the photo that is
5576 * valid. This value should not be used after any modification to the
5577 * photo image.
5578 *
5579 * Side Effects:
5580 * None.
5581 *
5582 *----------------------------------------------------------------------
5583 */
5584
5585 TkRegion
TkPhotoGetValidRegion(Tk_PhotoHandle handle)5586 TkPhotoGetValidRegion(
5587 Tk_PhotoHandle handle) /* Handle for the image whose valid region is
5588 * to obtained. */
5589 {
5590 PhotoMaster *masterPtr = (PhotoMaster *) handle;
5591
5592 return masterPtr->validRegion;
5593 }
5594
5595 /*
5596 *----------------------------------------------------------------------
5597 *
5598 * ImgGetPhoto --
5599 *
5600 * This function is called to obtain image data from a photo image. This
5601 * function fills in the Tk_PhotoImageBlock structure pointed to by
5602 * `blockPtr' with details of the address and layout of the image data in
5603 * memory.
5604 *
5605 * Results:
5606 * A pointer to the allocated data which should be freed later. NULL if
5607 * there is no need to free data because blockPtr->pixelPtr points
5608 * directly to the image data.
5609 *
5610 * Side effects:
5611 * None.
5612 *
5613 *----------------------------------------------------------------------
5614 */
5615
5616 static char *
ImgGetPhoto(PhotoMaster * masterPtr,Tk_PhotoImageBlock * blockPtr,struct SubcommandOptions * optPtr)5617 ImgGetPhoto(
5618 PhotoMaster *masterPtr, /* Handle for the photo image from which image
5619 * data is desired. */
5620 Tk_PhotoImageBlock *blockPtr,
5621 /* Information about the address and layout of
5622 * the image data is returned here. */
5623 struct SubcommandOptions *optPtr)
5624 {
5625 unsigned char *pixelPtr;
5626 int x, y, greenOffset, blueOffset, alphaOffset;
5627
5628 Tk_PhotoGetImage((Tk_PhotoHandle) masterPtr, blockPtr);
5629 blockPtr->pixelPtr += optPtr->fromY * blockPtr->pitch
5630 + optPtr->fromX * blockPtr->pixelSize;
5631 blockPtr->width = optPtr->fromX2 - optPtr->fromX;
5632 blockPtr->height = optPtr->fromY2 - optPtr->fromY;
5633
5634 if (!(masterPtr->flags & COLOR_IMAGE) &&
5635 (!(optPtr->options & OPT_BACKGROUND)
5636 || ((optPtr->background->red == optPtr->background->green)
5637 && (optPtr->background->red == optPtr->background->blue)))) {
5638 blockPtr->offset[0] = blockPtr->offset[1] = blockPtr->offset[2];
5639 }
5640 alphaOffset = 0;
5641 for (y = 0; y < blockPtr->height; y++) {
5642 pixelPtr = blockPtr->pixelPtr + (y * blockPtr->pitch)
5643 + blockPtr->pixelSize - 1;
5644 for (x = 0; x < blockPtr->width; x++) {
5645 if (*pixelPtr != 255) {
5646 alphaOffset = 3;
5647 break;
5648 }
5649 pixelPtr += blockPtr->pixelSize;
5650 }
5651 if (alphaOffset) {
5652 break;
5653 }
5654 }
5655 if (!alphaOffset) {
5656 blockPtr->offset[3]= -1; /* Tell caller alpha need not be read */
5657 }
5658 greenOffset = blockPtr->offset[1] - blockPtr->offset[0];
5659 blueOffset = blockPtr->offset[2] - blockPtr->offset[0];
5660 if (((optPtr->options & OPT_BACKGROUND) && alphaOffset) ||
5661 ((optPtr->options & OPT_GRAYSCALE) && (greenOffset||blueOffset))) {
5662 int newPixelSize,x,y;
5663 unsigned char *srcPtr, *destPtr;
5664 char *data;
5665
5666 newPixelSize = (!(optPtr->options & OPT_BACKGROUND) && alphaOffset)
5667 ? 2 : 1;
5668 if ((greenOffset||blueOffset) && !(optPtr->options & OPT_GRAYSCALE)) {
5669 newPixelSize += 2;
5670 }
5671 data = ckalloc((unsigned int) (newPixelSize *
5672 blockPtr->width * blockPtr->height));
5673 srcPtr = blockPtr->pixelPtr + blockPtr->offset[0];
5674 destPtr = (unsigned char *) data;
5675 if (!greenOffset && !blueOffset) {
5676 for (y = blockPtr->height; y > 0; y--) {
5677 for (x = blockPtr->width; x > 0; x--) {
5678 *destPtr = *srcPtr;
5679 srcPtr += blockPtr->pixelSize;
5680 destPtr += newPixelSize;
5681 }
5682 srcPtr += blockPtr->pitch -
5683 blockPtr->width * blockPtr->pixelSize;
5684 }
5685 } else if (optPtr->options & OPT_GRAYSCALE) {
5686 for (y = blockPtr->height; y > 0; y--) {
5687 for (x = blockPtr->width; x > 0; x--) {
5688 *destPtr = (unsigned char) ((srcPtr[0]*11 + srcPtr[1]*16
5689 + srcPtr[2]*5 + 16) >> 5);
5690 srcPtr += blockPtr->pixelSize;
5691 destPtr += newPixelSize;
5692 }
5693 srcPtr += blockPtr->pitch -
5694 blockPtr->width * blockPtr->pixelSize;
5695 }
5696 } else {
5697 for (y = blockPtr->height; y > 0; y--) {
5698 for (x = blockPtr->width; x > 0; x--) {
5699 destPtr[0] = srcPtr[0];
5700 destPtr[1] = srcPtr[1];
5701 destPtr[2] = srcPtr[2];
5702 srcPtr += blockPtr->pixelSize;
5703 destPtr += newPixelSize;
5704 }
5705 srcPtr += blockPtr->pitch -
5706 blockPtr->width * blockPtr->pixelSize;
5707 }
5708 }
5709 srcPtr = blockPtr->pixelPtr + alphaOffset;
5710 destPtr = (unsigned char *) data;
5711 if (!alphaOffset) {
5712 /*
5713 * Nothing to be done.
5714 */
5715 } else if (optPtr->options & OPT_BACKGROUND) {
5716 if (newPixelSize > 2) {
5717 int red = optPtr->background->red>>8;
5718 int green = optPtr->background->green>>8;
5719 int blue = optPtr->background->blue>>8;
5720
5721 for (y = blockPtr->height; y > 0; y--) {
5722 for (x = blockPtr->width; x > 0; x--) {
5723 destPtr[0] += (unsigned char) (((255 - *srcPtr) *
5724 (red-destPtr[0])) / 255);
5725 destPtr[1] += (unsigned char) (((255 - *srcPtr) *
5726 (green-destPtr[1])) / 255);
5727 destPtr[2] += (unsigned char) (((255 - *srcPtr) *
5728 (blue-destPtr[2])) / 255);
5729 srcPtr += blockPtr->pixelSize;
5730 destPtr += newPixelSize;
5731 }
5732 srcPtr += blockPtr->pitch -
5733 blockPtr->width * blockPtr->pixelSize;
5734 }
5735 } else {
5736 int gray = (unsigned char) (((optPtr->background->red>>8) * 11
5737 + (optPtr->background->green>>8) * 16
5738 + (optPtr->background->blue>>8) * 5 + 16) >> 5);
5739
5740 for (y = blockPtr->height; y > 0; y--) {
5741 for (x = blockPtr->width; x > 0; x--) {
5742 destPtr[0] += ((255 - *srcPtr) *
5743 (gray-destPtr[0])) / 255;
5744 srcPtr += blockPtr->pixelSize;
5745 destPtr += newPixelSize;
5746 }
5747 srcPtr += blockPtr->pitch -
5748 blockPtr->width * blockPtr->pixelSize;
5749 }
5750 }
5751 } else {
5752 destPtr += newPixelSize-1;
5753 for (y = blockPtr->height; y > 0; y--) {
5754 for (x = blockPtr->width; x > 0; x--) {
5755 *destPtr = *srcPtr;
5756 srcPtr += blockPtr->pixelSize;
5757 destPtr += newPixelSize;
5758 }
5759 srcPtr += blockPtr->pitch -
5760 blockPtr->width * blockPtr->pixelSize;
5761 }
5762 }
5763 blockPtr->pixelPtr = (unsigned char *) data;
5764 blockPtr->pixelSize = newPixelSize;
5765 blockPtr->pitch = newPixelSize * blockPtr->width;
5766 blockPtr->offset[0] = 0;
5767 if (newPixelSize>2) {
5768 blockPtr->offset[1]= 1;
5769 blockPtr->offset[2]= 2;
5770 blockPtr->offset[3]= 3;
5771 } else {
5772 blockPtr->offset[1]= 0;
5773 blockPtr->offset[2]= 0;
5774 blockPtr->offset[3]= 1;
5775 }
5776 return data;
5777 }
5778 return NULL;
5779 }
5780
5781 /*
5782 *----------------------------------------------------------------------
5783 *
5784 * ImgStringWrite --
5785 *
5786 * Default string write function. The data is formatted in the default
5787 * format as accepted by the "<img> put" command.
5788 *
5789 * Results:
5790 * A standard Tcl result.
5791 *
5792 * Side effects:
5793 * See the user documentation.
5794 *
5795 *----------------------------------------------------------------------
5796 */
5797
5798 static int
ImgStringWrite(Tcl_Interp * interp,Tcl_Obj * formatString,Tk_PhotoImageBlock * blockPtr)5799 ImgStringWrite(
5800 Tcl_Interp *interp,
5801 Tcl_Obj *formatString,
5802 Tk_PhotoImageBlock *blockPtr)
5803 {
5804 int row, col;
5805 char *line, *linePtr;
5806 unsigned char *pixelPtr;
5807 int greenOffset, blueOffset;
5808 Tcl_DString data;
5809
5810 greenOffset = blockPtr->offset[1] - blockPtr->offset[0];
5811 blueOffset = blockPtr->offset[2] - blockPtr->offset[0];
5812
5813 Tcl_DStringInit(&data);
5814 if ((blockPtr->width > 0) && (blockPtr->height > 0)) {
5815 line = (char *) ckalloc((unsigned int) ((8 * blockPtr->width) + 2));
5816 for (row=0; row<blockPtr->height; row++) {
5817 pixelPtr = blockPtr->pixelPtr + blockPtr->offset[0] +
5818 row * blockPtr->pitch;
5819 linePtr = line;
5820 for (col=0; col<blockPtr->width; col++) {
5821 sprintf(linePtr, " #%02x%02x%02x", *pixelPtr,
5822 pixelPtr[greenOffset], pixelPtr[blueOffset]);
5823 pixelPtr += blockPtr->pixelSize;
5824 linePtr += 8;
5825 }
5826 Tcl_DStringAppendElement(&data, line+1);
5827 }
5828 ckfree (line);
5829 }
5830 Tcl_DStringResult(interp, &data);
5831 return TCL_OK;
5832 }
5833
5834 /*
5835 *----------------------------------------------------------------------
5836 *
5837 * Tk_PhotoGetImage --
5838 *
5839 * This function is called to obtain image data from a photo image. This
5840 * function fills in the Tk_PhotoImageBlock structure pointed to by
5841 * `blockPtr' with details of the address and layout of the image data in
5842 * memory.
5843 *
5844 * Results:
5845 * TRUE (1) indicating that image data is available, for backwards
5846 * compatibility with the old photo widget.
5847 *
5848 * Side effects:
5849 * None.
5850 *
5851 *----------------------------------------------------------------------
5852 */
5853
5854 int
Tk_PhotoGetImage(Tk_PhotoHandle handle,Tk_PhotoImageBlock * blockPtr)5855 Tk_PhotoGetImage(
5856 Tk_PhotoHandle handle, /* Handle for the photo image from which image
5857 * data is desired. */
5858 Tk_PhotoImageBlock *blockPtr)
5859 /* Information about the address and layout of
5860 * the image data is returned here. */
5861 {
5862 PhotoMaster *masterPtr = (PhotoMaster *) handle;
5863
5864 blockPtr->pixelPtr = masterPtr->pix32;
5865 blockPtr->width = masterPtr->width;
5866 blockPtr->height = masterPtr->height;
5867 blockPtr->pitch = masterPtr->width * 4;
5868 blockPtr->pixelSize = 4;
5869 blockPtr->offset[0] = 0;
5870 blockPtr->offset[1] = 1;
5871 blockPtr->offset[2] = 2;
5872 blockPtr->offset[3] = 3;
5873 return 1;
5874 }
5875
5876 /*
5877 *----------------------------------------------------------------------
5878 *
5879 * PhotoOptionFind --
5880 *
5881 * Finds a specific Photo option.
5882 *
5883 * Results:
5884 * None.
5885 *
5886 * Side effects:
5887 * After commands are removed.
5888 *
5889 *----------------------------------------------------------------------
5890 */
5891
5892 typedef struct OptionAssocData {
5893 struct OptionAssocData *nextPtr;
5894 /* Pointer to next OptionAssocData. */
5895 Tcl_ObjCmdProc *command; /* Command associated with this option. */
5896 char name[1]; /* Name of option (remaining chars) */
5897 } OptionAssocData;
5898
5899 static Tcl_ObjCmdProc *
PhotoOptionFind(Tcl_Interp * interp,Tcl_Obj * obj)5900 PhotoOptionFind(
5901 Tcl_Interp *interp, /* Interpreter that is being deleted. */
5902 Tcl_Obj *obj) /* Name of option to be found. */
5903 {
5904 int length;
5905 char *name = Tcl_GetStringFromObj(obj, &length);
5906 char *prevname = NULL;
5907 Tcl_ObjCmdProc *proc = NULL;
5908 OptionAssocData *list = (OptionAssocData *) Tcl_GetAssocData(interp,
5909 "photoOption", NULL);
5910
5911 while (list != NULL) {
5912 if (strncmp(name, list->name, (unsigned) length) == 0) {
5913 if (proc != NULL) {
5914 Tcl_ResetResult(interp);
5915 Tcl_AppendResult(interp, "ambiguous option \"", name,
5916 "\": must be ", prevname, NULL);
5917 while (list->nextPtr != NULL) {
5918 Tcl_AppendResult(interp, prevname, ", ",NULL);
5919 list = list->nextPtr;
5920 prevname = list->name;
5921 }
5922 Tcl_AppendResult(interp, ", or", prevname, NULL);
5923 return NULL;
5924 }
5925 proc = list->command;
5926 prevname = list->name;
5927 }
5928 list = list->nextPtr;
5929 }
5930 if (proc != NULL) {
5931 Tcl_ResetResult(interp);
5932 }
5933 return proc;
5934 }
5935
5936 /*
5937 *----------------------------------------------------------------------
5938 *
5939 * PhotoOptionCleanupProc --
5940 *
5941 * This function is invoked whenever an interpreter is deleted to cleanup
5942 * the AssocData for "photoVisitor".
5943 *
5944 * Results:
5945 * None.
5946 *
5947 * Side effects:
5948 * Photo Visitor options are removed.
5949 *
5950 *----------------------------------------------------------------------
5951 */
5952
5953 static void
PhotoOptionCleanupProc(ClientData clientData,Tcl_Interp * interp)5954 PhotoOptionCleanupProc(
5955 ClientData clientData, /* Points to "photoVisitor" AssocData for the
5956 * interpreter. */
5957 Tcl_Interp *interp) /* Interpreter that is being deleted. */
5958 {
5959 OptionAssocData *list = (OptionAssocData *) clientData;
5960
5961 while (list != NULL) {
5962 register OptionAssocData *ptr;
5963
5964 list = (ptr = list)->nextPtr;
5965 ckfree((char *) ptr);
5966 }
5967 }
5968
5969 /*
5970 *--------------------------------------------------------------
5971 *
5972 * Tk_CreatePhotoOption --
5973 *
5974 * This function may be invoked to add a new kind of photo option to the
5975 * core photo command supported by Tk.
5976 *
5977 * Results:
5978 * None.
5979 *
5980 * Side effects:
5981 * From now on, the new option will be useable by the photo command.
5982 *
5983 *--------------------------------------------------------------
5984 */
5985
5986 MODULE_SCOPE void
Tk_CreatePhotoOption(Tcl_Interp * interp,CONST char * name,Tcl_ObjCmdProc * proc)5987 Tk_CreatePhotoOption(
5988 Tcl_Interp *interp, /* Interpreter. */
5989 CONST char *name, /* Option name. */
5990 Tcl_ObjCmdProc *proc) /* Function to execute command. */
5991 {
5992 OptionAssocData *typePtr2, *prevPtr, *ptr;
5993 OptionAssocData *list = (OptionAssocData *)
5994 Tcl_GetAssocData(interp, "photoOption", NULL);
5995
5996 /*
5997 * If there's already a photo option with the given name, remove it.
5998 */
5999
6000 for (typePtr2 = list, prevPtr = NULL; typePtr2 != NULL;
6001 prevPtr = typePtr2, typePtr2 = typePtr2->nextPtr) {
6002 if (strcmp(typePtr2->name, name) == 0) {
6003 if (prevPtr == NULL) {
6004 list = typePtr2->nextPtr;
6005 } else {
6006 prevPtr->nextPtr = typePtr2->nextPtr;
6007 }
6008 ckfree((char *) typePtr2);
6009 break;
6010 }
6011 }
6012 ptr = (OptionAssocData *) ckalloc(sizeof(OptionAssocData) + strlen(name));
6013 strcpy(&(ptr->name[0]), name);
6014 ptr->command = proc;
6015 ptr->nextPtr = list;
6016 Tcl_SetAssocData(interp, "photoOption", PhotoOptionCleanupProc,
6017 (ClientData) ptr);
6018 }
6019
6020 /*
6021 *--------------------------------------------------------------
6022 *
6023 * TkPostscriptPhoto --
6024 *
6025 * This function is called to output the contents of a photo image in
6026 * Postscript by calling the Tk_PostscriptPhoto function.
6027 *
6028 * Results:
6029 * Returns a standard Tcl return value.
6030 *
6031 * Side effects:
6032 * None.
6033 *
6034 *--------------------------------------------------------------
6035 */
6036
6037 static int
ImgPhotoPostscript(ClientData clientData,Tcl_Interp * interp,Tk_Window tkwin,Tk_PostscriptInfo psInfo,int x,int y,int width,int height,int prepass)6038 ImgPhotoPostscript(
6039 ClientData clientData, /* Handle for the photo image. */
6040 Tcl_Interp *interp, /* Interpreter. */
6041 Tk_Window tkwin, /* (unused) */
6042 Tk_PostscriptInfo psInfo, /* Postscript info. */
6043 int x, int y, /* First pixel to output. */
6044 int width, int height, /* Width and height of area. */
6045 int prepass) /* (unused) */
6046 {
6047 Tk_PhotoImageBlock block;
6048
6049 Tk_PhotoGetImage((Tk_PhotoHandle) clientData, &block);
6050 block.pixelPtr += y * block.pitch + x * block.pixelSize;
6051
6052 return Tk_PostscriptPhoto(interp, &block, psInfo, width, height);
6053 }
6054
6055 /*
6056 *----------------------------------------------------------------------
6057 *
6058 * Tk_PhotoPutBlock_NoComposite, Tk_PhotoPutZoomedBlock_NoComposite --
6059 *
6060 * These backward-compatability functions just exist to fill slots in stubs
6061 * table. For the behaviour of *_NoComposite, refer to the corresponding
6062 * function without the extra suffix, except that the compositing rule is
6063 * always "overlay" and the function always panics on memory-allocation
6064 * failure.
6065 *
6066 *----------------------------------------------------------------------
6067 */
6068
6069 void
Tk_PhotoPutBlock_NoComposite(Tk_PhotoHandle handle,Tk_PhotoImageBlock * blockPtr,int x,int y,int width,int height)6070 Tk_PhotoPutBlock_NoComposite(
6071 Tk_PhotoHandle handle,
6072 Tk_PhotoImageBlock *blockPtr,
6073 int x, int y, int width, int height)
6074 {
6075 if (Tk_PhotoPutBlock(NULL, handle, blockPtr, x, y, width, height,
6076 TK_PHOTO_COMPOSITE_OVERLAY) != TCL_OK) {
6077 Tcl_Panic(TK_PHOTO_ALLOC_FAILURE_MESSAGE);
6078 }
6079 }
6080
6081 void
Tk_PhotoPutZoomedBlock_NoComposite(Tk_PhotoHandle handle,Tk_PhotoImageBlock * blockPtr,int x,int y,int width,int height,int zoomX,int zoomY,int subsampleX,int subsampleY)6082 Tk_PhotoPutZoomedBlock_NoComposite(
6083 Tk_PhotoHandle handle,
6084 Tk_PhotoImageBlock *blockPtr,
6085 int x, int y, int width, int height,
6086 int zoomX, int zoomY, int subsampleX, int subsampleY)
6087 {
6088 if (Tk_PhotoPutZoomedBlock(NULL, handle, blockPtr, x, y, width, height,
6089 zoomX, zoomY, subsampleX, subsampleY,
6090 TK_PHOTO_COMPOSITE_OVERLAY) != TCL_OK) {
6091 Tcl_Panic(TK_PHOTO_ALLOC_FAILURE_MESSAGE);
6092 }
6093 }
6094
6095 /*
6096 *----------------------------------------------------------------------
6097 *
6098 * Tk_PhotoExpand_Panic, Tk_PhotoPutBlock_Panic,
6099 * Tk_PhotoPutZoomedBlock_Panic, Tk_PhotoSetSize_Panic
6100 *
6101 * Backward compatability functions for preserving the old behaviour (i.e.
6102 * panic on memory allocation failure) so that extensions do not need to be
6103 * significantly updated to take account of TIP #116. These call the new
6104 * interface (i.e. the interface without the extra suffix), but panic if an
6105 * error condition is returned.
6106 *
6107 *----------------------------------------------------------------------
6108 */
6109
6110 void
Tk_PhotoExpand_Panic(Tk_PhotoHandle handle,int width,int height)6111 Tk_PhotoExpand_Panic(
6112 Tk_PhotoHandle handle,
6113 int width, int height)
6114 {
6115 if (Tk_PhotoExpand(NULL, handle, width, height) != TCL_OK) {
6116 Tcl_Panic(TK_PHOTO_ALLOC_FAILURE_MESSAGE);
6117 }
6118 }
6119
6120 void
Tk_PhotoPutBlock_Panic(Tk_PhotoHandle handle,Tk_PhotoImageBlock * blockPtr,int x,int y,int width,int height,int compRule)6121 Tk_PhotoPutBlock_Panic(
6122 Tk_PhotoHandle handle,
6123 Tk_PhotoImageBlock *blockPtr,
6124 int x, int y, int width, int height, int compRule)
6125 {
6126 if (Tk_PhotoPutBlock(NULL, handle, blockPtr, x, y, width, height,
6127 compRule) != TCL_OK) {
6128 Tcl_Panic(TK_PHOTO_ALLOC_FAILURE_MESSAGE);
6129 }
6130 }
6131
6132 void
Tk_PhotoPutZoomedBlock_Panic(Tk_PhotoHandle handle,Tk_PhotoImageBlock * blockPtr,int x,int y,int width,int height,int zoomX,int zoomY,int subsampleX,int subsampleY,int compRule)6133 Tk_PhotoPutZoomedBlock_Panic(
6134 Tk_PhotoHandle handle, Tk_PhotoImageBlock *blockPtr,
6135 int x, int y, int width, int height,
6136 int zoomX, int zoomY, int subsampleX, int subsampleY,
6137 int compRule)
6138 {
6139 if (Tk_PhotoPutZoomedBlock(NULL, handle, blockPtr, x, y, width, height,
6140 zoomX, zoomY, subsampleX, subsampleY, compRule) != TCL_OK) {
6141 Tcl_Panic(TK_PHOTO_ALLOC_FAILURE_MESSAGE);
6142 }
6143 }
6144
6145 void
Tk_PhotoSetSize_Panic(Tk_PhotoHandle handle,int width,int height)6146 Tk_PhotoSetSize_Panic(
6147 Tk_PhotoHandle handle,
6148 int width, int height)
6149 {
6150 if (Tk_PhotoSetSize(NULL, handle, width, height) != TCL_OK) {
6151 Tcl_Panic(TK_PHOTO_ALLOC_FAILURE_MESSAGE);
6152 }
6153 }
6154
6155 /*
6156 * Local Variables:
6157 * mode: c
6158 * c-basic-offset: 4
6159 * fill-column: 78
6160 * End:
6161 */
6162