summaryrefslogtreecommitdiff
path: root/tk/generic/tkImgPhoto.c
diff options
context:
space:
mode:
Diffstat (limited to 'tk/generic/tkImgPhoto.c')
-rw-r--r--tk/generic/tkImgPhoto.c1285
1 files changed, 876 insertions, 409 deletions
diff --git a/tk/generic/tkImgPhoto.c b/tk/generic/tkImgPhoto.c
index 7416771041b..d2b0cb02711 100644
--- a/tk/generic/tkImgPhoto.c
+++ b/tk/generic/tkImgPhoto.c
@@ -7,6 +7,7 @@
*
* Copyright (c) 1994 The Australian National University.
* Copyright (c) 1994-1997 Sun Microsystems, Inc.
+ * Copyright (c) 2002 Donal K. Fellows
*
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
@@ -231,6 +232,7 @@ struct SubcommandOptions {
int subsampleX, subsampleY; /* Values specified for -subsample option. */
Tcl_Obj *format; /* Value specified for -format option. */
XColor *background; /* Value specified for -background option. */
+ int compositingRule; /* Value specified for -compositingrule opt */
};
/*
@@ -241,6 +243,7 @@ struct SubcommandOptions {
* field of the SubcommandOptions structure if that option was specified.
*
* OPT_BACKGROUND: Set if -format option allowed/specified.
+ * OPT_COMPOSITE: Set if -compositingrule option allowed/spec'd.
* OPT_FORMAT: Set if -format option allowed/specified.
* OPT_FROM: Set if -from option allowed/specified.
* OPT_GRAYSCALE: Set if -grayscale option allowed/specified.
@@ -251,13 +254,14 @@ struct SubcommandOptions {
*/
#define OPT_BACKGROUND 1
-#define OPT_FORMAT 2
-#define OPT_FROM 4
-#define OPT_GRAYSCALE 8
-#define OPT_SHRINK 0x10
-#define OPT_SUBSAMPLE 0x20
-#define OPT_TO 0x40
-#define OPT_ZOOM 0x80
+#define OPT_COMPOSITE 2
+#define OPT_FORMAT 4
+#define OPT_FROM 8
+#define OPT_GRAYSCALE 0x10
+#define OPT_SHRINK 0x20
+#define OPT_SUBSAMPLE 0x40
+#define OPT_TO 0x80
+#define OPT_ZOOM 0x100
/*
* List of option names. The order here must match the order of
@@ -266,6 +270,7 @@ struct SubcommandOptions {
static char *optionNames[] = {
"-background",
+ "-compositingrule",
"-format",
"-from",
"-grayscale",
@@ -277,7 +282,14 @@ static char *optionNames[] = {
};
/*
- * The type record for photo images:
+ * Message to generate when an attempt to resize an image fails due
+ * to memory problems.
+ */
+#define TK_PHOTO_ALLOC_FAILURE_MESSAGE \
+ "not enough free memory for image buffer"
+
+/*
+ * Functions used in the type record for photo images.
*/
static int ImgPhotoCreate _ANSI_ARGS_((Tcl_Interp *interp,
@@ -298,6 +310,10 @@ static int ImgPhotoPostscript _ANSI_ARGS_((ClientData clientData,
Tk_PostscriptInfo psInfo, int x, int y, int width,
int height, int prepass));
+/*
+ * The type record itself for photo images:
+ */
+
Tk_ImageType tkPhotoImageType = {
"photo", /* name */
ImgPhotoCreate, /* createProc */
@@ -314,6 +330,7 @@ typedef struct ThreadSpecificData {
* list of known photo image formats.*/
Tk_PhotoImageFormat *oldFormatList; /* Pointer to the first in the
* list of known photo image formats.*/
+ int initialized; /* set to 1 if we've initialized the strucuture */
} ThreadSpecificData;
static Tcl_ThreadDataKey dataKey;
@@ -357,6 +374,8 @@ static int imgPhotoColorHashInitialized;
* Forward declarations
*/
+static void PhotoFormatThreadExitProc _ANSI_ARGS_((
+ ClientData clientData));
static int ImgPhotoCmd _ANSI_ARGS_((ClientData clientData,
Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]));
static int ParseSubcommandOptions _ANSI_ARGS_((
@@ -370,7 +389,7 @@ static int ImgPhotoConfigureMaster _ANSI_ARGS_((
int objc, Tcl_Obj *CONST objv[], int flags));
static void ImgPhotoConfigureInstance _ANSI_ARGS_((
PhotoInstance *instancePtr));
-static void ImgPhotoSetSize _ANSI_ARGS_((PhotoMaster *masterPtr,
+static int ImgPhotoSetSize _ANSI_ARGS_((PhotoMaster *masterPtr,
int width, int height));
static void ImgPhotoInstanceSetSize _ANSI_ARGS_((
PhotoInstance *instancePtr));
@@ -381,7 +400,7 @@ static char * ImgGetPhoto _ANSI_ARGS_((PhotoMaster *masterPtr,
Tk_PhotoImageBlock *blockPtr,
struct SubcommandOptions *optPtr));
static int IsValidPalette _ANSI_ARGS_((PhotoInstance *instancePtr,
- char *palette));
+ CONST char *palette));
static int CountBits _ANSI_ARGS_((pixel mask));
static void GetColorTable _ANSI_ARGS_((PhotoInstance *instancePtr));
static void FreeColorTable _ANSI_ARGS_((ColorTable *colorPtr,
@@ -430,6 +449,48 @@ static void PhotoOptionCleanupProc _ANSI_ARGS_((
*
*----------------------------------------------------------------------
*/
+
+static void
+PhotoFormatThreadExitProc(clientData)
+ ClientData clientData; /* not used */
+{
+ Tk_PhotoImageFormat *freePtr;
+ ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
+ Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
+
+ while (tsdPtr->oldFormatList != NULL) {
+ freePtr = tsdPtr->oldFormatList;
+ tsdPtr->oldFormatList = tsdPtr->oldFormatList->nextPtr;
+ ckfree((char *) freePtr->name);
+ ckfree((char *) freePtr);
+ }
+ while (tsdPtr->formatList != NULL) {
+ freePtr = tsdPtr->formatList;
+ tsdPtr->formatList = tsdPtr->formatList->nextPtr;
+ ckfree((char *) freePtr->name);
+ ckfree((char *) freePtr);
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tk_CreateOldPhotoImageFormat, Tk_CreatePhotoImageFormat --
+ *
+ * This procedure is invoked by an image file handler to register
+ * a new photo image format and the procedures that handle the
+ * new format. The procedure is typically invoked during
+ * Tcl_AppInit.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * The new image file format is entered into a table used in the
+ * photo image "read" and "write" subcommands.
+ *
+ *----------------------------------------------------------------------
+ */
void
Tk_CreateOldPhotoImageFormat(formatPtr)
Tk_PhotoImageFormat *formatPtr;
@@ -442,6 +503,10 @@ Tk_CreateOldPhotoImageFormat(formatPtr)
ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
+ if (!tsdPtr->initialized) {
+ tsdPtr->initialized = 1;
+ Tcl_CreateThreadExitHandler(PhotoFormatThreadExitProc, NULL);
+ }
copyPtr = (Tk_PhotoImageFormat *) ckalloc(sizeof(Tk_PhotoImageFormat));
*copyPtr = *formatPtr;
copyPtr->name = (char *) ckalloc((unsigned) (strlen(formatPtr->name) + 1));
@@ -462,6 +527,10 @@ Tk_CreatePhotoImageFormat(formatPtr)
ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
+ if (!tsdPtr->initialized) {
+ tsdPtr->initialized = 1;
+ Tcl_CreateThreadExitHandler(PhotoFormatThreadExitProc, NULL);
+ }
copyPtr = (Tk_PhotoImageFormat *) ckalloc(sizeof(Tk_PhotoImageFormat));
*copyPtr = *formatPtr;
copyPtr->name = (char *) ckalloc((unsigned) (strlen(formatPtr->name) + 1));
@@ -563,13 +632,14 @@ ImgPhotoCmd(clientData, interp, objc, objv)
Tcl_Obj *CONST objv[]; /* Argument objects. */
{
int oldformat = 0;
- static char *photoOptions[] = {
+ static CONST char *photoOptions[] = {
"blank", "cget", "configure", "copy", "data", "get", "put",
- "read", "redither", "write", (char *) NULL
+ "read", "redither", "transparency", "write", (char *) NULL
};
enum options {
PHOTO_BLANK, PHOTO_CGET, PHOTO_CONFIGURE, PHOTO_COPY, PHOTO_DATA,
- PHOTO_GET, PHOTO_PUT, PHOTO_READ, PHOTO_REDITHER, PHOTO_WRITE
+ PHOTO_GET, PHOTO_PUT, PHOTO_READ, PHOTO_REDITHER, PHOTO_TRANS,
+ PHOTO_WRITE
};
PhotoMaster *masterPtr = (PhotoMaster *) clientData;
@@ -578,8 +648,8 @@ ImgPhotoCmd(clientData, interp, objc, objv)
int dataWidth, dataHeight;
struct SubcommandOptions options;
int listArgc;
- char **listArgv;
- char **srcArgv;
+ CONST char **listArgv;
+ CONST char **srcArgv;
unsigned char *pixelPtr;
Tk_PhotoImageBlock block;
Tk_Window tkwin;
@@ -607,8 +677,9 @@ ImgPhotoCmd(clientData, interp, objc, objv)
}
return proc(clientData, interp, objc, objv);
}
+
switch ((enum options) index) {
- case PHOTO_BLANK: {
+ case PHOTO_BLANK:
/*
* photo blank command - just call Tk_PhotoBlank.
*/
@@ -620,9 +691,10 @@ ImgPhotoCmd(clientData, interp, objc, objv)
return TCL_ERROR;
}
break;
- }
- case PHOTO_CGET: {
+
+ case PHOTO_CGET: {
char *arg;
+
if (objc != 3) {
Tcl_WrongNumArgs(interp, 2, objv, "option");
return TCL_ERROR;
@@ -643,12 +715,12 @@ ImgPhotoCmd(clientData, interp, objc, objv)
Tk_ConfigureValue(interp, Tk_MainWindow(interp), configSpecs,
(char *) masterPtr, Tcl_GetString(objv[2]), 0);
break;
- }
- case PHOTO_CONFIGURE: {
+ }
+
+ case PHOTO_CONFIGURE:
/*
* photo configure command - handle this in the standard way.
*/
- char *opt, *arg;
if (objc == 2) {
Tcl_Obj *obj, *subobj;
@@ -677,39 +749,38 @@ ImgPhotoCmd(clientData, interp, objc, objv)
return TCL_OK;
}
if (objc == 3) {
- char *arg = Tcl_GetStringFromObj(objv[2], (int *) &length);
- if (!strncmp(arg, "-data", length)) {
- Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
- "-data {} {} {}", (char *) NULL);
- if (masterPtr->dataString) {
- Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp),
- masterPtr->dataString);
- } else {
+ char *arg = Tcl_GetStringFromObj(objv[2], (int *) &length);
+ if (!strncmp(arg, "-data", length)) {
Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
- " {}", (char *) NULL);
- }
- return TCL_OK;
- } else if (!strncmp(arg, "-format", length)) {
- Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
- "-format {} {} {}", (char *) NULL);
- if (masterPtr->format) {
- Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp),
- masterPtr->format);
- } else {
+ "-data {} {} {}", (char *) NULL);
+ if (masterPtr->dataString) {
+ Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp),
+ masterPtr->dataString);
+ } else {
+ Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
+ " {}", (char *) NULL);
+ }
+ return TCL_OK;
+ } else if (!strncmp(arg, "-format", length)) {
Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
- " {}", (char *) NULL);
+ "-format {} {} {}", (char *) NULL);
+ if (masterPtr->format) {
+ Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp),
+ masterPtr->format);
+ } else {
+ Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
+ " {}", (char *) NULL);
+ }
+ return TCL_OK;
+ } else {
+ return Tk_ConfigureInfo(interp, Tk_MainWindow(interp),
+ configSpecs, (char *) masterPtr, arg, 0);
}
- return TCL_OK;
- } else {
- return Tk_ConfigureInfo(interp, Tk_MainWindow(interp),
- configSpecs, (char *) masterPtr, arg, 0);
- }
}
return ImgPhotoConfigureMaster(interp, masterPtr, objc-2, objv+2,
TK_CONFIG_ARGV_ONLY);
- break;
- }
- case PHOTO_COPY: {
+
+ case PHOTO_COPY:
/*
* photo copy command - first parse options.
*/
@@ -719,14 +790,15 @@ ImgPhotoCmd(clientData, interp, objc, objv)
options.zoomX = options.zoomY = 1;
options.subsampleX = options.subsampleY = 1;
options.name = NULL;
+ options.compositingRule = TK_PHOTO_COMPOSITE_OVERLAY;
if (ParseSubcommandOptions(&options, interp,
- OPT_FROM | OPT_TO | OPT_ZOOM | OPT_SUBSAMPLE | OPT_SHRINK,
- &index, objc, objv) != TCL_OK) {
+ OPT_FROM | OPT_TO | OPT_ZOOM | OPT_SUBSAMPLE | OPT_SHRINK |
+ OPT_COMPOSITE, &index, objc, objv) != TCL_OK) {
return TCL_ERROR;
}
if (options.name == NULL || index < objc) {
Tcl_WrongNumArgs(interp, 2, objv,
- "source-image ?-from x1 y1 x2 y2? ?-to x1 y1 x2 y2? ?-zoom x y? ?-subsample x y?");
+ "source-image ?-compositingrule rule? ?-from x1 y1 x2 y2? ?-to x1 y1 x2 y2? ?-zoom x y? ?-subsample x y?");
return TCL_ERROR;
}
@@ -735,7 +807,8 @@ ImgPhotoCmd(clientData, interp, objc, objv)
* Check the values given for the -from option.
*/
- if ((srcHandle = Tk_FindPhoto(interp, Tcl_GetString(options.name))) == NULL) {
+ srcHandle = Tk_FindPhoto(interp, Tcl_GetString(options.name));
+ if (srcHandle == NULL) {
Tcl_AppendResult(interp, "image \"",
Tcl_GetString(options.name), "\" doesn't",
" exist or is not a photo image", (char *) NULL);
@@ -754,11 +827,11 @@ ImgPhotoCmd(clientData, interp, objc, objv)
* Fill in default values for unspecified parameters.
*/
- if (((options.options & OPT_FROM) == 0) || (options.fromX2 < 0)) {
+ if (!(options.options & OPT_FROM) || (options.fromX2 < 0)) {
options.fromX2 = block.width;
options.fromY2 = block.height;
}
- if (((options.options & OPT_TO) == 0) || (options.toX2 < 0)) {
+ if (!(options.options & OPT_TO) || (options.toX2 < 0)) {
width = options.fromX2 - options.fromX;
if (options.subsampleX > 0) {
width = (width + options.subsampleX - 1) / options.subsampleX;
@@ -787,7 +860,13 @@ ImgPhotoCmd(clientData, interp, objc, objv)
*/
if (options.options & OPT_SHRINK) {
- ImgPhotoSetSize(masterPtr, options.toX2, options.toY2);
+ if (ImgPhotoSetSize(masterPtr, options.toX2,
+ options.toY2) != TCL_OK) {
+ Tcl_ResetResult(interp);
+ Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
+ TK_PHOTO_ALLOC_FAILURE_MESSAGE, (char *) NULL);
+ return TCL_ERROR;
+ }
}
/*
@@ -795,17 +874,18 @@ ImgPhotoCmd(clientData, interp, objc, objv)
*/
block.pixelPtr += options.fromX * block.pixelSize
- + options.fromY * block.pitch;
+ + options.fromY * block.pitch;
block.width = options.fromX2 - options.fromX;
block.height = options.fromY2 - options.fromY;
Tk_PhotoPutZoomedBlock((Tk_PhotoHandle) masterPtr, &block,
options.toX, options.toY, options.toX2 - options.toX,
options.toY2 - options.toY, options.zoomX, options.zoomY,
- options.subsampleX, options.subsampleY);
+ options.subsampleX, options.subsampleY,
+ options.compositingRule);
break;
- }
- case PHOTO_DATA: {
+
+ case PHOTO_DATA: {
char *data;
/*
@@ -878,7 +958,7 @@ ImgPhotoCmd(clientData, interp, objc, objv)
data = ImgGetPhoto(masterPtr, &block, &options);
- result = ((int (*) _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *formatString,
+ result = ((int (*) _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *formatString,
Tk_PhotoImageBlock *blockPtr, VOID *dummy))) stringWriteProc)
(interp, options.format, &block, (VOID *) NULL);
if (options.background) {
@@ -889,8 +969,9 @@ ImgPhotoCmd(clientData, interp, objc, objv)
}
return result;
break;
- }
- case PHOTO_GET: {
+ }
+
+ case PHOTO_GET: {
/*
* photo get command - first parse and check parameters.
*/
@@ -921,8 +1002,9 @@ ImgPhotoCmd(clientData, interp, objc, objv)
pixelPtr[2]);
Tcl_AppendResult(interp, string, (char *) NULL);
break;
- }
- case PHOTO_PUT: {
+ }
+
+ case PHOTO_PUT:
/*
* photo put command - first parse the options and colors specified.
*/
@@ -931,7 +1013,7 @@ ImgPhotoCmd(clientData, interp, objc, objv)
memset((VOID *) &options, 0, sizeof(options));
options.name = NULL;
if (ParseSubcommandOptions(&options, interp, OPT_TO|OPT_FORMAT,
- &index, objc, objv) != TCL_OK) {
+ &index, objc, objv) != TCL_OK) {
return TCL_ERROR;
}
if ((options.name == NULL) || (index < objc)) {
@@ -942,8 +1024,8 @@ ImgPhotoCmd(clientData, interp, objc, objv)
if (MatchStringFormat(interp, options.name ? objv[2]:NULL,
options.format, &imageFormat, &imageWidth,
&imageHeight, &oldformat) == TCL_OK) {
- Tcl_Obj *format;
- Tcl_Obj *data;
+ Tcl_Obj *format, *data;
+
if (((options.options & OPT_TO) == 0) || (options.toX2 < 0)) {
options.toX2 = options.toX + imageWidth;
options.toY2 = options.toY + imageHeight;
@@ -964,8 +1046,8 @@ ImgPhotoCmd(clientData, interp, objc, objv)
}
if ((*imageFormat->stringReadProc)(interp, data,
format, (Tk_PhotoHandle) masterPtr,
- 0, 0, imageWidth, imageHeight, options.toX, options.toY)
- != TCL_OK) {
+ options.toX, options.toY, imageWidth, imageHeight,
+ 0, 0) != TCL_OK) {
return TCL_ERROR;
}
masterPtr->flags |= IMAGE_CHANGED;
@@ -976,8 +1058,7 @@ ImgPhotoCmd(clientData, interp, objc, objv)
}
Tcl_ResetResult(interp);
if (Tcl_SplitList(interp, Tcl_GetString(options.name),
- &dataHeight, &srcArgv)
- != TCL_OK) {
+ &dataHeight, &srcArgv) != TCL_OK) {
return TCL_ERROR;
}
tkwin = Tk_MainWindow(interp);
@@ -991,17 +1072,14 @@ ImgPhotoCmd(clientData, interp, objc, objv)
}
if (y == 0) {
dataWidth = listArgc;
- pixelPtr = (unsigned char *) ckalloc((unsigned)
- dataWidth * dataHeight * 3);
+ pixelPtr = (unsigned char *)
+ ckalloc((unsigned) dataWidth * dataHeight * 3);
block.pixelPtr = pixelPtr;
- } else {
- if (listArgc != dataWidth) {
- Tcl_AppendResult(interp, "all elements of color list must",
- " have the same number of elements",
- (char *) NULL);
- ckfree((char *) listArgv);
- break;
- }
+ } else if (listArgc != dataWidth) {
+ Tcl_AppendResult(interp, "all elements of color list must",
+ " have the same number of elements", (char *) NULL);
+ ckfree((char *) listArgv);
+ break;
}
for (x = 0; x < dataWidth; ++x) {
if (!XParseColor(Tk_Display(tkwin), Tk_Colormap(tkwin),
@@ -1015,8 +1093,9 @@ ImgPhotoCmd(clientData, interp, objc, objv)
*pixelPtr++ = color.blue >> 8;
}
ckfree((char *) listArgv);
- if (x < dataWidth)
+ if (x < dataWidth) {
break;
+ }
}
ckfree((char *) srcArgv);
if (y < dataHeight || dataHeight == 0 || dataWidth == 0) {
@@ -1034,7 +1113,7 @@ ImgPhotoCmd(clientData, interp, objc, objv)
* copy the block in using Tk_PhotoPutBlock.
*/
- if (((options.options & OPT_TO) == 0) || (options.toX2 < 0)) {
+ if (!(options.options & OPT_TO) || (options.toX2 < 0)) {
options.toX2 = options.toX + dataWidth;
options.toY2 = options.toY + dataHeight;
}
@@ -1048,16 +1127,17 @@ ImgPhotoCmd(clientData, interp, objc, objv)
block.offset[3] = 0;
Tk_PhotoPutBlock((ClientData)masterPtr, &block,
options.toX, options.toY, options.toX2 - options.toX,
- options.toY2 - options.toY);
+ options.toY2 - options.toY, TK_PHOTO_COMPOSITE_SET);
ckfree((char *) block.pixelPtr);
break;
- }
- case PHOTO_READ: {
+
+ case PHOTO_READ: {
+ Tcl_Obj *format;
+
/*
* photo read command - first parse the options specified.
*/
- Tcl_Obj *format;
index = 2;
memset((VOID *) &options, 0, sizeof(options));
options.name = NULL;
@@ -1068,8 +1148,7 @@ ImgPhotoCmd(clientData, interp, objc, objv)
return TCL_ERROR;
}
if ((options.name == NULL) || (index < objc)) {
- Tcl_WrongNumArgs(interp, 2, objv,
- "fileName ?options?");
+ Tcl_WrongNumArgs(interp, 2, objv, "fileName ?options?");
return TCL_ERROR;
}
@@ -1079,7 +1158,7 @@ ImgPhotoCmd(clientData, interp, objc, objv)
if (Tcl_IsSafe(interp)) {
Tcl_AppendResult(interp, "can't get image from a file in a",
- " safe interpreter", (char *) NULL);
+ " safe interpreter", (char *) NULL);
return TCL_ERROR;
}
@@ -1094,16 +1173,18 @@ ImgPhotoCmd(clientData, interp, objc, objv)
}
if (Tcl_SetChannelOption(interp, chan, "-translation", "binary")
!= TCL_OK) {
+ Tcl_Close(NULL, chan);
return TCL_ERROR;
}
if (Tcl_SetChannelOption(interp, chan, "-encoding", "binary")
!= TCL_OK) {
+ Tcl_Close(NULL, chan);
return TCL_ERROR;
}
if (MatchFileFormat(interp, chan,
- Tcl_GetString(options.name), options.format,
- &imageFormat, &imageWidth, &imageHeight, &oldformat) != TCL_OK) {
+ Tcl_GetString(options.name), options.format, &imageFormat,
+ &imageWidth, &imageHeight, &oldformat) != TCL_OK) {
Tcl_Close(NULL, chan);
return TCL_ERROR;
}
@@ -1133,8 +1214,13 @@ ImgPhotoCmd(clientData, interp, objc, objv)
*/
if (options.options & OPT_SHRINK) {
- ImgPhotoSetSize(masterPtr, options.toX + width,
- options.toY + height);
+ if (ImgPhotoSetSize(masterPtr, options.toX + width,
+ options.toY + height) != TCL_OK) {
+ Tcl_ResetResult(interp);
+ Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
+ TK_PHOTO_ALLOC_FAILURE_MESSAGE, (char *) NULL);
+ return TCL_ERROR;
+ }
}
/*
@@ -1155,42 +1241,163 @@ ImgPhotoCmd(clientData, interp, objc, objv)
}
return result;
break;
- }
- case PHOTO_REDITHER: {
- if (objc == 2) {
+ }
+
+ case PHOTO_REDITHER:
+ if (objc != 2) {
+ Tcl_WrongNumArgs(interp, 2, objv, (char *) NULL);
+ return TCL_ERROR;
+ }
+
+ /*
+ * Call Dither if any part of the image is not correctly
+ * dithered at present.
+ */
+
+ x = masterPtr->ditherX;
+ y = masterPtr->ditherY;
+ if (masterPtr->ditherX != 0) {
+ Tk_DitherPhoto((Tk_PhotoHandle) masterPtr, x, y,
+ masterPtr->width - x, 1);
+ }
+ if (masterPtr->ditherY < masterPtr->height) {
+ x = 0;
+ Tk_DitherPhoto((Tk_PhotoHandle)masterPtr, 0,
+ masterPtr->ditherY, masterPtr->width,
+ masterPtr->height - masterPtr->ditherY);
+ }
+
+ if (y < masterPtr->height) {
/*
- * Call Dither if any part of the image is not correctly
- * dithered at present.
+ * Tell the core image code that part of the image has changed.
*/
- x = masterPtr->ditherX;
- y = masterPtr->ditherY;
- if (masterPtr->ditherX != 0) {
- Tk_DitherPhoto((Tk_PhotoHandle) masterPtr, x, y, masterPtr->width - x, 1);
+ Tk_ImageChanged(masterPtr->tkMaster, x, y,
+ (masterPtr->width - x), (masterPtr->height - y),
+ masterPtr->width, masterPtr->height);
+ }
+ break;
+
+ case PHOTO_TRANS: {
+ static CONST char *photoTransOptions[] = {
+ "get", "set", (char *) NULL
+ };
+ enum transOptions {
+ PHOTO_TRANS_GET, PHOTO_TRANS_SET
+ };
+
+ if (objc < 3) {
+ Tcl_WrongNumArgs(interp, 2, objv, "option ?arg arg ...?");
+ return TCL_ERROR;
+ }
+ if (Tcl_GetIndexFromObj(interp, objv[2], photoTransOptions, "option",
+ 0, &index) != TCL_OK) {
+ return TCL_ERROR;
+ }
+
+ switch ((enum transOptions) index) {
+ case PHOTO_TRANS_GET: {
+ XRectangle testBox;
+ TkRegion testRegion;
+
+ if (objc != 5) {
+ Tcl_WrongNumArgs(interp, 3, objv, "x y");
+ return TCL_ERROR;
+ }
+ if ((Tcl_GetIntFromObj(interp, objv[3], &x) != TCL_OK)
+ || (Tcl_GetIntFromObj(interp, objv[4], &y) != TCL_OK)) {
+ return TCL_ERROR;
+ }
+ if ((x < 0) || (x >= masterPtr->width)
+ || (y < 0) || (y >= masterPtr->height)) {
+ Tcl_AppendResult(interp, Tcl_GetString(objv[0]),
+ " transparency get: coordinates out of range",
+ (char *) NULL);
+ return TCL_ERROR;
+ }
+
+ testBox.x = x;
+ testBox.y = y;
+ testBox.width = 1;
+ testBox.height = 1;
+ /* What a way to do a test! */
+ testRegion = TkCreateRegion();
+ TkUnionRectWithRegion(&testBox, testRegion, testRegion);
+ TkIntersectRegion(testRegion, masterPtr->validRegion, testRegion);
+ TkClipBox(testRegion, &testBox);
+ TkDestroyRegion(testRegion);
+
+ Tcl_SetBooleanObj(Tcl_GetObjResult(interp),
+ (testBox.width==0 && testBox.height==0));
+ return TCL_OK;
+ }
+
+ case PHOTO_TRANS_SET: {
+ int transFlag;
+ XRectangle setBox;
+
+ if (objc != 6) {
+ Tcl_WrongNumArgs(interp, 3, objv, "x y boolean");
+ return TCL_ERROR;
+ }
+ if ((Tcl_GetIntFromObj(interp, objv[3], &x) != TCL_OK)
+ || (Tcl_GetIntFromObj(interp, objv[4], &y) != TCL_OK)
+ || (Tcl_GetBooleanFromObj(interp, objv[5],
+ &transFlag) != TCL_OK)) {
+ return TCL_ERROR;
}
- if (masterPtr->ditherY < masterPtr->height) {
- x = 0;
- Tk_DitherPhoto((Tk_PhotoHandle)masterPtr, 0, masterPtr->ditherY, masterPtr->width,
- masterPtr->height - masterPtr->ditherY);
+ if ((x < 0) || (x >= masterPtr->width)
+ || (y < 0) || (y >= masterPtr->height)) {
+ Tcl_AppendResult(interp, Tcl_GetString(objv[0]),
+ " transparency set: coordinates out of range",
+ (char *) NULL);
+ return TCL_ERROR;
}
- if (y < masterPtr->height) {
+ setBox.x = x;
+ setBox.y = y;
+ setBox.width = 1;
+ setBox.height = 1;
+ pixelPtr = masterPtr->pix24 + (y * masterPtr->width + x) * 4;
+
+ if (transFlag) {
/*
- * Tell the core image code that part of the image has changed.
+ * Make pixel transparent.
*/
+ TkRegion clearRegion = TkCreateRegion();
- Tk_ImageChanged(masterPtr->tkMaster, x, y,
- (masterPtr->width - x), (masterPtr->height - y),
- masterPtr->width, masterPtr->height);
+ TkUnionRectWithRegion(&setBox, clearRegion, clearRegion);
+ TkSubtractRegion(masterPtr->validRegion, clearRegion,
+ masterPtr->validRegion);
+ TkDestroyRegion(clearRegion);
+ /*
+ * Set the alpha value correctly.
+ */
+ pixelPtr[3] = 0;
+ } else {
+ /*
+ * Make pixel opaque.
+ */
+ TkUnionRectWithRegion(&setBox, masterPtr->validRegion,
+ masterPtr->validRegion);
+ pixelPtr[3] = 255;
}
- } else {
- Tcl_WrongNumArgs(interp, 2, objv, (char *) NULL);
- return TCL_ERROR;
+ /*
+ * Inform the generic image code that the image
+ * has (potentially) changed.
+ */
+
+ Tk_ImageChanged(masterPtr->tkMaster, x, y, 1, 1,
+ masterPtr->width, masterPtr->height);
+ masterPtr->flags &= ~IMAGE_CHANGED;
}
- break;
- }
- case PHOTO_WRITE: {
+
+ }
+ return TCL_OK;
+ }
+
+ case PHOTO_WRITE: {
char *data;
Tcl_Obj *format;
@@ -1200,7 +1407,7 @@ ImgPhotoCmd(clientData, interp, objc, objv)
if (Tcl_IsSafe(interp)) {
Tcl_AppendResult(interp, "can't write image to a file in a",
- " safe interpreter", (char *) NULL);
+ " safe interpreter", (char *) NULL);
return TCL_ERROR;
}
@@ -1234,7 +1441,7 @@ ImgPhotoCmd(clientData, interp, objc, objv)
* Fill in default values for unspecified parameters.
*/
- if (((options.options & OPT_FROM) == 0) || (options.fromX2 < 0)) {
+ if (!(options.options & OPT_FROM) || (options.fromX2 < 0)) {
options.fromX2 = masterPtr->width;
options.fromY2 = masterPtr->height;
}
@@ -1246,7 +1453,7 @@ ImgPhotoCmd(clientData, interp, objc, objv)
matched = 0;
for (imageFormat = tsdPtr->formatList; imageFormat != NULL;
- imageFormat = imageFormat->nextPtr) {
+ imageFormat = imageFormat->nextPtr) {
if ((options.format == NULL)
|| (strncasecmp(Tcl_GetString(options.format),
imageFormat->name, strlen(imageFormat->name)) == 0)) {
@@ -1257,18 +1464,18 @@ ImgPhotoCmd(clientData, interp, objc, objv)
}
}
if (imageFormat == NULL) {
- oldformat = 1;
- for (imageFormat = tsdPtr->oldFormatList; imageFormat != NULL;
- imageFormat = imageFormat->nextPtr) {
- if ((options.format == NULL)
- || (strncasecmp(Tcl_GetString(options.format),
- imageFormat->name, strlen(imageFormat->name)) == 0)) {
- matched = 1;
- if (imageFormat->fileWriteProc != NULL) {
- break;
+ oldformat = 1;
+ for (imageFormat = tsdPtr->oldFormatList; imageFormat != NULL;
+ imageFormat = imageFormat->nextPtr) {
+ if ((options.format == NULL)
+ || (strncasecmp(Tcl_GetString(options.format),
+ imageFormat->name, strlen(imageFormat->name)) == 0)) {
+ matched = 1;
+ if (imageFormat->fileWriteProc != NULL) {
+ break;
+ }
}
}
- }
}
if (imageFormat == NULL) {
if (options.format == NULL) {
@@ -1298,8 +1505,7 @@ ImgPhotoCmd(clientData, interp, objc, objv)
format = (Tcl_Obj *) Tcl_GetString(options.format);
}
result = (*imageFormat->fileWriteProc)(interp,
- Tcl_GetString(options.name),
- format, &block);
+ Tcl_GetString(options.name), format, &block);
if (options.background) {
Tk_FreeColor(options.background);
}
@@ -1307,10 +1513,9 @@ ImgPhotoCmd(clientData, interp, objc, objv)
ckfree(data);
}
return result;
- break;
- }
}
+ }
return TCL_OK;
}
@@ -1321,7 +1526,8 @@ ImgPhotoCmd(clientData, interp, objc, objv)
*
* This procedure is invoked to process one of the options
* which may be specified for the photo image subcommands,
- * namely, -from, -to, -zoom, -subsample, -format, and -shrink.
+ * namely, -from, -to, -zoom, -subsample, -format, -shrink,
+ * and -compositingrule.
*
* Results:
* A standard Tcl result.
@@ -1436,7 +1642,9 @@ ParseSubcommandOptions(optPtr, interp, allowedOptions, optIndexPtr, objc, objv)
}
} else if (bit == OPT_FORMAT) {
/*
- * The -format option takes a single string value.
+ * The -format option takes a single string value. Note
+ * that parsing this is outside the scope of this
+ * function.
*/
if (index + 1 < objc) {
@@ -1447,6 +1655,34 @@ ParseSubcommandOptions(optPtr, interp, allowedOptions, optIndexPtr, objc, objv)
"requires a value", (char *) NULL);
return TCL_ERROR;
}
+ } else if (bit == OPT_COMPOSITE) {
+ /*
+ * The -compositingrule option takes a single value from
+ * a well-known set.
+ */
+
+ if (index + 1 < objc) {
+ /*
+ * Note that these must match the TK_PHOTO_COMPOSITE_*
+ * constants.
+ */
+ static CONST char *compositingRules[] = {
+ "overlay", "set",
+ NULL
+ };
+
+ index++;
+ if (Tcl_GetIndexFromObj(interp, objv[index], compositingRules,
+ "compositing rule", 0, &optPtr->compositingRule)
+ != TCL_OK) {
+ return TCL_ERROR;
+ }
+ *optIndexPtr = index;
+ } else {
+ Tcl_AppendResult(interp, "the \"-compositingrule\" option ",
+ "requires a value", (char *) NULL);
+ return TCL_ERROR;
+ }
} else if ((bit != OPT_SHRINK) && (bit != OPT_GRAYSCALE)) {
char *val;
maxValues = ((bit == OPT_FROM) || (bit == OPT_TO))? 4: 2;
@@ -1588,7 +1824,7 @@ ImgPhotoConfigureMaster(interp, masterPtr, objc, objv, flags)
* such as TK_CONFIG_ARGV_ONLY. */
{
PhotoInstance *instancePtr;
- char *oldFileString, *oldPaletteString;
+ CONST char *oldFileString, *oldPaletteString;
Tcl_Obj *oldData, *data = NULL, *oldFormat, *format = NULL;
int length, i, j;
double oldGamma;
@@ -1596,11 +1832,11 @@ ImgPhotoConfigureMaster(interp, masterPtr, objc, objv, flags)
Tcl_Channel chan;
Tk_PhotoImageFormat *imageFormat;
int imageWidth, imageHeight;
- char **args;
+ CONST char **args;
int oldformat;
Tcl_Obj *tempdata, *tempformat;
- args = (char **) ckalloc((objc + 1) * sizeof(char *));
+ args = (CONST char **) ckalloc((objc + 1) * sizeof(char *));
for (i = 0, j = 0; i < objc; i++,j++) {
args[j] = Tcl_GetStringFromObj(objv[i], &length);
if ((length > 1) && (args[j][0] == '-')) {
@@ -1630,8 +1866,18 @@ ImgPhotoConfigureMaster(interp, masterPtr, objc, objv, flags)
*/
oldFileString = masterPtr->fileString;
- oldData = (oldFileString == NULL) ? masterPtr->dataString: NULL;
+ if (oldFileString == NULL) {
+ oldData = masterPtr->dataString;
+ if (oldData != NULL) {
+ Tcl_IncrRefCount(oldData);
+ }
+ } else {
+ oldData = NULL;
+ }
oldFormat = masterPtr->format;
+ if (oldFormat != NULL) {
+ Tcl_IncrRefCount(oldFormat);
+ }
oldPaletteString = masterPtr->palette;
oldGamma = masterPtr->gamma;
@@ -1642,7 +1888,7 @@ ImgPhotoConfigureMaster(interp, masterPtr, objc, objv, flags)
if (Tk_ConfigureWidget(interp, Tk_MainWindow(interp), configSpecs,
j, args, (char *) masterPtr, flags) != TCL_OK) {
ckfree((char *) args);
- return TCL_ERROR;
+ goto errorExit;
}
ckfree((char *) args);
@@ -1684,7 +1930,13 @@ ImgPhotoConfigureMaster(interp, masterPtr, objc, objv, flags)
* and make sure storage is correctly allocated for this image.
*/
- ImgPhotoSetSize(masterPtr, masterPtr->width, masterPtr->height);
+ if (ImgPhotoSetSize(masterPtr, masterPtr->width,
+ masterPtr->height) != TCL_OK) {
+ Tcl_ResetResult(interp);
+ Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
+ TK_PHOTO_ALLOC_FAILURE_MESSAGE, (char *) NULL);
+ goto errorExit;
+ }
/*
* Read in the image from the file or string if the user has
@@ -1700,30 +1952,36 @@ ImgPhotoConfigureMaster(interp, masterPtr, objc, objv, flags)
*/
if (Tcl_IsSafe(interp)) {
- Tcl_AppendResult(interp, "can't get image from a file in a",
- " safe interpreter", (char *) NULL);
- return TCL_ERROR;
+ Tcl_ResetResult(interp);
+ Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
+ "can't get image from a file in a safe interpreter",
+ (char *) NULL);
+ goto errorExit;
}
chan = Tcl_OpenFileChannel(interp, masterPtr->fileString, "r", 0);
if (chan == NULL) {
- return TCL_ERROR;
+ goto errorExit;
}
- if (Tcl_SetChannelOption(interp, chan, "-translation", "binary")
- != TCL_OK) {
- return TCL_ERROR;
- }
- if (Tcl_SetChannelOption(interp, chan, "-encoding", "binary")
- != TCL_OK) {
- return TCL_ERROR;
- }
- if (MatchFileFormat(interp, chan, masterPtr->fileString,
- masterPtr->format, &imageFormat, &imageWidth,
- &imageHeight, &oldformat) != TCL_OK) {
+ /*
+ * -translation binary also sets -encoding binary
+ */
+ if ((Tcl_SetChannelOption(interp, chan,
+ "-translation", "binary") != TCL_OK) ||
+ (MatchFileFormat(interp, chan, masterPtr->fileString,
+ masterPtr->format, &imageFormat, &imageWidth,
+ &imageHeight, &oldformat) != TCL_OK)) {
Tcl_Close(NULL, chan);
- return TCL_ERROR;
+ goto errorExit;
+ }
+ result = ImgPhotoSetSize(masterPtr, imageWidth, imageHeight);
+ if (result != TCL_OK) {
+ Tcl_Close(NULL, chan);
+ Tcl_ResetResult(interp);
+ Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
+ TK_PHOTO_ALLOC_FAILURE_MESSAGE, (char *) NULL);
+ goto errorExit;
}
- ImgPhotoSetSize(masterPtr, imageWidth, imageHeight);
tempformat = masterPtr->format;
if (oldformat && tempformat) {
tempformat = (Tcl_Obj *) Tcl_GetString(tempformat);
@@ -1734,7 +1992,7 @@ ImgPhotoConfigureMaster(interp, masterPtr, objc, objv, flags)
imageWidth, imageHeight, 0, 0);
Tcl_Close(NULL, chan);
if (result != TCL_OK) {
- return TCL_ERROR;
+ goto errorExit;
}
Tcl_ResetResult(interp);
@@ -1743,14 +2001,19 @@ ImgPhotoConfigureMaster(interp, masterPtr, objc, objv, flags)
if ((masterPtr->fileString == NULL) && (masterPtr->dataString != NULL)
&& ((masterPtr->dataString != oldData)
- || (masterPtr->format != oldFormat))) {
+ || (masterPtr->format != oldFormat))) {
- if (MatchStringFormat(interp, masterPtr->dataString,
+ if (MatchStringFormat(interp, masterPtr->dataString,
masterPtr->format, &imageFormat, &imageWidth,
&imageHeight, &oldformat) != TCL_OK) {
- return TCL_ERROR;
+ goto errorExit;
+ }
+ if (ImgPhotoSetSize(masterPtr, imageWidth, imageHeight) != TCL_OK) {
+ Tcl_ResetResult(interp);
+ Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
+ TK_PHOTO_ALLOC_FAILURE_MESSAGE, (char *) NULL);
+ goto errorExit;
}
- ImgPhotoSetSize(masterPtr, imageWidth, imageHeight);
tempformat = masterPtr->format;
tempdata = masterPtr->dataString;
if (oldformat) {
@@ -1762,7 +2025,7 @@ ImgPhotoConfigureMaster(interp, masterPtr, objc, objv, flags)
if ((*imageFormat->stringReadProc)(interp, tempdata,
tempformat, (Tk_PhotoHandle) masterPtr,
0, 0, imageWidth, imageHeight, 0, 0) != TCL_OK) {
- return TCL_ERROR;
+ goto errorExit;
}
Tcl_ResetResult(interp);
@@ -1802,7 +2065,22 @@ ImgPhotoConfigureMaster(interp, masterPtr, objc, objv, flags)
masterPtr->height, masterPtr->width, masterPtr->height);
masterPtr->flags &= ~IMAGE_CHANGED;
+ if (oldData != NULL) {
+ Tcl_DecrRefCount(oldData);
+ }
+ if (oldFormat != NULL) {
+ Tcl_DecrRefCount(oldFormat);
+ }
return TCL_OK;
+
+ errorExit:
+ if (oldData != NULL) {
+ Tcl_DecrRefCount(oldData);
+ }
+ if (oldFormat != NULL) {
+ Tcl_DecrRefCount(oldFormat);
+ }
+ return TCL_ERROR;
}
/*
@@ -1900,6 +2178,8 @@ ImgPhotoConfigureInstance(instancePtr)
* to byte-swap any 16 or 32 bit values that we store in the
* image in those situations where the server's endianness
* is different from ours.
+ *
+ * Can't we use autoconf to figure this out?
*/
if (imagePtr != NULL) {
@@ -1977,7 +2257,6 @@ ImgPhotoGet(tkwin, masterData)
Colormap colormap;
int mono, nRed, nGreen, nBlue;
XVisualInfo visualInfo, *visInfoPtr;
- XRectangle validBox;
char buf[TCL_INTEGER_SPACE * 3];
int numVisuals;
XColor *white, *black;
@@ -2121,8 +2400,10 @@ ImgPhotoGet(tkwin, masterData)
gcValues.graphics_exposures = False;
instancePtr->gc = Tk_GetGC(tkwin,
GCForeground|GCBackground|GCGraphicsExposures, &gcValues);
+
/*
* Set configuration options and finish the initialization of the instance.
+ * This will also dither the image if necessary.
*/
ImgPhotoConfigureInstance(instancePtr);
@@ -2136,16 +2417,6 @@ ImgPhotoGet(tkwin, masterData)
masterPtr->width, masterPtr->height);
}
- /*
- * Dither the image to fill in this instance's pixmap.
- */
-
- TkClipBox(masterPtr->validRegion, &validBox);
- if ((validBox.width > 0) && (validBox.height > 0)) {
- DitherInstance(instancePtr, validBox.x, validBox.y, validBox.width,
- validBox.height);
- }
-
return (ClientData) instancePtr;
}
@@ -2346,7 +2617,8 @@ ImgPhotoCmdDeletedProc(clientData)
* image's size to `width' x `height' pixels.
*
* Results:
- * None.
+ * TCL_OK if successful, TCL_ERROR if failure occurred (currently
+ * just with memory allocation.)
*
* Side effects:
* Storage gets reallocated, for the master and all its instances.
@@ -2354,12 +2626,12 @@ ImgPhotoCmdDeletedProc(clientData)
*----------------------------------------------------------------------
*/
-static void
+static int
ImgPhotoSetSize(masterPtr, width, height)
PhotoMaster *masterPtr;
int width, height;
{
- unsigned char *newPix24;
+ unsigned char *newPix24 = NULL;
int h, offset, pitch;
unsigned char *srcPtr, *destPtr;
XRectangle validBox, clipBox;
@@ -2373,6 +2645,21 @@ ImgPhotoSetSize(masterPtr, width, height)
height = masterPtr->userHeight;
}
+ pitch = width * 4;
+
+ /*
+ * Test if we're going to (re)allocate the main buffer now, so
+ * that any failures will leave the photo unchanged.
+ */
+ if ((width != masterPtr->width) || (height != masterPtr->height)
+ || (masterPtr->pix24 == NULL)) {
+ newPix24 = (unsigned char *)
+ attemptckalloc((unsigned) (height * pitch));
+ if (newPix24 == NULL) {
+ return TCL_ERROR;
+ }
+ }
+
/*
* We have to trim the valid region if it is currently
* larger than the new image size.
@@ -2393,17 +2680,12 @@ ImgPhotoSetSize(masterPtr, width, height)
TkClipBox(masterPtr->validRegion, &validBox);
}
- if ((width != masterPtr->width) || (height != masterPtr->height)
- || (masterPtr->pix24 == NULL)) {
-
- /*
- * Reallocate storage for the 24-bit image and copy
- * over valid regions.
- */
-
- pitch = width * 4;
- newPix24 = (unsigned char *) ckalloc((unsigned) (height * pitch));
-
+ /*
+ * Use the reallocated storage (allocation above) for the 24-bit
+ * image and copy over valid regions. Note that this test is true
+ * precisely when the allocation has already been done.
+ */
+ if (newPix24 != NULL) {
/*
* Zero the new array. The dithering code shouldn't read the
* areas outside validBox, but they might be copied to another
@@ -2479,12 +2761,10 @@ ImgPhotoSetSize(masterPtr, width, height)
masterPtr->ditherX = 0;
masterPtr->ditherY = validBox.height;
}
- } else {
- if ((masterPtr->ditherY > 0)
- || ((int) validBox.width < masterPtr->ditherX)) {
- masterPtr->ditherX = validBox.width;
- masterPtr->ditherY = 0;
- }
+ } else if ((masterPtr->ditherY > 0)
+ || ((int) validBox.width < masterPtr->ditherX)) {
+ masterPtr->ditherX = validBox.width;
+ masterPtr->ditherY = 0;
}
}
@@ -2496,6 +2776,8 @@ ImgPhotoSetSize(masterPtr, width, height)
instancePtr = instancePtr->nextPtr) {
ImgPhotoInstanceSetSize(instancePtr);
}
+
+ return TCL_OK;
}
/*
@@ -2540,6 +2822,10 @@ ImgPhotoInstanceSetSize(instancePtr)
(masterPtr->width > 0) ? masterPtr->width: 1,
(masterPtr->height > 0) ? masterPtr->height: 1,
instancePtr->visualInfo.depth);
+ if (!newPixmap) {
+ panic("Fail to create pixmap with Tk_GetPixmap in ImgPhotoInstanceSetSize.\n");
+ return;
+ }
/*
* The following is a gross hack needed to properly support colormaps
@@ -2654,7 +2940,7 @@ static int
IsValidPalette(instancePtr, palette)
PhotoInstance *instancePtr; /* Instance to which the palette
* specification is to be applied. */
- char *palette; /* Palette specification string. */
+ CONST char *palette; /* Palette specification string. */
{
int nRed, nGreen, nBlue, mono, numColors;
char *endp;
@@ -2932,7 +3218,6 @@ AllocateColors(colorPtr)
* shades of each primary.
*/
- nRed = nGreen = nBlue = 0;
mono = sscanf(colorPtr->id.palette, "%d/%d/%d", &nRed, &nGreen, &nBlue)
<= 1;
igam = 1.0 / colorPtr->id.gamma;
@@ -3436,7 +3721,7 @@ MatchFileFormat(interp, chan, fileName, formatObj, imageFormatPtr,
}
}
if (formatPtr->fileMatchProc != NULL) {
- (void) Tcl_Seek(chan, 0L, SEEK_SET);
+ (void) Tcl_Seek(chan, Tcl_LongAsWide(0L), SEEK_SET);
if ((*formatPtr->fileMatchProc)(chan, fileName, formatObj,
widthPtr, heightPtr, interp)) {
@@ -3451,35 +3736,35 @@ MatchFileFormat(interp, chan, fileName, formatObj, imageFormatPtr,
}
}
if (formatPtr == NULL) {
- useoldformat = 1;
- for (formatPtr = tsdPtr->oldFormatList; formatPtr != NULL;
- formatPtr = formatPtr->nextPtr) {
- if (formatString != NULL) {
- if (strncasecmp(formatString,
- formatPtr->name, strlen(formatPtr->name)) != 0) {
- continue;
- }
- matched = 1;
- if (formatPtr->fileMatchProc == NULL) {
- Tcl_AppendResult(interp, "-file option isn't supported for ",
- formatString, " images", (char *) NULL);
- return TCL_ERROR;
- }
- }
- if (formatPtr->fileMatchProc != NULL) {
- (void) Tcl_Seek(chan, 0L, SEEK_SET);
- if ((*formatPtr->fileMatchProc)(chan, fileName, (Tcl_Obj *) formatString,
- widthPtr, heightPtr, interp)) {
- if (*widthPtr < 1) {
- *widthPtr = 1;
+ useoldformat = 1;
+ for (formatPtr = tsdPtr->oldFormatList; formatPtr != NULL;
+ formatPtr = formatPtr->nextPtr) {
+ if (formatString != NULL) {
+ if (strncasecmp(formatString,
+ formatPtr->name, strlen(formatPtr->name)) != 0) {
+ continue;
}
- if (*heightPtr < 1) {
- *heightPtr = 1;
+ matched = 1;
+ if (formatPtr->fileMatchProc == NULL) {
+ Tcl_AppendResult(interp, "-file option isn't supported",
+ " for ", formatString, " images", (char *) NULL);
+ return TCL_ERROR;
+ }
+ }
+ if (formatPtr->fileMatchProc != NULL) {
+ (void) Tcl_Seek(chan, Tcl_LongAsWide(0L), SEEK_SET);
+ if ((*formatPtr->fileMatchProc)(chan, fileName, (Tcl_Obj *)
+ formatString, widthPtr, heightPtr, interp)) {
+ if (*widthPtr < 1) {
+ *widthPtr = 1;
+ }
+ if (*heightPtr < 1) {
+ *heightPtr = 1;
+ }
+ break;
}
- break;
}
}
- }
}
if (formatPtr == NULL) {
@@ -3497,7 +3782,7 @@ MatchFileFormat(interp, chan, fileName, formatObj, imageFormatPtr,
*imageFormatPtr = formatPtr;
*oldformat = useoldformat;
- (void) Tcl_Seek(chan, 0L, SEEK_SET);
+ (void) Tcl_Seek(chan, Tcl_LongAsWide(0L), SEEK_SET);
return TCL_OK;
}
@@ -3576,34 +3861,34 @@ MatchStringFormat(interp, data, formatObj, imageFormatPtr,
}
if (formatPtr == NULL) {
- useoldformat = 1;
- for (formatPtr = tsdPtr->oldFormatList; formatPtr != NULL;
- formatPtr = formatPtr->nextPtr) {
- if (formatObj != NULL) {
- if (strncasecmp(formatString,
- formatPtr->name, strlen(formatPtr->name)) != 0) {
- continue;
+ useoldformat = 1;
+ for (formatPtr = tsdPtr->oldFormatList; formatPtr != NULL;
+ formatPtr = formatPtr->nextPtr) {
+ if (formatObj != NULL) {
+ if (strncasecmp(formatString,
+ formatPtr->name, strlen(formatPtr->name)) != 0) {
+ continue;
+ }
+ matched = 1;
+ if (formatPtr->stringMatchProc == NULL) {
+ Tcl_AppendResult(interp, "-data option isn't supported",
+ " for ", formatString, " images", (char *) NULL);
+ return TCL_ERROR;
+ }
}
- matched = 1;
- if (formatPtr->stringMatchProc == NULL) {
- Tcl_AppendResult(interp, "-data option isn't supported for ",
- formatString, " images", (char *) NULL);
- return TCL_ERROR;
+ if ((formatPtr->stringMatchProc != NULL)
+ && (formatPtr->stringReadProc != NULL)
+ && (*formatPtr->stringMatchProc)(
+ (Tcl_Obj *) Tcl_GetString(data),
+ (Tcl_Obj *) formatString,
+ widthPtr, heightPtr, interp)) {
+ break;
}
}
- if ((formatPtr->stringMatchProc != NULL)
- && (formatPtr->stringReadProc != NULL)
- && (*formatPtr->stringMatchProc)((Tcl_Obj *) Tcl_GetString(data),
- (Tcl_Obj *) formatString,
- widthPtr, heightPtr, interp)) {
- break;
- }
- }
}
if (formatPtr == NULL) {
if ((formatObj != NULL) && !matched) {
- Tcl_AppendResult(interp, "image format \"",
- formatString,
+ Tcl_AppendResult(interp, "image format \"", formatString,
"\" is not supported", (char *) NULL);
} else {
Tcl_AppendResult(interp, "couldn't recognize image data",
@@ -3641,7 +3926,7 @@ Tk_PhotoHandle
Tk_FindPhoto(interp, imageName)
Tcl_Interp *interp; /* Interpreter (application) in which image
* exists. */
- char *imageName; /* Name of the desired photo image. */
+ CONST char *imageName; /* Name of the desired photo image. */
{
ClientData clientData;
Tk_ImageType *typePtr;
@@ -3670,7 +3955,7 @@ Tk_FindPhoto(interp, imageName)
*---------------------------------------------------------------------- */
void
-Tk_PhotoPutBlock(handle, blockPtr, x, y, width, height)
+Tk_PhotoPutBlock(handle, blockPtr, x, y, width, height, compRule)
Tk_PhotoHandle handle; /* Opaque handle for the photo image
* to be updated. */
register Tk_PhotoImageBlock *blockPtr;
@@ -3680,6 +3965,8 @@ Tk_PhotoPutBlock(handle, blockPtr, x, y, width, height)
* be updated in the image. */
int width, height; /* Dimensions of the area of the image
* to be updated. */
+ int compRule; /* Compositing rule to use when processing
+ * transparent pixels. */
{
register PhotoMaster *masterPtr;
int xEnd, yEnd;
@@ -3700,14 +3987,17 @@ Tk_PhotoPutBlock(handle, blockPtr, x, y, width, height)
&& ((y + height) > masterPtr->userHeight)) {
height = masterPtr->userHeight - y;
}
- if ((width <= 0) || (height <= 0))
+ if ((width <= 0) || (height <= 0)) {
return;
+ }
xEnd = x + width;
yEnd = y + height;
if ((xEnd > masterPtr->width) || (yEnd > masterPtr->height)) {
- ImgPhotoSetSize(masterPtr, MAX(xEnd, masterPtr->width),
- MAX(yEnd, masterPtr->height));
+ if (ImgPhotoSetSize(masterPtr, MAX(xEnd, masterPtr->width),
+ MAX(yEnd, masterPtr->height)) == TCL_ERROR) {
+ panic(TK_PHOTO_ALLOC_FAILURE_MESSAGE);
+ }
}
if ((y < masterPtr->ditherY) || ((y == masterPtr->ditherY)
@@ -3753,40 +4043,82 @@ Tk_PhotoPutBlock(handle, blockPtr, x, y, width, height)
&& (greenOffset == 1) && (blueOffset == 2) && (alphaOffset == 3)
&& (width <= blockPtr->width) && (height <= blockPtr->height)
&& ((height == 1) || ((x == 0) && (width == masterPtr->width)
- && (blockPtr->pitch == pitch)))) {
+ && (blockPtr->pitch == pitch)))
+ && (compRule == TK_PHOTO_COMPOSITE_SET)) {
memcpy((VOID *) destLinePtr,
(VOID *) (blockPtr->pixelPtr + blockPtr->offset[0]),
(size_t) (height * width * 4));
} else {
+ int alpha;
for (hLeft = height; hLeft > 0;) {
srcLinePtr = blockPtr->pixelPtr + blockPtr->offset[0];
hCopy = MIN(hLeft, blockPtr->height);
hLeft -= hCopy;
for (; hCopy > 0; --hCopy) {
- destPtr = destLinePtr;
- for (wLeft = width; wLeft > 0;) {
- wCopy = MIN(wLeft, blockPtr->width);
- wLeft -= wCopy;
- srcPtr = srcLinePtr;
- for (; wCopy > 0; --wCopy) {
- if (!destPtr[3]) {
- destPtr[0] = destPtr[1] = destPtr[2] = 0xd9;
- }
- if (!alphaOffset || (srcPtr[alphaOffset] == 255)) {
- *destPtr++ = srcPtr[0];
- *destPtr++ = srcPtr[greenOffset];
- *destPtr++ = srcPtr[blueOffset];
- *destPtr++ = 255;
- } else {
- if (srcPtr[alphaOffset]) {
- destPtr[0] += (srcPtr[0] - destPtr[0]) * srcPtr[alphaOffset] / 255;
- destPtr[1] += (srcPtr[greenOffset] - destPtr[1]) * srcPtr[alphaOffset] / 255;
- destPtr[2] += (srcPtr[blueOffset] - destPtr[2]) * srcPtr[alphaOffset] / 255;
- destPtr[3] += (255 - destPtr[3]) * srcPtr[alphaOffset] / 255;
- }
- destPtr+=4;
- }
- srcPtr += blockPtr->pixelSize;
+ if ((blockPtr->pixelSize == 4) && (greenOffset == 1)
+ && (blueOffset == 2) && (alphaOffset == 3)
+ && (width <= blockPtr->width)
+ && (compRule == TK_PHOTO_COMPOSITE_SET)) {
+ memcpy((VOID *) destLinePtr, (VOID *) srcLinePtr,
+ (size_t) (width * 4));
+ } else {
+ destPtr = destLinePtr;
+ for (wLeft = width; wLeft > 0;) {
+ wCopy = MIN(wLeft, blockPtr->width);
+ wLeft -= wCopy;
+ srcPtr = srcLinePtr;
+ for (; wCopy > 0; --wCopy) {
+ alpha = srcPtr[alphaOffset];
+ /*
+ * In the easy case, we can just copy.
+ */
+ if (!alphaOffset || (alpha == 255)) {
+ /* new solid part of the image */
+ *destPtr++ = srcPtr[0];
+ *destPtr++ = srcPtr[greenOffset];
+ *destPtr++ = srcPtr[blueOffset];
+ *destPtr++ = 255;
+ srcPtr += blockPtr->pixelSize;
+ continue;
+ }
+
+ /*
+ * Combine according to the compositing rule.
+ */
+ switch (compRule) {
+ case TK_PHOTO_COMPOSITE_SET:
+ *destPtr++ = srcPtr[0];
+ *destPtr++ = srcPtr[greenOffset];
+ *destPtr++ = srcPtr[blueOffset];
+ *destPtr++ = alpha;
+ break;
+
+ case TK_PHOTO_COMPOSITE_OVERLAY:
+ if (!destPtr[3]) {
+ /*
+ * There must be a better way to select a
+ * background colour!
+ */
+ destPtr[0] = destPtr[1] = destPtr[2] = 0xd9;
+ }
+
+ if (alpha) {
+ destPtr[0] += (srcPtr[0] - destPtr[0]) * alpha / 255;
+ destPtr[1] += (srcPtr[greenOffset] - destPtr[1]) * alpha / 255;
+ destPtr[2] += (srcPtr[blueOffset] - destPtr[2]) * alpha / 255;
+ destPtr[3] += (255 - destPtr[3]) * alpha / 255;
+ }
+ /*
+ * else should be empty space
+ */
+ destPtr += 4;
+ break;
+
+ default:
+ panic("unknown compositing rule: %d", compRule);
+ }
+ srcPtr += blockPtr->pixelSize;
+ }
}
}
srcLinePtr += blockPtr->pitch;
@@ -3799,61 +4131,81 @@ Tk_PhotoPutBlock(handle, blockPtr, x, y, width, height)
* Add this new block to the region which specifies which data is valid.
*/
- if (alphaOffset) {
- int x1, y1, end;
-
- /*
- * This block is grossly inefficient. For each row in the image, it
- * finds each continguous string of transparent pixels, then marks those
- * areas as invalid in the validRegion mask. This makes drawing very
- * efficient, because of the way we use X: we just say, here's your
- * mask, and here's your data. We need not worry about the current
- * background color, etc. But this costs us a lot on the image setup.
- * Still, image setup only happens once, whereas the drawing happens
- * many times, so this might be the best way to go.
- *
- * An alternative might be to not set up this mask, and instead, at
- * drawing time, for each transparent pixel, set its color to the
- * color of the background behind that pixel. This is what I suspect
- * most of programs do. However, they don't have to deal with the canvas,
- * which could have many different background colors. Determining the
- * correct bg color for a given pixel might be expensive.
- */
-
- destLinePtr = masterPtr->pix24 + (y * masterPtr->width + x) * 4 + 3;
- for (y1 = 0; y1 < height; y1++) {
- x1 = 0;
- destPtr = destLinePtr;
- while (x1 < width) {
- /* search for first non-transparent pixel */
- while ((x1 < width) && !*destPtr) {
- x1++; destPtr += 4;
- }
- end = x1;
- /* search for first transparent pixel */
- while ((end < width) && *destPtr) {
- end++; destPtr += 4;
- }
- if (end > x1) {
- rect.x = x + x1;
- rect.y = y + y1;
- rect.width = end - x1;
- rect.height = 1;
- TkUnionRectWithRegion(&rect, masterPtr->validRegion,
- masterPtr->validRegion);
+ if (alphaOffset) {
+ int x1, y1, end;
+
+ /*
+ * This block is grossly inefficient. For each row in the image, it
+ * finds each continguous string of nontransparent pixels, then marks
+ * those areas as valid in the validRegion mask. This makes drawing
+ * very efficient, because of the way we use X: we just say, here's
+ * your mask, and here's your data. We need not worry about the
+ * current background color, etc. But this costs us a lot on the
+ * image setup. Still, image setup only happens once, whereas the
+ * drawing happens many times, so this might be the best way to go.
+ *
+ * An alternative might be to not set up this mask, and instead, at
+ * drawing time, for each transparent pixel, set its color to the
+ * color of the background behind that pixel. This is what I suspect
+ * most of programs do. However, they don't have to deal with the
+ * canvas, which could have many different background colors.
+ * Determining the correct bg color for a given pixel might be
+ * expensive.
+ */
+
+ if (compRule != TK_PHOTO_COMPOSITE_OVERLAY) {
+ /*
+ * Don't need this when using the OVERLAY compositing rule,
+ * which always strictly increases the valid region.
+ */
+ TkRegion workRgn = TkCreateRegion();
+
+ rect.x = x;
+ rect.y = y;
+ rect.width = width;
+ rect.height = height;
+ TkUnionRectWithRegion(&rect, workRgn, workRgn);
+ TkSubtractRegion(masterPtr->validRegion, workRgn,
+ masterPtr->validRegion);
+ TkDestroyRegion(workRgn);
+ }
+
+ destLinePtr = masterPtr->pix24 + (y * masterPtr->width + x) * 4 + 3;
+ for (y1 = 0; y1 < height; y1++) {
+ x1 = 0;
+ destPtr = destLinePtr;
+ while (x1 < width) {
+ /* search for first non-transparent pixel */
+ while ((x1 < width) && !*destPtr) {
+ x1++;
+ destPtr += 4;
+ }
+ end = x1;
+ /* search for first transparent pixel */
+ while ((end < width) && *destPtr) {
+ end++;
+ destPtr += 4;
+ }
+ if (end > x1) {
+ rect.x = x + x1;
+ rect.y = y + y1;
+ rect.width = end - x1;
+ rect.height = 1;
+ TkUnionRectWithRegion(&rect, masterPtr->validRegion,
+ masterPtr->validRegion);
+ }
+ x1 = end;
}
- x1 = end;
+ destLinePtr += masterPtr->width * 4;
}
- destLinePtr += masterPtr->width * 4;
+ } else {
+ rect.x = x;
+ rect.y = y;
+ rect.width = width;
+ rect.height = height;
+ TkUnionRectWithRegion(&rect, masterPtr->validRegion,
+ masterPtr->validRegion);
}
- } else {
- rect.x = x;
- rect.y = y;
- rect.width = width;
- rect.height = height;
- TkUnionRectWithRegion(&rect, masterPtr->validRegion,
- masterPtr->validRegion);
- }
/*
* Update each instance.
@@ -3889,7 +4241,7 @@ Tk_PhotoPutBlock(handle, blockPtr, x, y, width, height)
void
Tk_PhotoPutZoomedBlock(handle, blockPtr, x, y, width, height, zoomX, zoomY,
- subsampleX, subsampleY)
+ subsampleX, subsampleY, compRule)
Tk_PhotoHandle handle; /* Opaque handle for the photo image
* to be updated. */
register Tk_PhotoImageBlock *blockPtr;
@@ -3901,6 +4253,8 @@ Tk_PhotoPutZoomedBlock(handle, blockPtr, x, y, width, height, zoomX, zoomY,
* to be updated. */
int zoomX, zoomY; /* Zoom factors for the X and Y axes. */
int subsampleX, subsampleY; /* Subsampling factors for the X and Y axes. */
+ int compRule; /* Compositing rule to use when processing
+ * transparent pixels. */
{
register PhotoMaster *masterPtr;
int xEnd, yEnd;
@@ -3915,16 +4269,16 @@ Tk_PhotoPutZoomedBlock(handle, blockPtr, x, y, width, height, zoomX, zoomY,
int blockXSkip, blockYSkip;
XRectangle rect;
- if ((zoomX == 1) && (zoomY == 1) && (subsampleX == 1)
- && (subsampleY == 1)) {
- Tk_PhotoPutBlock(handle, blockPtr, x, y, width, height);
+ if (zoomX==1 && zoomY==1 && subsampleX==1 && subsampleY==1) {
+ Tk_PhotoPutBlock(handle, blockPtr, x, y, width, height, compRule);
return;
}
masterPtr = (PhotoMaster *) handle;
- if ((zoomX <= 0) || (zoomY <= 0))
+ if (zoomX <= 0 || zoomY <= 0) {
return;
+ }
if ((masterPtr->userWidth != 0) && ((x + width) > masterPtr->userWidth)) {
width = masterPtr->userWidth - x;
}
@@ -3932,15 +4286,18 @@ Tk_PhotoPutZoomedBlock(handle, blockPtr, x, y, width, height, zoomX, zoomY,
&& ((y + height) > masterPtr->userHeight)) {
height = masterPtr->userHeight - y;
}
- if ((width <= 0) || (height <= 0))
+ if (width <= 0 || height <= 0) {
return;
+ }
xEnd = x + width;
yEnd = y + height;
if ((xEnd > masterPtr->width) || (yEnd > masterPtr->height)) {
int sameSrc = (blockPtr->pixelPtr == masterPtr->pix24);
- ImgPhotoSetSize(masterPtr, MAX(xEnd, masterPtr->width),
- MAX(yEnd, masterPtr->height));
+ if (ImgPhotoSetSize(masterPtr, MAX(xEnd, masterPtr->width),
+ MAX(yEnd, masterPtr->height)) == TCL_ERROR) {
+ panic(TK_PHOTO_ALLOC_FAILURE_MESSAGE);
+ }
if (sameSrc) {
blockPtr->pixelPtr = masterPtr->pix24;
}
@@ -3980,18 +4337,20 @@ Tk_PhotoPutZoomedBlock(handle, blockPtr, x, y, width, height, zoomX, zoomY,
blockXSkip = subsampleX * blockPtr->pixelSize;
blockYSkip = subsampleY * blockPtr->pitch;
- if (subsampleX > 0)
+ if (subsampleX > 0) {
blockWid = ((blockPtr->width + subsampleX - 1) / subsampleX) * zoomX;
- else if (subsampleX == 0)
+ } else if (subsampleX == 0) {
blockWid = width;
- else
+ } else {
blockWid = ((blockPtr->width - subsampleX - 1) / -subsampleX) * zoomX;
- if (subsampleY > 0)
+ }
+ if (subsampleY > 0) {
blockHt = ((blockPtr->height + subsampleY - 1) / subsampleY) * zoomY;
- else if (subsampleY == 0)
+ } else if (subsampleY == 0) {
blockHt = height;
- else
+ } else {
blockHt = ((blockPtr->height - subsampleY - 1) / -subsampleY) * zoomY;
+ }
/*
* Copy the data into our local 24-bit/pixel array.
@@ -4020,23 +4379,43 @@ Tk_PhotoPutZoomedBlock(handle, blockPtr, x, y, width, height, zoomX, zoomY,
srcPtr = srcLinePtr;
for (; wCopy > 0; wCopy -= zoomX) {
for (xRepeat = MIN(wCopy, zoomX); xRepeat > 0; xRepeat--) {
- if (!destPtr[3]) {
- destPtr[0] = destPtr[1] = destPtr[2] = 0xd9;
- }
- if (!alphaOffset || (srcPtr[alphaOffset] == 255)) {
- *destPtr++ = srcPtr[0];
- *destPtr++ = srcPtr[greenOffset];
- *destPtr++ = srcPtr[blueOffset];
- *destPtr++ = 255;
- } else {
- if (srcPtr[alphaOffset]) {
- destPtr[0] += (srcPtr[0] - destPtr[0]) * srcPtr[alphaOffset] / 255;
- destPtr[1] += (srcPtr[greenOffset] - destPtr[1]) * srcPtr[alphaOffset] / 255;
- destPtr[2] += (srcPtr[blueOffset] - destPtr[2]) * srcPtr[alphaOffset] / 255;
- destPtr[3] += (255 - destPtr[3]) * srcPtr[alphaOffset] / 255;
- }
- destPtr+=4;
- }
+ /*
+ * Common case (solid pixels) first
+ */
+ if (!alphaOffset || (srcPtr[alphaOffset] == 255)) {
+ *destPtr++ = srcPtr[0];
+ *destPtr++ = srcPtr[greenOffset];
+ *destPtr++ = srcPtr[blueOffset];
+ *destPtr++ = 255;
+ continue;
+ }
+
+ switch (compRule) {
+ case TK_PHOTO_COMPOSITE_SET:
+ *destPtr++ = srcPtr[0];
+ *destPtr++ = srcPtr[greenOffset];
+ *destPtr++ = srcPtr[blueOffset];
+ *destPtr++ = srcPtr[alphaOffset];
+ break;
+ case TK_PHOTO_COMPOSITE_OVERLAY:
+ if (!destPtr[3]) {
+ /*
+ * There must be a better way to select a
+ * background colour!
+ */
+ destPtr[0] = destPtr[1] = destPtr[2] = 0xd9;
+ }
+ if (srcPtr[alphaOffset]) {
+ destPtr[0] += (srcPtr[0] - destPtr[0]) * srcPtr[alphaOffset] / 255;
+ destPtr[1] += (srcPtr[greenOffset] - destPtr[1]) * srcPtr[alphaOffset] / 255;
+ destPtr[2] += (srcPtr[blueOffset] - destPtr[2]) * srcPtr[alphaOffset] / 255;
+ destPtr[3] += (255 - destPtr[3]) * srcPtr[alphaOffset] / 255;
+ }
+ destPtr += 4;
+ break;
+ default:
+ panic("unknown compositing rule: %d", compRule);
+ }
}
srcPtr += blockXSkip;
}
@@ -4051,46 +4430,65 @@ Tk_PhotoPutZoomedBlock(handle, blockPtr, x, y, width, height, zoomX, zoomY,
}
/*
- * Add this new block to the region that specifies which data is valid.
+ * Recompute the region of data for which we have valid pixels to plot.
*/
- if (alphaOffset) {
- int x1, y1, end;
-
- destLinePtr = masterPtr->pix24 + (y * masterPtr->width + x) * 4 + 3;
- for (y1 = 0; y1 < height; y1++) {
- x1 = 0;
- destPtr = destLinePtr;
- while (x1 < width) {
- /* search for first non-transparent pixel */
- while ((x1 < width) && !*destPtr) {
- x1++; destPtr += 4;
- }
- end = x1;
- /* search for first transparent pixel */
- while ((end < width) && *destPtr) {
- end++; destPtr += 4;
- }
- if (end > x1) {
- rect.x = x + x1;
- rect.y = y + y1;
- rect.width = end - x1;
- rect.height = 1;
- TkUnionRectWithRegion(&rect, masterPtr->validRegion,
- masterPtr->validRegion);
+ if (alphaOffset) {
+ int x1, y1, end;
+
+ if (compRule != TK_PHOTO_COMPOSITE_OVERLAY) {
+ /*
+ * Don't need this when using the OVERLAY compositing rule, which
+ * always strictly increases the valid region.
+ */
+ TkRegion workRgn = TkCreateRegion();
+
+ rect.x = x;
+ rect.y = y;
+ rect.width = width;
+ rect.height = 1;
+ TkUnionRectWithRegion(&rect, workRgn, workRgn);
+ TkSubtractRegion(masterPtr->validRegion, workRgn,
+ masterPtr->validRegion);
+ TkDestroyRegion(workRgn);
+ }
+
+ destLinePtr = masterPtr->pix24 + (y * masterPtr->width + x) * 4 + 3;
+ for (y1 = 0; y1 < height; y1++) {
+ x1 = 0;
+ destPtr = destLinePtr;
+ while (x1 < width) {
+ /* search for first non-transparent pixel */
+ while ((x1 < width) && !*destPtr) {
+ x1++;
+ destPtr += 4;
+ }
+ end = x1;
+ /* search for first transparent pixel */
+ while ((end < width) && *destPtr) {
+ end++;
+ destPtr += 4;
+ }
+ if (end > x1) {
+ rect.x = x + x1;
+ rect.y = y + y1;
+ rect.width = end - x1;
+ rect.height = 1;
+ TkUnionRectWithRegion(&rect, masterPtr->validRegion,
+ masterPtr->validRegion);
+ }
+ x1 = end;
}
- x1 = end;
+ destLinePtr += masterPtr->width * 4;
}
- destLinePtr += masterPtr->width * 4;
+ } else {
+ rect.x = x;
+ rect.y = y;
+ rect.width = width;
+ rect.height = height;
+ TkUnionRectWithRegion(&rect, masterPtr->validRegion,
+ masterPtr->validRegion);
}
- } else {
- rect.x = x;
- rect.y = y;
- rect.width = width;
- rect.height = height;
- TkUnionRectWithRegion(&rect, masterPtr->validRegion,
- masterPtr->validRegion);
- }
/*
* Update each instance.
@@ -4626,8 +5024,10 @@ Tk_PhotoExpand(handle, width, height)
height = masterPtr->height;
}
if ((width != masterPtr->width) || (height != masterPtr->height)) {
- ImgPhotoSetSize(masterPtr, MAX(width, masterPtr->width),
- MAX(height, masterPtr->height));
+ if (ImgPhotoSetSize(masterPtr, MAX(width, masterPtr->width),
+ MAX(height, masterPtr->height)) == TCL_ERROR) {
+ panic(TK_PHOTO_ALLOC_FAILURE_MESSAGE);
+ }
Tk_ImageChanged(masterPtr->tkMaster, 0, 0, 0, 0, masterPtr->width,
masterPtr->height);
}
@@ -4696,8 +5096,10 @@ Tk_PhotoSetSize(handle, width, height)
masterPtr->userWidth = width;
masterPtr->userHeight = height;
- ImgPhotoSetSize(masterPtr, ((width > 0) ? width: masterPtr->width),
- ((height > 0) ? height: masterPtr->height));
+ if (ImgPhotoSetSize(masterPtr, ((width > 0) ? width: masterPtr->width),
+ ((height > 0) ? height: masterPtr->height)) == TCL_ERROR) {
+ panic(TK_PHOTO_ALLOC_FAILURE_MESSAGE);
+ }
Tk_ImageChanged(masterPtr->tkMaster, 0, 0, 0, 0,
masterPtr->width, masterPtr->height);
}
@@ -4705,6 +5107,37 @@ Tk_PhotoSetSize(handle, width, height)
/*
*----------------------------------------------------------------------
*
+ * TkGetPhotoValidRegion --
+ *
+ * This procedure is called to get the part of the photo where
+ * there is valid data. Or, conversely, the part of the photo
+ * which is transparent.
+ *
+ * Results:
+ * A TkRegion value that indicates the current area of the photo
+ * that is valid. This value should not be used after any
+ * modification to the photo image.
+ *
+ * Side Effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+TkRegion
+TkPhotoGetValidRegion(handle)
+ Tk_PhotoHandle handle; /* Handle for the image whose valid region
+ * is to obtained. */
+{
+ PhotoMaster *masterPtr;
+
+ masterPtr = (PhotoMaster *) handle;
+ return masterPtr->validRegion;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
* ImgGetPhoto --
*
* This procedure is called to obtain image data from a photo
@@ -4754,11 +5187,14 @@ ImgGetPhoto(masterPtr, blockPtr, optPtr)
+ blockPtr->pixelSize - 1;
for (x = 0; x < blockPtr->width; x++) {
if (*pixelPtr != 255) {
- alphaOffset = 3; break;
+ alphaOffset = 3;
+ break;
}
pixelPtr += blockPtr->pixelSize;
}
- if (alphaOffset) break;
+ if (alphaOffset) {
+ break;
+ }
}
if (!alphaOffset) {
blockPtr->pixelPtr--;
@@ -5138,13 +5574,13 @@ Tk_CreatePhotoOption(interp, name, proc)
static int
ImgPhotoPostscript(clientData, interp, tkwin, psInfo,
x, y, width, height, prepass)
- ClientData clientData;
- Tcl_Interp *interp;
- Tk_Window tkwin;
- Tk_PostscriptInfo psInfo; /* postscript info */
- int x, y; /* First pixel to output */
- int width, height; /* Width and height of area */
- int prepass;
+ ClientData clientData; /* Handle for the photo image */
+ Tcl_Interp *interp; /* Interpreter */
+ Tk_Window tkwin; /* (unused) */
+ Tk_PostscriptInfo psInfo; /* postscript info */
+ int x, y; /* First pixel to output */
+ int width, height; /* Width and height of area */
+ int prepass; /* (unused) */
{
Tk_PhotoImageBlock block;
@@ -5153,4 +5589,35 @@ ImgPhotoPostscript(clientData, interp, tkwin, psInfo,
return Tk_PostscriptPhoto(interp, &block, psInfo, width, height);
}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tk_PhotoPutBlock_NoComposite, Tk_PhotoPutZoomedBlock_NoComposite --
+ *
+ * These backward-compatability functions just exist to fill slots in
+ * stubs table. For the behaviour of *_NoComposite, refer to the
+ * corresponding function without the extra suffix.
+ *
+ *----------------------------------------------------------------------
+ */
+void
+Tk_PhotoPutBlock_NoComposite(handle, blockPtr, x, y, width, height)
+ Tk_PhotoHandle handle;
+ Tk_PhotoImageBlock *blockPtr;
+ int x, y, width, height;
+{
+ Tk_PhotoPutBlock(handle, blockPtr, x, y, width, height,
+ TK_PHOTO_COMPOSITE_OVERLAY);
+}
+void
+Tk_PhotoPutZoomedBlock_NoComposite(handle, blockPtr, x, y, width, height,
+ zoomX, zoomY, subsampleX, subsampleY)
+ Tk_PhotoHandle handle;
+ Tk_PhotoImageBlock *blockPtr;
+ int x, y, width, height, zoomX, zoomY, subsampleX, subsampleY;
+{
+ Tk_PhotoPutZoomedBlock(handle, blockPtr, x, y, width, height,
+ zoomX, zoomY, subsampleX, subsampleY, TK_PHOTO_COMPOSITE_OVERLAY);
+}