diff options
author | dkf <donal.k.fellows@manchester.ac.uk> | 2002-06-14 13:35:46 (GMT) |
---|---|---|
committer | dkf <donal.k.fellows@manchester.ac.uk> | 2002-06-14 13:35:46 (GMT) |
commit | 8abf69416e48492ccda18dcfc6e8adf9d33d0a32 (patch) | |
tree | c4ad54b29f443e940a51b7b0ca0a9c57e5b65adc /generic/tkImgPhoto.c | |
parent | 8c18f8111d03425255bcd1d60b70da5c9ae5f521 (diff) | |
download | tk-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.c | 532 |
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); +} |