summaryrefslogtreecommitdiffstats
path: root/generic/tkImgPhoto.c
diff options
context:
space:
mode:
authordkf <donal.k.fellows@manchester.ac.uk>2002-06-14 13:35:46 (GMT)
committerdkf <donal.k.fellows@manchester.ac.uk>2002-06-14 13:35:46 (GMT)
commit8abf69416e48492ccda18dcfc6e8adf9d33d0a32 (patch)
treec4ad54b29f443e940a51b7b0ca0a9c57e5b65adc /generic/tkImgPhoto.c
parent8c18f8111d03425255bcd1d60b70da5c9ae5f521 (diff)
downloadtk-8abf69416e48492ccda18dcfc6e8adf9d33d0a32.zip
tk-8abf69416e48492ccda18dcfc6e8adf9d33d0a32.tar.gz
tk-8abf69416e48492ccda18dcfc6e8adf9d33d0a32.tar.bz2
TIP#98 implementation; improved photo image copy and GIF frame access
Diffstat (limited to 'generic/tkImgPhoto.c')
-rw-r--r--generic/tkImgPhoto.c532
1 files changed, 345 insertions, 187 deletions
diff --git a/generic/tkImgPhoto.c b/generic/tkImgPhoto.c
index ca524df..032ce89 100644
--- a/generic/tkImgPhoto.c
+++ b/generic/tkImgPhoto.c
@@ -16,7 +16,7 @@
* Department of Computer Science,
* Australian National University.
*
- * RCS: @(#) $Id: tkImgPhoto.c,v 1.30 2002/04/12 06:48:58 hobbs Exp $
+ * RCS: @(#) $Id: tkImgPhoto.c,v 1.31 2002/06/14 13:35:48 dkf Exp $
*/
#include "tkInt.h"
@@ -232,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 */
};
/*
@@ -242,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.
@@ -252,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
@@ -267,6 +270,7 @@ struct SubcommandOptions {
static char *optionNames[] = {
"-background",
+ "-compositingrule",
"-format",
"-from",
"-grayscale",
@@ -775,14 +779,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;
}
@@ -858,7 +863,8 @@ ImgPhotoCmd(clientData, interp, objc, objv)
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;
@@ -946,9 +952,9 @@ ImgPhotoCmd(clientData, interp, objc, objv)
}
return result;
break;
- }
+ }
- case PHOTO_GET: {
+ case PHOTO_GET: {
/*
* photo get command - first parse and check parameters.
*/
@@ -979,9 +985,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.
*/
@@ -1104,7 +1110,7 @@ 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;
@@ -1326,59 +1332,43 @@ ImgPhotoCmd(clientData, interp, objc, objv)
return TCL_ERROR;
}
+ setBox.x = x;
+ setBox.y = y;
+ setBox.width = 1;
+ setBox.height = 1;
+ pixelPtr = masterPtr->pix24 + (y * masterPtr->width + x) * 4;
+
if (transFlag) {
/*
- * Make pixel transparent. Do by building a mask for
- * all the other pixels in the image and setting the
- * validRegion to the intersection of that with the
- * old validRegion. There isn't a neater way to do
- * this given the limited set of operations available
- * in the platform-independent region operations.
+ * Make pixel transparent.
*/
- TkRegion setRegion = TkCreateRegion();
-
- if (y > 0) {
- setBox.x = 0;
- setBox.y = 0;
- setBox.width = masterPtr->width;
- setBox.height = y;
- TkUnionRectWithRegion(&setBox, setRegion, setRegion);
- }
- if (x > 0) {
- setBox.x = 0;
- setBox.y = y;
- setBox.width = x;
- setBox.height = 1;
- TkUnionRectWithRegion(&setBox, setRegion, setRegion);
- }
- if (x < masterPtr->width-1) {
- setBox.x = x+1;
- setBox.y = y;
- setBox.width = masterPtr->width-1 - x;
- setBox.height = 1;
- TkUnionRectWithRegion(&setBox, setRegion, setRegion);
- }
- if (y < masterPtr->height-1) {
- setBox.x = 0;
- setBox.y = y+1;
- setBox.width = masterPtr->width;
- setBox.height = masterPtr->height-1 - y;
- TkUnionRectWithRegion(&setBox, setRegion, setRegion);
- }
- TkIntersectRegion(masterPtr->validRegion, setRegion,
+ TkRegion clearRegion = TkCreateRegion();
+
+ TkUnionRectWithRegion(&setBox, clearRegion, clearRegion);
+ TkSubtractRegion(masterPtr->validRegion, clearRegion,
masterPtr->validRegion);
- TkDestroyRegion(setRegion);
+ TkDestroyRegion(clearRegion);
+ /*
+ * Set the alpha value correctly.
+ */
+ pixelPtr[3] = 0;
} else {
/*
* Make pixel opaque.
*/
- setBox.x = x;
- setBox.y = y;
- setBox.width = 1;
- setBox.height = 1;
TkUnionRectWithRegion(&setBox, masterPtr->validRegion,
masterPtr->validRegion);
+ pixelPtr[3] = 255;
}
+
+ /*
+ * 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;
}
}
@@ -1514,7 +1504,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.
@@ -1629,7 +1620,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) {
@@ -1640,6 +1633,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;
@@ -1935,7 +1956,7 @@ ImgPhotoConfigureMaster(interp, masterPtr, objc, objv, flags)
&& ((masterPtr->dataString != oldData)
|| (masterPtr->format != oldFormat))) {
- if (MatchStringFormat(interp, masterPtr->dataString,
+ if (MatchStringFormat(interp, masterPtr->dataString,
masterPtr->format, &imageFormat, &imageWidth,
&imageHeight, &oldformat) != TCL_OK) {
return TCL_ERROR;
@@ -2090,6 +2111,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) {
@@ -2660,12 +2683,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;
}
}
@@ -2721,7 +2742,7 @@ ImgPhotoInstanceSetSize(instancePtr)
(masterPtr->width > 0) ? masterPtr->width: 1,
(masterPtr->height > 0) ? masterPtr->height: 1,
instancePtr->visualInfo.depth);
- if(!newPixmap) {
+ if (!newPixmap) {
panic("Fail to create pixmap with Tk_GetPixmap in ImgPhotoInstanceSetSize.\n");
return;
}
@@ -3635,35 +3656,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, Tcl_LongAsWide(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) {
@@ -3760,34 +3781,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",
@@ -3854,7 +3875,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;
@@ -3864,6 +3885,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;
@@ -3884,8 +3907,9 @@ 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;
@@ -3937,7 +3961,8 @@ 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));
@@ -3948,35 +3973,70 @@ Tk_PhotoPutBlock(handle, blockPtr, x, y, width, height)
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) {
- alpha = srcPtr[alphaOffset];
- if (!destPtr[3]) {
- destPtr[0] = destPtr[1] = destPtr[2] = 0xd9;
- }
- if (!alphaOffset || (alpha == 255)) {
- /* new solid part of the image */
- *destPtr++ = srcPtr[0];
- *destPtr++ = srcPtr[greenOffset];
- *destPtr++ = srcPtr[blueOffset];
- *destPtr++ = 255;
- } else {
- 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;
+ 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;
}
+
/*
- * else should be empty space
+ * Combine according to the compositing rule.
*/
- destPtr += 4;
+ 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;
}
- srcPtr += blockPtr->pixelSize;
}
}
srcLinePtr += blockPtr->pitch;
@@ -4011,6 +4071,23 @@ Tk_PhotoPutBlock(handle, blockPtr, x, y, width, height)
* 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;
@@ -4018,12 +4095,14 @@ Tk_PhotoPutBlock(handle, blockPtr, x, y, width, height)
while (x1 < width) {
/* search for first non-transparent pixel */
while ((x1 < width) && !*destPtr) {
- x1++; destPtr += 4;
+ x1++;
+ destPtr += 4;
}
end = x1;
/* search for first transparent pixel */
while ((end < width) && *destPtr) {
- end++; destPtr += 4;
+ end++;
+ destPtr += 4;
}
if (end > x1) {
rect.x = x + x1;
@@ -4080,7 +4159,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;
@@ -4092,6 +4171,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;
@@ -4106,16 +4187,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;
}
@@ -4123,8 +4204,9 @@ 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;
@@ -4171,18 +4253,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.
@@ -4211,23 +4295,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;
}
@@ -4242,12 +4346,29 @@ 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;
+ 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;
@@ -4255,12 +4376,14 @@ Tk_PhotoPutZoomedBlock(handle, blockPtr, x, y, width, height, zoomX, zoomY,
while (x1 < width) {
/* search for first non-transparent pixel */
while ((x1 < width) && !*destPtr) {
- x1++; destPtr += 4;
+ x1++;
+ destPtr += 4;
}
end = x1;
/* search for first transparent pixel */
while ((end < width) && *destPtr) {
- end++; destPtr += 4;
+ end++;
+ destPtr += 4;
}
if (end > x1) {
rect.x = x + x1;
@@ -4976,11 +5099,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--;
@@ -5360,13 +5486,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;
@@ -5375,3 +5501,35 @@ ImgPhotoPostscript(clientData, interp, tkwin, psInfo,
return Tk_PostscriptPhoto(interp, &block, psInfo, width, height);
}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * Tk_PhotoPutBlock_Old, Tk_PhotoPutZoomedBlock_Old --
+ *
+ * These backward-compatability functions just exist to fill slots in
+ * stubs table. For the behaviour of *_Old, refer to the
+ * corresponding function without the extra suffix.
+ *
+ *----------------------------------------------------------------------
+ */
+void
+Tk_PhotoPutBlock_Old(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_Old(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);
+}