From 8abf69416e48492ccda18dcfc6e8adf9d33d0a32 Mon Sep 17 00:00:00 2001 From: dkf Date: Fri, 14 Jun 2002 13:35:46 +0000 Subject: TIP#98 implementation; improved photo image copy and GIF frame access --- ChangeLog | 46 +++++ doc/FindPhoto.3 | 37 +++- doc/photo.n | 14 +- generic/tk.decls | 18 +- generic/tk.h | 31 ++- generic/tkDecls.h | 43 +++-- generic/tkImgGIF.c | 5 +- generic/tkImgPPM.c | 5 +- generic/tkImgPhoto.c | 532 +++++++++++++++++++++++++++++++++------------------ generic/tkInt.decls | 6 +- generic/tkIntDecls.h | 33 +++- generic/tkStubInit.c | 17 +- mac/tkMacRegion.c | 32 +++- tests/imgPhoto.test | 49 ++++- unix/tkUnixPort.h | 4 +- win/tkWinRegion.c | 27 ++- 16 files changed, 675 insertions(+), 224 deletions(-) diff --git a/ChangeLog b/ChangeLog index 2ddbb75..58650ea 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,49 @@ +2002-06-14 Donal K. Fellows + + * tests/imgPhoto.test: Added tests of -compositingrule + + * doc/photo.n: Added documentation for "-compositingrule". + * generic/tkImgPhoto.c (ImgPhotoCmd,ParseSubcommandOptions): New + "-compositingrule" option for [$photo copy] subcommand, using + OPT_COMPOSITE flag and compositingRule field in SubcommandOptions + structure. + + * doc/FindPhoto.3: Documented the extra argument for the + compositing rule and the action to take if anyone wants to + maintain total backward-compatability. + + * generic/tk.h (TK_PHOTO_COMPOSITE_*): Defined values for use as + compositing rules. + (USE_OLD_PHOTO_PUT_BLOCK): Added a way for users to select the old + interface to Tk_PhotoPutBlock to provide an easier upgrade path. + + * generic/tk.decls: Alter Tk_PhotoPut*Block to Tk_PhotoPut*Block_Old + and introduce new slots for the old name of function with an extra + argument at the end for the compositing rule. + + * generic/tkImgPhoto.c (ImgPhotoCmd): Updated "transparency set" + subcommand to use TkSubtractRegion(). + + * win/tkWinRegion.c (TkSubtractRegion): + * mac/tkMacRegion.c (TkSubtractRegion): + * generic/tkInt.decls (TkSubtractRegion): + * unix/tkUnixPort.h (TkSubtractRegion): Added function to perform + the set-difference operation on regions; it seems all platforms + can support it, and it makes removing rectangular bits from + regions much easier. + + * generic/tkImgPPM.c (FileReadPPM): Reading a PPM/PGM always uses + the SET compositing rule because it is faster and the format does + not have any transparency information. + + * generic/tkImgGIF.c (FileReadGIF): Reading a GIF always uses the + SET compositing rule because GIF files model transparency as a + single special colour. + + * generic/tkImgPhoto.c (Tk_PhotoPutBlock, Tk_PhotoPutZoomedBlock): + Added a compositing rule to allow better control over what happens + to transparent pixels when inserting data into a photo image. + 2002-06-13 Mo DeJong * tests/winfo.test: Add basic tests for winfo ismapped. diff --git a/doc/FindPhoto.3 b/doc/FindPhoto.3 index 47f5df2..d1c96d1 100644 --- a/doc/FindPhoto.3 +++ b/doc/FindPhoto.3 @@ -9,7 +9,7 @@ '\" Department of Computer Science, '\" Australian National University. '\" -'\" RCS: @(#) $Id: FindPhoto.3,v 1.3 1999/10/29 03:57:40 hobbs Exp $ +'\" RCS: @(#) $Id: FindPhoto.3,v 1.4 2002/06/14 13:35:47 dkf Exp $ '\" .so man.macros .TH Tk_FindPhoto 3 8.0 Tk "Tk Library Procedures" @@ -27,11 +27,11 @@ Tk_PhotoHandle .VE .sp void -\fBTk_PhotoPutBlock\fR(\fIhandle, blockPtr, x, y, width, height\fR) +\fBTk_PhotoPutBlock\fR(\fIhandle, blockPtr, x, y, width, height, compRule\fR) .sp void \fBTk_PhotoPutZoomedBlock\fR(\fIhandle, blockPtr, x, y, width, height,\ -zoomX, zoomY, subsampleX, subsampleY\fR) +zoomX, zoomY, subsampleX, subsampleY, compRule\fR) .sp int \fBTk_PhotoGetImage\fR(\fIhandle, blockPtr\fR) @@ -69,6 +69,16 @@ to be placed within the image. Specifies the width of the image area to be affected (for \fBTk_PhotoPutBlock\fR) or the desired image width (for \fBTk_PhotoExpand\fR and \fBTk_PhotoSetSize\fR). +.VS 8.4 +.AP int compRule in +Specifies the compositing rule used when combining transparent pixels +in a block of data with a photo image. Must be one of +TK_PHOTO_COMPOSITE_OVERLAY (which puts the block of data over the top +of the existing photo image, with the previous contents showing +through in the transparent bits) or TK_PHOTO_COMPOSITE_SET (which +discards the existing photo image contents in the rectangle covered by +the data block.) +.VE 8.4 .AP int height in Specifies the height of the image area to be affected (for \fBTk_PhotoPutBlock\fR) or the desired image height (for @@ -135,6 +145,17 @@ to the addresses of the bytes containing the red, green, blue and alpha have other values, e.g., for images that are stored as separate red, green and blue planes. .PP +.VS 8.4 +The \fIcompRule\fR parameter to \fBTk_PhotoPutBlock\fR specifies a +compositing rule that says what to do with transparent pixels. The +value TK_PHOTO_COMPOSITE_OVERLAY says that the previous contents of +the photo image should show through, and the value +TK_PHOTO_COMPOSITE_SET says that the previous contents of the photo +image should be completely ignored, and the values from the block be +copied directly across. The behavior in Tk8.3 and earlier was +equivalent to having TK_PHOTO_COMPOSITE_OVERLAY as a compositing rule. +.VE 8.4 +.PP The value given for the \fIwidth\fR and \fIheight\fR parameters to \fBTk_PhotoPutBlock\fR do not have to correspond to the values specified in \fIblock\fR. If they are smaller, \fBTk_PhotoPutBlock\fR extracts a @@ -193,6 +214,16 @@ calls to \fBTk_PhotoPutBlock\fR, \fBTk_PhotoPutZoomedBlock\fR or \fBTk_PhotoGetSize\fR returns the dimensions of the image in *\fIwidthPtr\fR and *\fIheightPtr\fR. +.SH PORTABILITY +.VS 8.4 +.PP +In Tk 8.3 and earlier, \fBTk_PhotoPutBlock\fR and +\fBTk_PhotoPutZoomedBlock\fR had different signatures. If you want to +compile code that uses the old interface against 8.4 without updating +your code, compile it with the flag -DUSE_OLD_PHOTO_PUT_BLOCK. Code +linked using Stubs against older versions of Tk will continue to work. +.VE 8.4 + .SH CREDITS .PP The code for the photo image type was developed by Paul Mackerras, diff --git a/doc/photo.n b/doc/photo.n index 5e16f92..83a5966 100644 --- a/doc/photo.n +++ b/doc/photo.n @@ -9,7 +9,7 @@ '\" Department of Computer Science, '\" Australian National University. '\" -'\" RCS: @(#) $Id: photo.n,v 1.10 2002/03/14 10:19:40 dkf Exp $ +'\" RCS: @(#) $Id: photo.n,v 1.11 2002/06/14 13:35:47 dkf Exp $ '\" .so man.macros .TH photo n 4.0 Tk "Tk Built-In Commands" @@ -189,6 +189,18 @@ only every \fIx\fRth pixel in the X direction and \fIy\fRth pixel in the Y direction. Negative values will cause the image to be flipped about the Y or X axes, respectively. If \fIy\fR is not given, the default value is the same as \fIx\fR. +.TP +\fB\-compositingrule \fIrule\fR +.VS 8.4 +Specifies how transparent pixels in the source image are combined with +the destination image. When a compositing rule of \fIoverlay\fR is +set, the old contents of the destination image are visible, as if the +source image were printed on a piece of transparent film and placed +over the top of the destination. When a compositing rule of \fIset\R +is set, the old contents of the destination image are discarded and +the source image is used as-is. The default compositing rule is +\fIoverlay\fR. +.VE 8.4 .RE .TP \fIimageName \fBdata ?\fIoption value(s) ...\fR? diff --git a/generic/tk.decls b/generic/tk.decls index 78564de..445845a 100644 --- a/generic/tk.decls +++ b/generic/tk.decls @@ -11,7 +11,7 @@ # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # -# RCS: @(#) $Id: tk.decls,v 1.18 2002/04/05 08:38:22 hobbs Exp $ +# RCS: @(#) $Id: tk.decls,v 1.19 2002/06/14 13:35:47 dkf Exp $ library tk @@ -708,13 +708,13 @@ declare 143 generic { } declare 144 generic { - void Tk_PhotoPutBlock (Tk_PhotoHandle handle, \ + void Tk_PhotoPutBlock_Old (Tk_PhotoHandle handle, \ Tk_PhotoImageBlock *blockPtr, int x, int y, \ int width, int height) } declare 145 generic { - void Tk_PhotoPutZoomedBlock (Tk_PhotoHandle handle, \ + void Tk_PhotoPutZoomedBlock_Old (Tk_PhotoHandle handle, \ Tk_PhotoImageBlock *blockPtr, int x, int y, \ int width, int height, int zoomX, int zoomY, \ int subsampleX, int subsampleY) @@ -1164,6 +1164,18 @@ declare 245 generic { void Tk_SetCaretPos (Tk_Window tkwin, int x, int y, int height) } +declare 246 generic { + void Tk_PhotoPutBlock (Tk_PhotoHandle handle, + Tk_PhotoImageBlock *blockPtr, int x, int y, + int width, int height, int compRule) +} +declare 247 generic { + void Tk_PhotoPutZoomedBlock (Tk_PhotoHandle handle, + Tk_PhotoImageBlock *blockPtr, int x, int y, + int width, int height, int zoomX, int zoomY, + int subsampleX, int subsampleY, int compRule) +} + # Define the platform specific public Tk interface. These functions are # only available on the designated platform. diff --git a/generic/tk.h b/generic/tk.h index 2f082b1..fecb2ab 100644 --- a/generic/tk.h +++ b/generic/tk.h @@ -12,7 +12,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tk.h,v 1.58 2002/03/06 15:36:17 dkf Exp $ + * RCS: @(#) $Id: tk.h,v 1.59 2002/06/14 13:35:47 dkf Exp $ */ #ifndef _TK @@ -1270,6 +1270,15 @@ typedef struct Tk_PhotoImageBlock { } Tk_PhotoImageBlock; /* + * The following values control how blocks are combined into photo + * images when the alpha component of a pixel is not 255, a.k.a. the + * compositing rule. + */ + +#define TK_PHOTO_COMPOSITE_OVERLAY 0 +#define TK_PHOTO_COMPOSITE_SET 1 + +/* * Procedure prototypes and structures used in reading and * writing photo images: */ @@ -1459,6 +1468,26 @@ typedef int (Tk_SelectionProc) _ANSI_ARGS_((ClientData clientData, #include "tkDecls.h" /* + * Allow users to say that they don't want to alter their source to + * add the extra argument to Tk_PhotoPutBlock(); DO NOT DEFINE THIS + * WHEN BUILDING TK. + * + * This goes after the inclusion of the stubbed-decls so that the + * declarations of what is actually there can be correct. + */ + +#ifdef USE_OLD_PHOTO_PUT_BLOCK +# ifdef Tk_PhotoPutBlock +# undef Tk_PhotoPutBlock +# endif +# define Tk_PhotoPutBlock Tk_PhotoPutBlock_Old +# ifdef Tk_PhotoPutZoomedBlock +# undef Tk_PhotoPutZoomedBlock +# endif +# define Tk_PhotoPutZoomedBlock Tk_PhotoPutZoomedBlock_Old +#endif /* USE_OLD_PHOTO_PUT_BLOCK */ + +/* * Tcl commands exported by Tk: */ diff --git a/generic/tkDecls.h b/generic/tkDecls.h index 057295e..09e5014 100644 --- a/generic/tkDecls.h +++ b/generic/tkDecls.h @@ -8,7 +8,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkDecls.h,v 1.18 2002/04/05 08:38:22 hobbs Exp $ + * RCS: @(#) $Id: tkDecls.h,v 1.19 2002/06/14 13:35:47 dkf Exp $ */ #ifndef _TKDECLS @@ -510,11 +510,12 @@ EXTERN int Tk_ParseArgv _ANSI_ARGS_((Tcl_Interp * interp, CONST84 char ** argv, Tk_ArgvInfo * argTable, int flags)); /* 144 */ -EXTERN void Tk_PhotoPutBlock _ANSI_ARGS_((Tk_PhotoHandle handle, +EXTERN void Tk_PhotoPutBlock_Old _ANSI_ARGS_(( + Tk_PhotoHandle handle, Tk_PhotoImageBlock * blockPtr, int x, int y, int width, int height)); /* 145 */ -EXTERN void Tk_PhotoPutZoomedBlock _ANSI_ARGS_(( +EXTERN void Tk_PhotoPutZoomedBlock_Old _ANSI_ARGS_(( Tk_PhotoHandle handle, Tk_PhotoImageBlock * blockPtr, int x, int y, int width, int height, int zoomX, int zoomY, @@ -846,6 +847,16 @@ EXTERN void Tk_SetMinimumRequestSize _ANSI_ARGS_(( /* 245 */ EXTERN void Tk_SetCaretPos _ANSI_ARGS_((Tk_Window tkwin, int x, int y, int height)); +/* 246 */ +EXTERN void Tk_PhotoPutBlock _ANSI_ARGS_((Tk_PhotoHandle handle, + Tk_PhotoImageBlock * blockPtr, int x, int y, + int width, int height, int compRule)); +/* 247 */ +EXTERN void Tk_PhotoPutZoomedBlock _ANSI_ARGS_(( + Tk_PhotoHandle handle, + Tk_PhotoImageBlock * blockPtr, int x, int y, + int width, int height, int zoomX, int zoomY, + int subsampleX, int subsampleY, int compRule)); typedef struct TkStubHooks { struct TkPlatStubs *tkPlatStubs; @@ -1002,8 +1013,8 @@ typedef struct TkStubs { Tk_Window (*tk_NameToWindow) _ANSI_ARGS_((Tcl_Interp * interp, CONST char * pathName, Tk_Window tkwin)); /* 141 */ void (*tk_OwnSelection) _ANSI_ARGS_((Tk_Window tkwin, Atom selection, Tk_LostSelProc * proc, ClientData clientData)); /* 142 */ int (*tk_ParseArgv) _ANSI_ARGS_((Tcl_Interp * interp, Tk_Window tkwin, int * argcPtr, CONST84 char ** argv, Tk_ArgvInfo * argTable, int flags)); /* 143 */ - void (*tk_PhotoPutBlock) _ANSI_ARGS_((Tk_PhotoHandle handle, Tk_PhotoImageBlock * blockPtr, int x, int y, int width, int height)); /* 144 */ - void (*tk_PhotoPutZoomedBlock) _ANSI_ARGS_((Tk_PhotoHandle handle, Tk_PhotoImageBlock * blockPtr, int x, int y, int width, int height, int zoomX, int zoomY, int subsampleX, int subsampleY)); /* 145 */ + void (*tk_PhotoPutBlock_Old) _ANSI_ARGS_((Tk_PhotoHandle handle, Tk_PhotoImageBlock * blockPtr, int x, int y, int width, int height)); /* 144 */ + void (*tk_PhotoPutZoomedBlock_Old) _ANSI_ARGS_((Tk_PhotoHandle handle, Tk_PhotoImageBlock * blockPtr, int x, int y, int width, int height, int zoomX, int zoomY, int subsampleX, int subsampleY)); /* 145 */ int (*tk_PhotoGetImage) _ANSI_ARGS_((Tk_PhotoHandle handle, Tk_PhotoImageBlock * blockPtr)); /* 146 */ void (*tk_PhotoBlank) _ANSI_ARGS_((Tk_PhotoHandle handle)); /* 147 */ void (*tk_PhotoExpand) _ANSI_ARGS_((Tk_PhotoHandle handle, int width, int height)); /* 148 */ @@ -1104,6 +1115,8 @@ typedef struct TkStubs { void (*tk_SetInternalBorderEx) _ANSI_ARGS_((Tk_Window tkwin, int left, int right, int top, int bottom)); /* 243 */ void (*tk_SetMinimumRequestSize) _ANSI_ARGS_((Tk_Window tkwin, int minWidth, int minHeight)); /* 244 */ void (*tk_SetCaretPos) _ANSI_ARGS_((Tk_Window tkwin, int x, int y, int height)); /* 245 */ + void (*tk_PhotoPutBlock) _ANSI_ARGS_((Tk_PhotoHandle handle, Tk_PhotoImageBlock * blockPtr, int x, int y, int width, int height, int compRule)); /* 246 */ + void (*tk_PhotoPutZoomedBlock) _ANSI_ARGS_((Tk_PhotoHandle handle, Tk_PhotoImageBlock * blockPtr, int x, int y, int width, int height, int zoomX, int zoomY, int subsampleX, int subsampleY, int compRule)); /* 247 */ } TkStubs; #ifdef __cplusplus @@ -1696,13 +1709,13 @@ extern TkStubs *tkStubsPtr; #define Tk_ParseArgv \ (tkStubsPtr->tk_ParseArgv) /* 143 */ #endif -#ifndef Tk_PhotoPutBlock -#define Tk_PhotoPutBlock \ - (tkStubsPtr->tk_PhotoPutBlock) /* 144 */ +#ifndef Tk_PhotoPutBlock_Old +#define Tk_PhotoPutBlock_Old \ + (tkStubsPtr->tk_PhotoPutBlock_Old) /* 144 */ #endif -#ifndef Tk_PhotoPutZoomedBlock -#define Tk_PhotoPutZoomedBlock \ - (tkStubsPtr->tk_PhotoPutZoomedBlock) /* 145 */ +#ifndef Tk_PhotoPutZoomedBlock_Old +#define Tk_PhotoPutZoomedBlock_Old \ + (tkStubsPtr->tk_PhotoPutZoomedBlock_Old) /* 145 */ #endif #ifndef Tk_PhotoGetImage #define Tk_PhotoGetImage \ @@ -2098,6 +2111,14 @@ extern TkStubs *tkStubsPtr; #define Tk_SetCaretPos \ (tkStubsPtr->tk_SetCaretPos) /* 245 */ #endif +#ifndef Tk_PhotoPutBlock +#define Tk_PhotoPutBlock \ + (tkStubsPtr->tk_PhotoPutBlock) /* 246 */ +#endif +#ifndef Tk_PhotoPutZoomedBlock +#define Tk_PhotoPutZoomedBlock \ + (tkStubsPtr->tk_PhotoPutZoomedBlock) /* 247 */ +#endif #endif /* defined(USE_TK_STUBS) && !defined(USE_TK_STUB_PROCS) */ diff --git a/generic/tkImgGIF.c b/generic/tkImgGIF.c index 6fe4ed9..cad9ea8 100644 --- a/generic/tkImgGIF.c +++ b/generic/tkImgGIF.c @@ -29,7 +29,7 @@ * | provided "as is" without express or implied warranty. | * +-------------------------------------------------------------------+ * - * RCS: @(#) $Id: tkImgGIF.c,v 1.20 2002/02/19 14:05:43 dkf Exp $ + * RCS: @(#) $Id: tkImgGIF.c,v 1.21 2002/06/14 13:35:48 dkf Exp $ */ /* @@ -481,7 +481,8 @@ FileReadGIF(interp, chan, fileName, format, imageHandle, destX, destY, break; } - Tk_PhotoPutBlock(imageHandle, &block, destX, destY, width, height); + Tk_PhotoPutBlock(imageHandle, &block, destX, destY, width, height, + TK_PHOTO_COMPOSITE_SET); noerror: if (block.pixelPtr) { diff --git a/generic/tkImgPPM.c b/generic/tkImgPPM.c index ab99679..9715cf4 100644 --- a/generic/tkImgPPM.c +++ b/generic/tkImgPPM.c @@ -13,7 +13,7 @@ * Department of Computer Science, * Australian National University. * - * RCS: @(#) $Id: tkImgPPM.c,v 1.9 2002/02/19 16:30:26 dkf Exp $ + * RCS: @(#) $Id: tkImgPPM.c,v 1.10 2002/06/14 13:35:48 dkf Exp $ */ #define USE_OLD_IMAGE @@ -228,7 +228,8 @@ FileReadPPM(interp, chan, fileName, formatString, imageHandle, destX, destY, } } block.height = nLines; - Tk_PhotoPutBlock(imageHandle, &block, destX, destY, width, nLines); + Tk_PhotoPutBlock(imageHandle, &block, destX, destY, width, nLines, + TK_PHOTO_COMPOSITE_SET); destY += nLines; } 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); +} diff --git a/generic/tkInt.decls b/generic/tkInt.decls index 64ea04b..d0e2fd7 100644 --- a/generic/tkInt.decls +++ b/generic/tkInt.decls @@ -9,7 +9,7 @@ # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # -# RCS: @(#) $Id: tkInt.decls,v 1.26 2002/05/27 19:49:32 mdejong Exp $ +# RCS: @(#) $Id: tkInt.decls,v 1.27 2002/06/14 13:35:48 dkf Exp $ library tk @@ -657,6 +657,10 @@ declare 144 generic { void TkGCCleanup(TkDisplay *dispPtr) } +declare 145 {mac win} { + void TkSubtractRegion (TkRegion sra, TkRegion srcb, TkRegion dr_return) +} + ############################################################################## # Define the platform specific internal Tcl interface. These functions are diff --git a/generic/tkIntDecls.h b/generic/tkIntDecls.h index ecd9a28..4fcdf63 100644 --- a/generic/tkIntDecls.h +++ b/generic/tkIntDecls.h @@ -11,7 +11,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkIntDecls.h,v 1.17 2002/04/12 10:10:48 hobbs Exp $ + * RCS: @(#) $Id: tkIntDecls.h,v 1.18 2002/06/14 13:35:49 dkf Exp $ */ #ifndef _TKINTDECLS @@ -489,6 +489,16 @@ EXTERN void TkFocusFree _ANSI_ARGS_((TkMainInfo * mainPtr)); EXTERN void TkClipCleanup _ANSI_ARGS_((TkDisplay * dispPtr)); /* 144 */ EXTERN void TkGCCleanup _ANSI_ARGS_((TkDisplay * dispPtr)); +#ifdef __WIN32__ +/* 145 */ +EXTERN void TkSubtractRegion _ANSI_ARGS_((TkRegion sra, + TkRegion srcb, TkRegion dr_return)); +#endif /* __WIN32__ */ +#ifdef MAC_TCL +/* 145 */ +EXTERN void TkSubtractRegion _ANSI_ARGS_((TkRegion sra, + TkRegion srcb, TkRegion dr_return)); +#endif /* MAC_TCL */ typedef struct TkIntStubs { int magic; @@ -719,6 +729,15 @@ typedef struct TkIntStubs { void (*tkFocusFree) _ANSI_ARGS_((TkMainInfo * mainPtr)); /* 142 */ void (*tkClipCleanup) _ANSI_ARGS_((TkDisplay * dispPtr)); /* 143 */ void (*tkGCCleanup) _ANSI_ARGS_((TkDisplay * dispPtr)); /* 144 */ +#if !defined(__WIN32__) && !defined(MAC_TCL) /* UNIX */ + void *reserved145; +#endif /* UNIX */ +#ifdef __WIN32__ + void (*tkSubtractRegion) _ANSI_ARGS_((TkRegion sra, TkRegion srcb, TkRegion dr_return)); /* 145 */ +#endif /* __WIN32__ */ +#ifdef MAC_TCL + void (*tkSubtractRegion) _ANSI_ARGS_((TkRegion sra, TkRegion srcb, TkRegion dr_return)); /* 145 */ +#endif /* MAC_TCL */ } TkIntStubs; #ifdef __cplusplus @@ -1338,6 +1357,18 @@ extern TkIntStubs *tkIntStubsPtr; #define TkGCCleanup \ (tkIntStubsPtr->tkGCCleanup) /* 144 */ #endif +#ifdef __WIN32__ +#ifndef TkSubtractRegion +#define TkSubtractRegion \ + (tkIntStubsPtr->tkSubtractRegion) /* 145 */ +#endif +#endif /* __WIN32__ */ +#ifdef MAC_TCL +#ifndef TkSubtractRegion +#define TkSubtractRegion \ + (tkIntStubsPtr->tkSubtractRegion) /* 145 */ +#endif +#endif /* MAC_TCL */ #endif /* defined(USE_TK_STUBS) && !defined(USE_TK_STUB_PROCS) */ diff --git a/generic/tkStubInit.c b/generic/tkStubInit.c index cebe2ad..699defc 100644 --- a/generic/tkStubInit.c +++ b/generic/tkStubInit.c @@ -8,7 +8,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkStubInit.c,v 1.33 2002/05/27 19:49:32 mdejong Exp $ + * RCS: @(#) $Id: tkStubInit.c,v 1.34 2002/06/14 13:35:49 dkf Exp $ */ #include "tkInt.h" @@ -272,6 +272,15 @@ TkIntStubs tkIntStubs = { TkFocusFree, /* 142 */ TkClipCleanup, /* 143 */ TkGCCleanup, /* 144 */ +#if !defined(__WIN32__) && !defined(MAC_TCL) /* UNIX */ + NULL, /* 145 */ +#endif /* UNIX */ +#ifdef __WIN32__ + TkSubtractRegion, /* 145 */ +#endif /* __WIN32__ */ +#ifdef MAC_TCL + TkSubtractRegion, /* 145 */ +#endif /* MAC_TCL */ }; TkIntPlatStubs tkIntPlatStubs = { @@ -785,8 +794,8 @@ TkStubs tkStubs = { Tk_NameToWindow, /* 141 */ Tk_OwnSelection, /* 142 */ Tk_ParseArgv, /* 143 */ - Tk_PhotoPutBlock, /* 144 */ - Tk_PhotoPutZoomedBlock, /* 145 */ + Tk_PhotoPutBlock_Old, /* 144 */ + Tk_PhotoPutZoomedBlock_Old, /* 145 */ Tk_PhotoGetImage, /* 146 */ Tk_PhotoBlank, /* 147 */ Tk_PhotoExpand, /* 148 */ @@ -887,6 +896,8 @@ TkStubs tkStubs = { Tk_SetInternalBorderEx, /* 243 */ Tk_SetMinimumRequestSize, /* 244 */ Tk_SetCaretPos, /* 245 */ + Tk_PhotoPutBlock, /* 246 */ + Tk_PhotoPutZoomedBlock, /* 247 */ }; /* !END!: Do not edit above this line. */ diff --git a/mac/tkMacRegion.c b/mac/tkMacRegion.c index c2a70ae..86e193e 100644 --- a/mac/tkMacRegion.c +++ b/mac/tkMacRegion.c @@ -8,7 +8,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkMacRegion.c,v 1.3 1999/05/22 06:35:00 jingham Exp $ + * RCS: @(#) $Id: tkMacRegion.c,v 1.4 2002/06/14 13:35:49 dkf Exp $ */ #include "tkInt.h" @@ -216,3 +216,33 @@ TkClipBox( rect_return->width = (**rgn).rgnBBox.right - (**rgn).rgnBBox.left; rect_return->height = (**rgn).rgnBBox.bottom - (**rgn).rgnBBox.top; } + +/* + *---------------------------------------------------------------------- + * + * TkSubtractRegion -- + * + * Implements the equivilent of the X window function + * XSubtractRegion. See X window documentation for more details. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +void +TkSubtractRegion( + TkRegion sra, + TkRegion srb, + TkRegion dr_return) +{ + RgnHandle srcRgnA = (RgnHandle) sra; + RgnHandle srcRgnB = (RgnHandle) srb; + RgnHandle destRgn = (RgnHandle) dr_return; + + DiffRgn(srcRgnA, srcRgnB, destRgn); +} diff --git a/tests/imgPhoto.test b/tests/imgPhoto.test index 320b289..04c813d 100644 --- a/tests/imgPhoto.test +++ b/tests/imgPhoto.test @@ -9,7 +9,7 @@ # # Author: Paul Mackerras (paulus@cs.anu.edu.au) # -# RCS: @(#) $Id: imgPhoto.test,v 1.9 2002/02/01 14:27:30 dkf Exp $ +# RCS: @(#) $Id: imgPhoto.test,v 1.10 2002/06/14 13:35:49 dkf Exp $ if {[lsearch [namespace children] ::tcltest] == -1} { source [file join [pwd] [file dirname [info script]] defs.tcl] @@ -27,7 +27,7 @@ canvas .c pack .c update -# temporarily copy the README fiel from testsDir to tmpDir +# temporarily copy the README file from testsDir to tmpDir if {![file exists README]} { set newREADME [file join $::tcltest::workingDir README] file copy [file join $::tcltest::testsDir README] $newREADME @@ -95,7 +95,7 @@ test imgPhoto-2.2 {ImgPhotoCreate procedure} { eval image delete [image names] image create photo image1 list [info commands image1] [image names] \ - [image width image1] [image height image1] + [image width image1] [image height image1] } {image1 image1 0 0} # test imgPhoto-2.3 {ImgPhotoCreate procedure: creation failure} { # image create photo p1 @@ -167,13 +167,13 @@ test imgPhoto-4.10 {ImgPhotoCmd procedure: copy option} { } {256 256 {169 117 90}} test imgPhoto-4.11 {ImgPhotoCmd procedure: copy option} { list [catch {p1 copy} msg] $msg -} {1 {wrong # args: should be "p1 copy source-image ?-from x1 y1 x2 y2? ?-to x1 y1 x2 y2? ?-zoom x y? ?-subsample x y?"}} +} {1 {wrong # args: should be "p1 copy source-image ?-compositingrule rule? ?-from x1 y1 x2 y2? ?-to x1 y1 x2 y2? ?-zoom x y? ?-subsample x y?"}} test imgPhoto-4.12 {ImgPhotoCmd procedure: copy option} { list [catch {p1 copy blah} msg] $msg } {1 {image "blah" doesn't exist or is not a photo image}} test imgPhoto-4.13 {ImgPhotoCmd procedure: copy option} { list [catch {p1 copy p2 -blah} msg] $msg -} {1 {unrecognized option "-blah": must be -from, -shrink, -subsample, -to, or -zoom}} +} {1 {unrecognized option "-blah": must be -compositingrule, -from, -shrink, -subsample, -to, or -zoom}} test imgPhoto-4.14 {ImgPhotoCmd procedure: copy option} { list [catch {p1 copy p2 -from -to} msg] $msg } {1 {the "-from" option requires one to four integer values}} @@ -415,9 +415,46 @@ proc checkImgTransLoopResetSet {img width height} { test imgPhoto-4.68 {ImgPhotoCmd procedure: transparency set option} { checkImgTransLoopResetSet p1 3 3 } {0 1 0 2 1 0 1 1 1 2 2 0 2 1 2 2 , 0 0 0 1 0 2 1 0 1 1 1 2 2 0 2 1 2 2 . 0 0 0 2 1 0 1 1 1 2 2 0 2 1 2 2 , 0 0 0 1 0 2 1 0 1 1 1 2 2 0 2 1 2 2 . 0 0 0 1 1 0 1 1 1 2 2 0 2 1 2 2 , 0 0 0 1 0 2 1 0 1 1 1 2 2 0 2 1 2 2 . 0 0 0 1 0 2 1 1 1 2 2 0 2 1 2 2 , 0 0 0 1 0 2 1 0 1 1 1 2 2 0 2 1 2 2 . 0 0 0 1 0 2 1 0 1 2 2 0 2 1 2 2 , 0 0 0 1 0 2 1 0 1 1 1 2 2 0 2 1 2 2 . 0 0 0 1 0 2 1 0 1 1 2 0 2 1 2 2 , 0 0 0 1 0 2 1 0 1 1 1 2 2 0 2 1 2 2 . 0 0 0 1 0 2 1 0 1 1 1 2 2 1 2 2 , 0 0 0 1 0 2 1 0 1 1 1 2 2 0 2 1 2 2 . 0 0 0 1 0 2 1 0 1 1 1 2 2 0 2 2 , 0 0 0 1 0 2 1 0 1 1 1 2 2 0 2 1 2 2 . 0 0 0 1 0 2 1 0 1 1 1 2 2 0 2 1 , 0 0 0 1 0 2 1 0 1 1 1 2 2 0 2 1 2 2 .} -catch {rename checkImgTrans {}} catch {rename checkImgTransLoopSetReset {}} catch {rename checkImgTransLoopResetSet {}} +# Test the compositing rules for copying images +image create photo p1 -width 3 -height 3 +image create photo p2 -width 2 -height 2 +test imgPhoto-4.68 {ImgPhotoCmd procedure: copy with -compositingrule} { + list [catch {p1 copy p2 -to 1 1 -compositingrule} msg] $msg +} {1 {the "-compositingrule" option requires a value}} +test imgPhoto-4.69 {ImgPhotoCmd procedure: copy with -compositingrule} { + list [catch {p1 copy p2 -to 1 1 -compositingrule BAD} msg] $msg +} {1 {bad compositing rule "BAD": must be overlay or set}} +test imgPhoto-4.70 {ImgPhotoCmd procedure: copy with -compositingrule} { + # Tests default compositing rule + p1 blank + p2 blank + p1 put white -to 0 0 2 2 + p2 put white -to 0 0 2 2 + p2 transparency set 0 0 true + p1 copy p2 -to 1 1 + checkImgTrans p1 3 3 +} {0 2 2 0} +test imgPhoto-4.71 {ImgPhotoCmd procedure: copy with -compositingrule} { + p1 blank + p2 blank + p1 put white -to 0 0 2 2 + p2 put white -to 0 0 2 2 + p2 transparency set 0 0 true + p1 copy p2 -to 1 1 -compositingrule overlay + checkImgTrans p1 3 3 +} {0 2 2 0} +test imgPhoto-4.72 {ImgPhotoCmd procedure: copy with -compositingrule} { + p1 blank + p2 blank + p1 put white -to 0 0 2 2 + p2 put white -to 0 0 2 2 + p2 transparency set 0 0 true + p1 copy p2 -to 1 1 -compositingrule set + checkImgTrans p1 3 3 +} {0 2 1 1 2 0} +catch {rename checkImgTrans {}} test imgPhoto-5.1 {ImgPhotoGet/Free procedures, shared instances} { eval image delete [image names] diff --git a/unix/tkUnixPort.h b/unix/tkUnixPort.h index 6e51fe7..dbde1f2 100644 --- a/unix/tkUnixPort.h +++ b/unix/tkUnixPort.h @@ -11,7 +11,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkUnixPort.h,v 1.7 2001/09/25 16:25:20 dgp Exp $ + * RCS: @(#) $Id: tkUnixPort.h,v 1.8 2002/06/14 13:35:49 dkf Exp $ */ #ifndef _UNIXPORT @@ -145,6 +145,8 @@ extern int errno; (Region) b, (Region) r) #define TkRectInRegion(r, x, y, w, h) XRectInRegion((Region) r, x, y, w, h) #define TkSetRegion(d, gc, rgn) XSetRegion(d, gc, (Region) rgn) +#define TkSubtractRegion(a, b, r) XSubtractRegion((Region) a, \ + (Region) b, (Region) r) #define TkUnionRectWithRegion(rect, src, ret) XUnionRectWithRegion(rect, \ (Region) src, (Region) ret) diff --git a/win/tkWinRegion.c b/win/tkWinRegion.c index c7be771..8a50620 100644 --- a/win/tkWinRegion.c +++ b/win/tkWinRegion.c @@ -8,7 +8,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkWinRegion.c,v 1.2 1998/09/14 18:24:01 stanton Exp $ + * RCS: @(#) $Id: tkWinRegion.c,v 1.3 2002/06/14 13:35:49 dkf Exp $ */ #include "tkWinInt.h" @@ -177,3 +177,28 @@ TkRectInRegion(r, x, y, width, height) rect.right = x+width; return RectInRegion((HRGN)r, &rect) ? RectanglePart : RectangleOut; } + +/* + *---------------------------------------------------------------------- + * + * TkSubtractRegion -- + * + * Compute the set-difference of two regions. + * + * Results: + * Returns the result in the dr_return region. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +void +TkSubtractRegion(sra, srb, dr_return) + TkRegion sra; + TkRegion srb; + TkRegion dr_return; +{ + CombineRgn((HRGN) dr_return, (HRGN) sra, (HRGN) srb, RGN_DIFF); +} -- cgit v0.12