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