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