* tkImgPhoto.c --
*
* Implements images of type "photo" for Tk. Photo images are
- * stored in full color (24 bits per pixel) and displayed using
+ * stored in full color (32 bits per pixel) and displayed using
* dithering if necessary.
*
* Copyright (c) 1994 The Australian National University.
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
+ * Author: Paul Mackerras (paulus@cs.anu.edu.au),
+ * Department of Computer Science,
+ * Australian National University.
+ *
* RCS: @(#) $Id$
*/
#include "tclMath.h"
#include <ctype.h>
+#ifdef __WIN32__
+#include "tkWinInt.h"
+#endif
+
/*
* Declaration for internal Xlib function used here:
*/
-extern _XInitImageFuncPtrs _ANSI_ARGS_((XImage *image));
+extern int _XInitImageFuncPtrs _ANSI_ARGS_((XImage *image));
/*
* A signed 8-bit integral type. If chars are unsigned and the compiler
* MAP_COLORS: 1 means pixel values should be mapped
* through pixelMap.
*/
+#ifdef COLOR_WINDOW
+#undef COLOR_WINDOW
+#endif
#define BLACK_AND_WHITE 1
#define COLOR_WINDOW 2
* instances of this image. */
double gamma; /* Display gamma value to correct for. */
char *fileString; /* Name of file to read into image. */
- Tcl_Obj *dataObj; /* Object to use as contents of image. */
- char *format; /* User-specified format of data in image
+ Tcl_Obj *dataString; /* Object to use as contents of image. */
+ Tcl_Obj *format; /* User-specified format of data in image
* file or string value. */
unsigned char *pix24; /* Local storage for 24-bit image. */
int ditherX, ditherY; /* Location of first incorrectly
struct SubcommandOptions {
int options; /* Individual bits indicate which
* options were specified - see below. */
- char *name; /* Name specified without an option. */
+ Tcl_Obj *name; /* Name specified without an option. */
int fromX, fromY; /* Values specified for -from option. */
int fromX2, fromY2; /* Second coordinate pair for -from option. */
int toX, toY; /* Values specified for -to option. */
int toX2, toY2; /* Second coordinate pair for -to option. */
int zoomX, zoomY; /* Values specified for -zoom option. */
int subsampleX, subsampleY; /* Values specified for -subsample option. */
- char *format; /* Value specified for -format option. */
+ Tcl_Obj *format; /* Value specified for -format option. */
XColor *background; /* Value specified for -background option. */
};
*/
static int ImgPhotoCreate _ANSI_ARGS_((Tcl_Interp *interp,
- char *name, int argc, Tcl_Obj *CONST objv[],
+ char *name, int objc, Tcl_Obj *CONST objv[],
Tk_ImageType *typePtr, Tk_ImageMaster master,
ClientData *clientDataPtr));
static ClientData ImgPhotoGet _ANSI_ARGS_((Tk_Window tkwin,
static void ImgPhotoFree _ANSI_ARGS_((ClientData clientData,
Display *display));
static void ImgPhotoDelete _ANSI_ARGS_((ClientData clientData));
+static int ImgPhotoPostscript _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, Tk_Window tkwin,
+ Tk_PostscriptInfo psInfo, int x, int y, int width,
+ int height, int prepass));
Tk_ImageType tkPhotoImageType = {
"photo", /* name */
ImgPhotoDisplay, /* displayProc */
ImgPhotoFree, /* freeProc */
ImgPhotoDelete, /* deleteProc */
+ ImgPhotoPostscript, /* postscriptProc */
(Tk_ImageType *) NULL /* nextPtr */
};
+typedef struct ThreadSpecificData {
+ Tk_PhotoImageFormat *formatList; /* Pointer to the first in the
+ * list of known photo image formats.*/
+ Tk_PhotoImageFormat *oldFormatList; /* Pointer to the first in the
+ * list of known photo image formats.*/
+} ThreadSpecificData;
+static Tcl_ThreadDataKey dataKey;
+
/*
* Default configuration
*/
* Information used for parsing configuration specifications:
*/
static Tk_ConfigSpec configSpecs[] = {
- {TK_CONFIG_STRING, "-format", (char *) NULL, (char *) NULL,
- (char *) NULL, Tk_Offset(PhotoMaster, format), TK_CONFIG_NULL_OK},
{TK_CONFIG_STRING, "-file", (char *) NULL, (char *) NULL,
(char *) NULL, Tk_Offset(PhotoMaster, fileString), TK_CONFIG_NULL_OK},
{TK_CONFIG_DOUBLE, "-gamma", (char *) NULL, (char *) NULL,
#define N_COLOR_HASH (sizeof(ColorTableId) / sizeof(int))
/*
- * Pointer to the first in the list of known photo image formats.
- */
-
-static Tk_PhotoImageFormat *formatList = NULL;
-
-/*
* Forward declarations
*/
static int ImgPhotoCmd _ANSI_ARGS_((ClientData clientData,
- Tcl_Interp *interp, int argc, Tcl_Obj *CONST objv[]));
+ Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[]));
static int ParseSubcommandOptions _ANSI_ARGS_((
struct SubcommandOptions *optPtr,
Tcl_Interp *interp, int allowedOptions,
- int *indexPtr, int argc, char **argv));
+ int *indexPtr, int objc, Tcl_Obj *CONST objv[]));
static void ImgPhotoCmdDeletedProc _ANSI_ARGS_((
ClientData clientData));
static int ImgPhotoConfigureMaster _ANSI_ARGS_((
Tcl_Interp *interp, PhotoMaster *masterPtr,
- int argc, Tcl_Obj *CONST objv[], int flags));
+ int objc, Tcl_Obj *CONST objv[], int flags));
static void ImgPhotoConfigureInstance _ANSI_ARGS_((
PhotoInstance *instancePtr));
static void ImgPhotoSetSize _ANSI_ARGS_((PhotoMaster *masterPtr,
static void ImgPhotoInstanceSetSize _ANSI_ARGS_((
PhotoInstance *instancePtr));
static int ImgStringWrite _ANSI_ARGS_((Tcl_Interp *interp,
- Tcl_DString *dataPtr, char *formatString,
+ Tcl_Obj *formatString,
Tk_PhotoImageBlock *blockPtr));
static char * ImgGetPhoto _ANSI_ARGS_((PhotoMaster *masterPtr,
Tk_PhotoImageBlock *blockPtr,
static int ReclaimColors _ANSI_ARGS_((ColorTableId *id,
int numColors));
static int MatchFileFormat _ANSI_ARGS_((Tcl_Interp *interp,
- Tcl_Channel chan, char *fileName,
- char *formatString,
+ Tcl_Channel chan, char *fileName, Tcl_Obj *formatString,
Tk_PhotoImageFormat **imageFormatPtr,
- int *widthPtr, int *heightPtr));
+ int *widthPtr, int *heightPtr, int *oldformat));
static int MatchStringFormat _ANSI_ARGS_((Tcl_Interp *interp,
- Tcl_Obj *dataObj, char *formatString,
+ Tcl_Obj *data, Tcl_Obj *formatString,
Tk_PhotoImageFormat **imageFormatPtr,
- int *widthPtr, int *heightPtr));
-static void Dither _ANSI_ARGS_((PhotoMaster *masterPtr,
- int x, int y, int width, int height));
+ int *widthPtr, int *heightPtr, int *oldformat));
+static Tcl_ObjCmdProc * PhotoOptionFind _ANSI_ARGS_((Tcl_Interp * interp,
+ Tcl_Obj *obj));
static void DitherInstance _ANSI_ARGS_((PhotoInstance *instancePtr,
int x, int y, int width, int height));
+static void PhotoOptionCleanupProc _ANSI_ARGS_((
+ ClientData clientData, Tcl_Interp *interp));
#undef MIN
#define MIN(a, b) ((a) < (b)? (a): (b))
/*
*----------------------------------------------------------------------
*
- * Tk_CreatePhotoImageFormat --
+ * Tk_CreateOldPhotoImageFormat, Tk_CreatePhotoImageFormat --
*
* This procedure is invoked by an image file handler to register
* a new photo image format and the procedures that handle the
*
*----------------------------------------------------------------------
*/
+void
+Tk_CreateOldPhotoImageFormat(formatPtr)
+ Tk_PhotoImageFormat *formatPtr;
+ /* Structure describing the format. All of
+ * the fields except "nextPtr" must be filled
+ * in by caller. Must not have been passed
+ * to Tk_CreatePhotoImageFormat previously. */
+{
+ Tk_PhotoImageFormat *copyPtr;
+ ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
+ Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
+
+ copyPtr = (Tk_PhotoImageFormat *) ckalloc(sizeof(Tk_PhotoImageFormat));
+ *copyPtr = *formatPtr;
+ copyPtr->name = (char *) ckalloc((unsigned) (strlen(formatPtr->name) + 1));
+ strcpy(copyPtr->name, formatPtr->name);
+ copyPtr->nextPtr = tsdPtr->oldFormatList;
+ tsdPtr->oldFormatList = copyPtr;
+}
void
Tk_CreatePhotoImageFormat(formatPtr)
* to Tk_CreatePhotoImageFormat previously. */
{
Tk_PhotoImageFormat *copyPtr;
+ ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
+ Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
copyPtr = (Tk_PhotoImageFormat *) ckalloc(sizeof(Tk_PhotoImageFormat));
*copyPtr = *formatPtr;
copyPtr->name = (char *) ckalloc((unsigned) (strlen(formatPtr->name) + 1));
strcpy(copyPtr->name, formatPtr->name);
- copyPtr->nextPtr = formatList;
- formatList = copyPtr;
+ if (isupper((unsigned char) *formatPtr->name)) {
+ copyPtr->nextPtr = tsdPtr->oldFormatList;
+ tsdPtr->oldFormatList = copyPtr;
+ } else {
+ copyPtr->nextPtr = tsdPtr->formatList;
+ tsdPtr->formatList = copyPtr;
+ }
}
\f
/*
*/
static int
-ImgPhotoCreate(interp, name, argc, objv, typePtr, master, clientDataPtr)
+ImgPhotoCreate(interp, name, objc, objv, typePtr, master, clientDataPtr)
Tcl_Interp *interp; /* Interpreter for application containing
* image. */
char *name; /* Name to use for image. */
- int argc; /* Number of arguments. */
+ int objc; /* Number of arguments. */
Tcl_Obj *CONST objv[]; /* Argument objects for options (doesn't
* include image name or type). */
Tk_ImageType *typePtr; /* Pointer to our type record (not used). */
* Process configuration options given in the image create command.
*/
- if (ImgPhotoConfigureMaster(interp, masterPtr, argc, objv, 0) != TCL_OK) {
+ if (ImgPhotoConfigureMaster(interp, masterPtr, objc, objv, 0) != TCL_OK) {
ImgPhotoDelete((ClientData) masterPtr);
return TCL_ERROR;
}
*/
static int
-ImgPhotoCmd(clientData, interp, argc, objv)
+ImgPhotoCmd(clientData, interp, objc, objv)
ClientData clientData; /* Information about photo master. */
Tcl_Interp *interp; /* Current interpreter. */
- int argc; /* Number of arguments. */
+ int objc; /* Number of arguments. */
Tcl_Obj *CONST objv[]; /* Argument objects. */
{
+ int oldformat = 0;
+ static char *photoOptions[] = {
+ "blank", "cget", "configure", "copy", "data", "get", "put",
+ "read", "redither", "write", (char *) NULL
+ };
+ enum options {
+ PHOTO_BLANK, PHOTO_CGET, PHOTO_CONFIGURE, PHOTO_COPY, PHOTO_DATA,
+ PHOTO_GET, PHOTO_PUT, PHOTO_READ, PHOTO_REDITHER, PHOTO_WRITE
+ };
+
PhotoMaster *masterPtr = (PhotoMaster *) clientData;
- int c, result, index;
+ int result, index;
int x, y, width, height;
int dataWidth, dataHeight;
struct SubcommandOptions options;
unsigned char *pixelPtr;
Tk_PhotoImageBlock block;
Tk_Window tkwin;
- char string[16];
XColor color;
Tk_PhotoImageFormat *imageFormat;
int imageWidth, imageHeight;
Tcl_Channel chan;
Tk_PhotoHandle srcHandle;
size_t length;
- static char **argv = NULL;
+ ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
+ Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
- if (argc < 2) {
- Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
- " option ?arg arg ...?\"", (char *) NULL);
+ if (objc < 2) {
+ Tcl_WrongNumArgs(interp, 1, objv, "option ?arg arg ...?");
return TCL_ERROR;
}
- if (argv) {
- ckfree((char *) argv);
- }
- argv = (char **) ckalloc((argc+1) * sizeof(char *));
- argv[argc] = NULL;
- for (index = 0; index < argc; index++) {
- argv[index] = Tcl_GetStringFromObj(objv[index], (int *) NULL);
+ if (Tcl_GetIndexFromObj(interp, objv[1], photoOptions, "option", 0,
+ &index) != TCL_OK) {
+ Tcl_ObjCmdProc *proc;
+ proc = PhotoOptionFind(interp, objv[1]);
+ if (proc == (Tcl_ObjCmdProc *) NULL) {
+ return TCL_ERROR;
+ }
+ return proc(clientData, interp, objc, objv);
}
- c = argv[1][0];
- length = strlen(argv[1]);
-
- if ((c == 'b') && (strncmp(argv[1], "blank", length) == 0)) {
+ switch ((enum options) index) {
+ case PHOTO_BLANK: {
/*
* photo blank command - just call Tk_PhotoBlank.
*/
- if (argc == 2) {
+ if (objc == 2) {
Tk_PhotoBlank(masterPtr);
} else {
- Tcl_AppendResult(interp, "wrong # args: should be \"",
- argv[0], " blank\"", (char *) NULL);
+ Tcl_WrongNumArgs(interp, 2, objv, (char *) NULL);
return TCL_ERROR;
}
- } else if ((c == 'c') && (length >= 2)
- && (strncmp(argv[1], "cget", length) == 0)) {
- if (argc != 3) {
- Tcl_AppendResult(interp, "wrong # args: should be \"",
- argv[0], " cget option\"",
- (char *) NULL);
+ break;
+ }
+ case PHOTO_CGET: {
+ char *arg;
+ if (objc != 3) {
+ Tcl_WrongNumArgs(interp, 2, objv, "option");
return TCL_ERROR;
}
- if (strncmp(argv[2],"-data", length) == 0) {
- if (masterPtr->dataObj) {
- Tcl_SetObjResult(interp, masterPtr->dataObj);
+ arg = Tcl_GetStringFromObj(objv[2], (int *) &length);
+ if (strncmp(arg,"-data", length) == 0) {
+ if (masterPtr->dataString) {
+ Tcl_SetObjResult(interp, masterPtr->dataString);
+ }
+ return TCL_OK;
+ }
+ if (strncmp(arg,"-format", length) == 0) {
+ if (masterPtr->format) {
+ Tcl_SetObjResult(interp, masterPtr->format);
}
return TCL_OK;
}
Tk_ConfigureValue(interp, Tk_MainWindow(interp), configSpecs,
- (char *) masterPtr, argv[2], 0);
- } else if ((c == 'c') && (length >= 3)
- && (strncmp(argv[1], "configure", length) == 0)) {
+ (char *) masterPtr, Tcl_GetString(objv[2]), 0);
+ break;
+ }
+ case PHOTO_CONFIGURE: {
/*
* photo configure command - handle this in the standard way.
*/
char *opt, *arg;
- if (argc == 2) {
+ if (objc == 2) {
+ Tcl_Obj *obj, *subobj;
result = Tk_ConfigureInfo(interp, Tk_MainWindow(interp),
configSpecs, (char *) masterPtr, (char *) NULL, 0);
if (result != TCL_OK) {
return result;
}
- opt = Tcl_GetStringFromObj(Tcl_GetObjResult(interp), &length);
- arg = (char *) ckalloc(length + 1);
- strcpy(arg, opt);
- Tcl_ResetResult(interp);
- Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
- "{-data {} {} {} {}} ", arg, (char*) NULL);
- ckfree(arg);
+ obj = Tcl_NewObj();
+ subobj = Tcl_NewStringObj("-data {} {} {}", 14);
+ if (masterPtr->dataString) {
+ Tcl_ListObjAppendElement(interp, subobj, masterPtr->dataString);
+ } else {
+ Tcl_AppendStringsToObj(subobj, " {}", (char *) NULL);
+ }
+ Tcl_ListObjAppendElement(interp, obj, subobj);
+ subobj = Tcl_NewStringObj("-format {} {} {}", 16);
+ if (masterPtr->format) {
+ Tcl_ListObjAppendElement(interp, subobj, masterPtr->format);
+ } else {
+ Tcl_AppendStringsToObj(subobj, " {}", (char *) NULL);
+ }
+ Tcl_ListObjAppendElement(interp, obj, subobj);
+ Tcl_ListObjAppendList(interp, obj, Tcl_GetObjResult(interp));
+ Tcl_SetObjResult(interp, obj);
return TCL_OK;
}
- if (argc == 3) {
- if (strncmp(argv[2], "-data", length)) {
- return Tk_ConfigureInfo(interp, Tk_MainWindow(interp),
- configSpecs, (char *) masterPtr, argv[2], 0);
- } else {
+ if (objc == 3) {
+ char *arg = Tcl_GetStringFromObj(objv[2], (int *) &length);
+ if (!strncmp(arg, "-data", length)) {
+ Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
+ "-data {} {} {}", (char *) NULL);
+ if (masterPtr->dataString) {
+ Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp),
+ masterPtr->dataString);
+ } else {
+ Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
+ " {}", (char *) NULL);
+ }
+ return TCL_OK;
+ } else if (!strncmp(arg, "-format", length)) {
Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
- "-data {} {} {} ", (char *) NULL);
- if (masterPtr->dataObj) {
+ "-format {} {} {}", (char *) NULL);
+ if (masterPtr->format) {
Tcl_ListObjAppendElement(interp, Tcl_GetObjResult(interp),
- masterPtr->dataObj);
+ masterPtr->format);
} else {
Tcl_AppendStringsToObj(Tcl_GetObjResult(interp),
- "{}", (char *) NULL);
+ " {}", (char *) NULL);
}
return TCL_OK;
+ } else {
+ return Tk_ConfigureInfo(interp, Tk_MainWindow(interp),
+ configSpecs, (char *) masterPtr, arg, 0);
}
}
- return ImgPhotoConfigureMaster(interp, masterPtr, argc-2, objv+2,
+ return ImgPhotoConfigureMaster(interp, masterPtr, objc-2, objv+2,
TK_CONFIG_ARGV_ONLY);
- } else if ((c == 'c') && (length >= 3)
- && (strncmp(argv[1], "copy", length) == 0)) {
+ break;
+ }
+ case PHOTO_COPY: {
/*
* photo copy command - first parse options.
*/
options.name = NULL;
if (ParseSubcommandOptions(&options, interp,
OPT_FROM | OPT_TO | OPT_ZOOM | OPT_SUBSAMPLE | OPT_SHRINK,
- &index, argc, argv) != TCL_OK) {
+ &index, objc, objv) != TCL_OK) {
return TCL_ERROR;
}
- if (options.name == NULL || index < argc) {
- Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
- " copy source-image ?-from x1 y1 x2 y2?",
- " ?-to x1 y1 x2 y2? ?-zoom x y? ?-subsample x y?",
- "\"", (char *) NULL);
+ 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?");
return TCL_ERROR;
}
* Check the values given for the -from option.
*/
- if ((srcHandle = Tk_FindPhoto(interp, options.name)) == NULL) {
- Tcl_AppendResult(interp, "image \"", argv[2], "\" doesn't",
+ if ((srcHandle = Tk_FindPhoto(interp, Tcl_GetString(options.name))) == NULL) {
+ Tcl_AppendResult(interp, "image \"",
+ Tcl_GetString(options.name), "\" doesn't",
" exist or is not a photo image", (char *) NULL);
return TCL_ERROR;
}
options.toY2 - options.toY, options.zoomX, options.zoomY,
options.subsampleX, options.subsampleY);
- } else if ((c == 'd') && (strncmp(argv[1], "data", length) == 0)) {
- Tcl_DString buffer;
+ break;
+ }
+ case PHOTO_DATA: {
char *data;
/*
options.fromY = 0;
if (ParseSubcommandOptions(&options, interp,
OPT_FORMAT | OPT_FROM | OPT_GRAYSCALE | OPT_BACKGROUND,
- &index, argc, argv) != TCL_OK) {
+ &index, objc, objv) != TCL_OK) {
return TCL_ERROR;
}
- if ((options.name != NULL) || (index < argc)) {
- Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
- " data ?-format format-name?",
- "?-from x1 y1 x2 y2?\"", (char *) NULL);
+ if ((options.name != NULL) || (index < objc)) {
+ Tcl_WrongNumArgs(interp, 2, objv, "?options?");
return TCL_ERROR;
}
if ((options.fromX > masterPtr->width)
*/
if (options.options & OPT_FORMAT) {
- for (imageFormat = formatList; imageFormat != NULL;
+ for (imageFormat = tsdPtr->formatList; imageFormat != NULL;
imageFormat = imageFormat->nextPtr) {
- if ((strncasecmp(options.format, imageFormat->name,
- strlen(imageFormat->name)) == 0)) {
+ if ((strncasecmp(Tcl_GetString(options.format),
+ imageFormat->name, strlen(imageFormat->name)) == 0)) {
if (imageFormat->stringWriteProc != NULL) {
stringWriteProc = imageFormat->stringWriteProc;
break;
}
}
if (stringWriteProc == NULL) {
- Tcl_AppendResult(interp, "image string format \"", options.format,
+ Tcl_AppendResult(interp, "image string format \"",
+ Tcl_GetString(options.format),
"\" is not supported", (char *) NULL);
return TCL_ERROR;
}
*/
data = ImgGetPhoto(masterPtr, &block, &options);
- Tcl_DStringInit(&buffer);
- result = stringWriteProc(interp, &buffer,
- options.format, &block);
+ result = ((int (*) _ANSI_ARGS_((Tcl_Interp *interp, Tcl_Obj *formatString,
+ Tk_PhotoImageBlock *blockPtr, VOID *dummy))) stringWriteProc)
+ (interp, options.format, &block, (VOID *) NULL);
if (options.background) {
Tk_FreeColor(options.background);
}
if (data) {
ckfree(data);
}
- if (result == TCL_OK) {
- Tcl_DStringResult(interp, &buffer);
- } else {
- Tcl_DStringFree(&buffer);
- }
return result;
- } else if ((c == 'g') && (strncmp(argv[1], "get", length) == 0)) {
+ break;
+ }
+ case PHOTO_GET: {
/*
* photo get command - first parse and check parameters.
*/
- if (argc != 4) {
- Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
- " get x y\"", (char *) NULL);
+ char string[TCL_INTEGER_SPACE * 3];
+
+ if (objc != 4) {
+ Tcl_WrongNumArgs(interp, 2, objv, "x y");
return TCL_ERROR;
}
- if ((Tcl_GetInt(interp, argv[2], &x) != TCL_OK)
- || (Tcl_GetInt(interp, argv[3], &y) != TCL_OK)) {
+ if ((Tcl_GetIntFromObj(interp, objv[2], &x) != TCL_OK)
+ || (Tcl_GetIntFromObj(interp, objv[3], &y) != TCL_OK)) {
return TCL_ERROR;
}
if ((x < 0) || (x >= masterPtr->width)
|| (y < 0) || (y >= masterPtr->height)) {
- Tcl_AppendResult(interp, argv[0], " get: ",
+ Tcl_AppendResult(interp, Tcl_GetString(objv[0]), " get: ",
"coordinates out of range", (char *) NULL);
return TCL_ERROR;
}
sprintf(string, "%d %d %d", pixelPtr[0], pixelPtr[1],
pixelPtr[2]);
Tcl_AppendResult(interp, string, (char *) NULL);
- } else if ((c == 'p') && (strncmp(argv[1], "put", length) == 0)) {
+ break;
+ }
+ case PHOTO_PUT: {
/*
* photo put command - first parse the options and colors specified.
*/
memset((VOID *) &options, 0, sizeof(options));
options.name = NULL;
if (ParseSubcommandOptions(&options, interp, OPT_TO|OPT_FORMAT,
- &index, argc, argv) != TCL_OK) {
+ &index, objc, objv) != TCL_OK) {
return TCL_ERROR;
}
- if ((options.name == NULL) || (index < argc)) {
- Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
- " put data ?-format format? ?-to x1 y1 x2 y2?\"",
- (char *) NULL);
+ if ((options.name == NULL) || (index < objc)) {
+ Tcl_WrongNumArgs(interp, 2, objv, "data ?options?");
return TCL_ERROR;
}
if (MatchStringFormat(interp, options.name ? objv[2]:NULL,
options.format, &imageFormat, &imageWidth,
- &imageHeight) == TCL_OK) {
+ &imageHeight, &oldformat) == TCL_OK) {
+ Tcl_Obj *format;
+ Tcl_Obj *data;
if (((options.options & OPT_TO) == 0) || (options.toX2 < 0)) {
options.toX2 = options.toX + imageWidth;
options.toY2 = options.toY + imageHeight;
if (imageHeight > options.toY2 - options.toY) {
imageHeight = options.toY2 - options.toY;
}
- if ((*imageFormat->stringReadProc)(interp, objv[2],
- options.format, (Tk_PhotoHandle) masterPtr,
+ format = options.format;
+ data = objv[2];
+ if (oldformat) {
+ if (format) {
+ format = (Tcl_Obj *) Tcl_GetString(format);
+ }
+ data = (Tcl_Obj *) Tcl_GetString(data);
+ }
+ if ((*imageFormat->stringReadProc)(interp, data,
+ format, (Tk_PhotoHandle) masterPtr,
0, 0, imageWidth, imageHeight, options.toX, options.toY)
!= TCL_OK) {
return TCL_ERROR;
return TCL_ERROR;
}
Tcl_ResetResult(interp);
- if (Tcl_SplitList(interp, options.name, &dataHeight, &srcArgv)
+ if (Tcl_SplitList(interp, Tcl_GetString(options.name),
+ &dataHeight, &srcArgv)
!= TCL_OK) {
return TCL_ERROR;
}
block.offset[0] = 0;
block.offset[1] = 1;
block.offset[2] = 2;
+ block.offset[3] = 0;
Tk_PhotoPutBlock((ClientData)masterPtr, &block,
options.toX, options.toY, options.toX2 - options.toX,
options.toY2 - options.toY);
ckfree((char *) block.pixelPtr);
- } else if ((c == 'r') && (length >= 3)
- && (strncmp(argv[1], "read", length) == 0)) {
+ break;
+ }
+ case PHOTO_READ: {
/*
* photo read command - first parse the options specified.
*/
+ Tcl_Obj *format;
index = 2;
memset((VOID *) &options, 0, sizeof(options));
options.name = NULL;
options.format = NULL;
if (ParseSubcommandOptions(&options, interp,
OPT_FORMAT | OPT_FROM | OPT_TO | OPT_SHRINK,
- &index, argc, argv) != TCL_OK) {
+ &index, objc, objv) != TCL_OK) {
return TCL_ERROR;
}
- if ((options.name == NULL) || (index < argc)) {
- Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
- " read fileName ?-format format-name?",
- " ?-from x1 y1 x2 y2? ?-to x y? ?-shrink?\"",
- (char *) NULL);
+ if ((options.name == NULL) || (index < objc)) {
+ Tcl_WrongNumArgs(interp, 2, objv,
+ "fileName ?options?");
return TCL_ERROR;
}
* Open the image file and look for a handler for it.
*/
- chan = Tcl_OpenFileChannel(interp, options.name, "r", 0);
+ chan = Tcl_OpenFileChannel(interp,
+ Tcl_GetString(options.name), "r", 0);
if (chan == NULL) {
return TCL_ERROR;
}
!= TCL_OK) {
return TCL_ERROR;
}
- if (MatchFileFormat(interp, chan, options.name, options.format,
- &imageFormat, &imageWidth, &imageHeight) != TCL_OK) {
+ if (Tcl_SetChannelOption(interp, chan, "-encoding", "binary")
+ != TCL_OK) {
+ return TCL_ERROR;
+ }
+
+ if (MatchFileFormat(interp, chan,
+ Tcl_GetString(options.name), options.format,
+ &imageFormat, &imageWidth, &imageHeight, &oldformat) != TCL_OK) {
Tcl_Close(NULL, chan);
return TCL_ERROR;
}
* into the image.
*/
- result = (*imageFormat->fileReadProc)(interp, chan, options.name,
- options.format, (Tk_PhotoHandle) masterPtr, options.toX,
+ format = options.format;
+ if (oldformat && format) {
+ format = (Tcl_Obj *) Tcl_GetString(format);
+ }
+ result = (*imageFormat->fileReadProc)(interp, chan,
+ Tcl_GetString(options.name),
+ format, (Tk_PhotoHandle) masterPtr, options.toX,
options.toY, width, height, options.fromX, options.fromY);
if (chan != NULL) {
Tcl_Close(NULL, chan);
}
return result;
- } else if ((c == 'r') && (length >= 3)
- && (strncmp(argv[1], "redither", length) == 0)) {
-
- if (argc == 2) {
+ break;
+ }
+ case PHOTO_REDITHER: {
+ if (objc == 2) {
/*
* Call Dither if any part of the image is not correctly
* dithered at present.
x = masterPtr->ditherX;
y = masterPtr->ditherY;
if (masterPtr->ditherX != 0) {
- Dither(masterPtr, x, y, masterPtr->width - x, 1);
+ Tk_DitherPhoto((Tk_PhotoHandle) masterPtr, x, y, masterPtr->width - x, 1);
}
if (masterPtr->ditherY < masterPtr->height) {
x = 0;
- Dither(masterPtr, 0, masterPtr->ditherY, masterPtr->width,
+ Tk_DitherPhoto((Tk_PhotoHandle)masterPtr, 0, masterPtr->ditherY, masterPtr->width,
masterPtr->height - masterPtr->ditherY);
}
}
} else {
- Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
- " redither\"", (char *) NULL);
+ Tcl_WrongNumArgs(interp, 2, objv, (char *) NULL);
return TCL_ERROR;
}
- } else if ((c == 'w') && (strncmp(argv[1], "write", length) == 0)) {
+ break;
+ }
+ case PHOTO_WRITE: {
char *data;
+ Tcl_Obj *format;
+
/*
* Prevent file system access in safe interpreters.
*/
options.format = NULL;
if (ParseSubcommandOptions(&options, interp,
OPT_FORMAT | OPT_FROM | OPT_GRAYSCALE | OPT_BACKGROUND,
- &index, argc, argv) != TCL_OK) {
+ &index, objc, objv) != TCL_OK) {
return TCL_ERROR;
}
- if ((options.name == NULL) || (index < argc)) {
- Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
- " write fileName ?-format format-name?",
- "?-from x1 y1 x2 y2?\"", (char *) NULL);
+ if ((options.name == NULL) || (index < objc)) {
+ Tcl_WrongNumArgs(interp, 2, objv, "fileName ?options?");
return TCL_ERROR;
}
if ((options.fromX > masterPtr->width)
*/
matched = 0;
- for (imageFormat = formatList; imageFormat != NULL;
+ for (imageFormat = tsdPtr->formatList; imageFormat != NULL;
+ imageFormat = imageFormat->nextPtr) {
+ if ((options.format == NULL)
+ || (strncasecmp(Tcl_GetString(options.format),
+ imageFormat->name, strlen(imageFormat->name)) == 0)) {
+ matched = 1;
+ if (imageFormat->fileWriteProc != NULL) {
+ break;
+ }
+ }
+ }
+ if (imageFormat == NULL) {
+ oldformat = 1;
+ for (imageFormat = tsdPtr->oldFormatList; imageFormat != NULL;
imageFormat = imageFormat->nextPtr) {
if ((options.format == NULL)
- || (strncasecmp(options.format, imageFormat->name,
- strlen(imageFormat->name)) == 0)) {
+ || (strncasecmp(Tcl_GetString(options.format),
+ imageFormat->name, strlen(imageFormat->name)) == 0)) {
matched = 1;
if (imageFormat->fileWriteProc != NULL) {
break;
}
}
+ }
}
if (imageFormat == NULL) {
if (options.format == NULL) {
"has file writing capability", (char *) NULL);
} else if (!matched) {
Tcl_AppendResult(interp, "image file format \"",
- options.format, "\" is unknown", (char *) NULL);
+ Tcl_GetString(options.format),
+ "\" is unknown", (char *) NULL);
} else {
Tcl_AppendResult(interp, "image file format \"",
- options.format, "\" has no file writing capability",
+ Tcl_GetString(options.format),
+ "\" has no file writing capability",
(char *) NULL);
}
return TCL_ERROR;
*/
data = ImgGetPhoto(masterPtr, &block, &options);
- result = (*imageFormat->fileWriteProc)(interp, options.name,
- options.format, &block);
+ format = options.format;
+ if (oldformat && format) {
+ format = (Tcl_Obj *) Tcl_GetString(options.format);
+ }
+ result = (*imageFormat->fileWriteProc)(interp,
+ Tcl_GetString(options.name),
+ format, &block);
if (options.background) {
Tk_FreeColor(options.background);
}
ckfree(data);
}
return result;
- } else {
- Tcl_AppendResult(interp, "bad option \"", argv[1],
- "\": must be blank, cget, configure, copy, get, put,",
- " read, redither, or write", (char *) NULL);
- return TCL_ERROR;
+ break;
+ }
}
return TCL_OK;
*/
static int
-ParseSubcommandOptions(optPtr, interp, allowedOptions, optIndexPtr, argc, argv)
+ParseSubcommandOptions(optPtr, interp, allowedOptions, optIndexPtr, objc, objv)
struct SubcommandOptions *optPtr;
/* Information about the options specified
* and the values given is returned here. */
int allowedOptions; /* Indicates which options are valid for
* the current command. */
int *optIndexPtr; /* Points to a variable containing the
- * current index in argv; this variable is
+ * current index in objv; this variable is
* updated by this procedure. */
- int argc; /* Number of arguments in argv[]. */
- char **argv; /* Arguments to be parsed. */
+ int objc; /* Number of arguments in objv[]. */
+ Tcl_Obj *CONST objv[]; /* Arguments to be parsed. */
{
int index, c, bit, currentBit;
- size_t length;
+ int length;
char *option, **listPtr;
int values[4];
int numValues, maxValues, argIndex;
- for (index = *optIndexPtr; index < argc; *optIndexPtr = ++index) {
+ for (index = *optIndexPtr; index < objc; *optIndexPtr = ++index) {
/*
* We can have one value specified without an option;
* it goes into optPtr->name.
*/
- option = argv[index];
+ option = Tcl_GetStringFromObj(objv[index], &length);
if (option[0] != '-') {
if (optPtr->name == NULL) {
- optPtr->name = option;
+ optPtr->name = objv[index];
continue;
}
break;
* Work out which option this is.
*/
- length = strlen(option);
c = option[0];
bit = 0;
currentBit = 1;
for (listPtr = optionNames; *listPtr != NULL; ++listPtr) {
if ((c == *listPtr[0])
- && (strncmp(option, *listPtr, length) == 0)) {
+ && (strncmp(option, *listPtr, (size_t) length) == 0)) {
if (bit != 0) {
bit = 0; /* An ambiguous option. */
break;
*/
if ((allowedOptions & bit) == 0) {
- Tcl_AppendResult(interp, "unrecognized option \"", argv[index],
+ Tcl_AppendResult(interp, "unrecognized option \"",
+ Tcl_GetString(objv[index]),
"\": must be ", (char *)NULL);
bit = 1;
for (listPtr = optionNames; *listPtr != NULL; ++listPtr) {
* The -background option takes a single XColor value.
*/
- if (index + 1 < argc) {
+ if (index + 1 < objc) {
*optIndexPtr = ++index;
optPtr->background = Tk_GetColor(interp, Tk_MainWindow(interp),
- Tk_GetUid(argv[index]));
+ Tk_GetUid(Tcl_GetString(objv[index])));
if (!optPtr->background) {
return TCL_ERROR;
}
* The -format option takes a single string value.
*/
- if (index + 1 < argc) {
+ if (index + 1 < objc) {
*optIndexPtr = ++index;
- optPtr->format = argv[index];
+ optPtr->format = objv[index];
} else {
Tcl_AppendResult(interp, "the \"-format\" 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;
argIndex = index + 1;
for (numValues = 0; numValues < maxValues; ++numValues) {
- if ((argIndex < argc) && (isdigit(UCHAR(argv[argIndex][0]))
- || ((argv[argIndex][0] == '-')
- && (isdigit(UCHAR(argv[argIndex][1])))))) {
- if (Tcl_GetInt(interp, argv[argIndex], &values[numValues])
+ if (argIndex >= objc) {
+ break;
+ }
+ val = Tcl_GetString(objv[argIndex]);
+ if ((argIndex < objc) && (isdigit(UCHAR(val[0]))
+ || ((val[0] == '-') && isdigit(UCHAR(val[1]))))) {
+ if (Tcl_GetInt(interp, val, &values[numValues])
!= TCL_OK) {
return TCL_ERROR;
}
}
if (numValues == 0) {
- Tcl_AppendResult(interp, "the \"", argv[index], "\" option ",
+ Tcl_AppendResult(interp, "the \"", option, "\" option ",
"requires one ", maxValues == 2? "or two": "to four",
" integer values", (char *) NULL);
return TCL_ERROR;
*
* Results:
* A standard Tcl return value. If TCL_ERROR is returned then
- * an error message is left in masterPtr->interp->result.
+ * an error message is left in the masterPtr->interp's result.
*
* Side effects:
* Existing instances of the image will be redisplayed to match
*/
static int
-ImgPhotoConfigureMaster(interp, masterPtr, argc, objv, flags)
+ImgPhotoConfigureMaster(interp, masterPtr, objc, objv, flags)
Tcl_Interp *interp; /* Interpreter to use for reporting errors. */
PhotoMaster *masterPtr; /* Pointer to data structure describing
* overall photo image to (re)configure. */
- int argc; /* Number of entries in argv. */
+ int objc; /* Number of entries in objv. */
Tcl_Obj *CONST objv[]; /* Pairs of configuration options for image. */
int flags; /* Flags to pass to Tk_ConfigureWidget,
* such as TK_CONFIG_ARGV_ONLY. */
{
PhotoInstance *instancePtr;
- char *oldFileString, *oldPaletteString, *oldFormat;
- Tcl_Obj *oldDataObj, *dataObj = NULL;
+ char *oldFileString, *oldPaletteString;
+ Tcl_Obj *oldData, *data = NULL, *oldFormat, *format = NULL;
int length, i, j;
double oldGamma;
int result;
Tcl_Channel chan;
Tk_PhotoImageFormat *imageFormat;
int imageWidth, imageHeight;
- static char **argv = NULL;
-
- if (argv) ckfree((char *) argv);
- argv = (char **) ckalloc((argc + 1) * sizeof(char *));
- for (i = 0, j = 0; i < argc; i++,j++) {
- argv[j] = Tcl_GetStringFromObj(objv[i], &length);
- if (argv[j][0] == '-' && argv[j][1] == 'd' &&
- strncmp(argv[j],"-data", length) == 0) {
- if (i < argc) {
- dataObj = objv[++i];
- j--;
+ char **args;
+ int oldformat;
+ Tcl_Obj *tempdata, *tempformat;
+
+ args = (char **) ckalloc((objc + 1) * sizeof(char *));
+ for (i = 0, j = 0; i < objc; i++,j++) {
+ args[j] = Tcl_GetStringFromObj(objv[i], &length);
+ if ((length > 1) && (args[j][0] == '-')) {
+ if ((args[j][1] == 'd') &&
+ !strncmp(args[j],"-data", (size_t) length)) {
+ if (i < objc) {
+ data = objv[++i];
+ j--;
+ }
+ } else if ((args[j][1] == 'f') &&
+ !strncmp(args[j],"-format", (size_t) length)) {
+ if (i < objc) {
+ format = objv[++i];
+ j--;
+ }
}
}
}
+
/*
* Save the current values for fileString and dataString, so we
* can tell if the user specifies them anew.
*/
oldFileString = masterPtr->fileString;
- oldDataObj = (oldFileString == NULL) ? masterPtr->dataObj: NULL;
+ oldData = (oldFileString == NULL) ? masterPtr->dataString: NULL;
oldFormat = masterPtr->format;
oldPaletteString = masterPtr->palette;
oldGamma = masterPtr->gamma;
*/
if (Tk_ConfigureWidget(interp, Tk_MainWindow(interp), configSpecs,
- j, argv, (char *) masterPtr, flags) != TCL_OK) {
+ j, args, (char *) masterPtr, flags) != TCL_OK) {
+ ckfree((char *) args);
return TCL_ERROR;
}
+ ckfree((char *) args);
/*
* Regard the empty string for -file, -data or -format as the null
ckfree(masterPtr->fileString);
masterPtr->fileString = NULL;
}
- if (dataObj) {
- if (dataObj->length) {
- Tcl_IncrRefCount(dataObj);
+ if (data) {
+ if (data->length
+ || (data->typePtr == Tcl_GetObjType("bytearray")
+ && data->internalRep.otherValuePtr != NULL)) {
+ Tcl_IncrRefCount(data);
} else {
- dataObj = NULL;
+ data = NULL;
}
- if (masterPtr->dataObj) {
- Tcl_DecrRefCount(masterPtr->dataObj);
+ if (masterPtr->dataString) {
+ Tcl_DecrRefCount(masterPtr->dataString);
}
- masterPtr->dataObj = dataObj;
+ masterPtr->dataString = data;
}
- if ((masterPtr->format != NULL) && (masterPtr->format[0] == 0)) {
- ckfree(masterPtr->format);
- masterPtr->format = NULL;
+ if (format) {
+ if (format->length) {
+ Tcl_IncrRefCount(format);
+ } else {
+ format = NULL;
+ }
+ if (masterPtr->format) {
+ Tcl_DecrRefCount(masterPtr->format);
+ }
+ masterPtr->format = format;
}
-
/*
* Set the image to the user-requested size, if any,
* and make sure storage is correctly allocated for this image.
!= TCL_OK) {
return TCL_ERROR;
}
+ if (Tcl_SetChannelOption(interp, chan, "-encoding", "binary")
+ != TCL_OK) {
+ return TCL_ERROR;
+ }
if (MatchFileFormat(interp, chan, masterPtr->fileString,
masterPtr->format, &imageFormat, &imageWidth,
- &imageHeight) != TCL_OK) {
+ &imageHeight, &oldformat) != TCL_OK) {
Tcl_Close(NULL, chan);
return TCL_ERROR;
}
ImgPhotoSetSize(masterPtr, imageWidth, imageHeight);
+ tempformat = masterPtr->format;
+ if (oldformat && tempformat) {
+ tempformat = (Tcl_Obj *) Tcl_GetString(tempformat);
+ }
result = (*imageFormat->fileReadProc)(interp, chan,
- masterPtr->fileString, masterPtr->format,
+ masterPtr->fileString, tempformat,
(Tk_PhotoHandle) masterPtr, 0, 0,
imageWidth, imageHeight, 0, 0);
Tcl_Close(NULL, chan);
return TCL_ERROR;
}
+ Tcl_ResetResult(interp);
masterPtr->flags |= IMAGE_CHANGED;
}
- if ((masterPtr->fileString == NULL) && (masterPtr->dataObj != NULL)
- && ((masterPtr->dataObj != oldDataObj)
+ if ((masterPtr->fileString == NULL) && (masterPtr->dataString != NULL)
+ && ((masterPtr->dataString != oldData)
|| (masterPtr->format != oldFormat))) {
- if (MatchStringFormat(interp, masterPtr->dataObj,
+ if (MatchStringFormat(interp, masterPtr->dataString,
masterPtr->format, &imageFormat, &imageWidth,
- &imageHeight) != TCL_OK) {
+ &imageHeight, &oldformat) != TCL_OK) {
return TCL_ERROR;
}
ImgPhotoSetSize(masterPtr, imageWidth, imageHeight);
- if ((*imageFormat->stringReadProc)(interp, masterPtr->dataObj,
- masterPtr->format, (Tk_PhotoHandle) masterPtr,
+ tempformat = masterPtr->format;
+ tempdata = masterPtr->dataString;
+ if (oldformat) {
+ if (tempformat) {
+ tempformat = (Tcl_Obj *) Tcl_GetString(tempformat);
+ }
+ tempdata = (Tcl_Obj *) Tcl_GetString(tempdata);
+ }
+ if ((*imageFormat->stringReadProc)(interp, tempdata,
+ tempformat, (Tk_PhotoHandle) masterPtr,
0, 0, imageWidth, imageHeight, 0, 0) != TCL_OK) {
return TCL_ERROR;
}
+ Tcl_ResetResult(interp);
masterPtr->flags |= IMAGE_CHANGED;
}
int mono, nRed, nGreen, nBlue;
XVisualInfo visualInfo, *visInfoPtr;
XRectangle validBox;
- char buf[16];
+ char buf[TCL_INTEGER_SPACE * 3];
int numVisuals;
XColor *white, *black;
XGCValues gcValues;
gcValues.background = (black != NULL)? black->pixel:
BlackPixelOfScreen(Tk_Screen(tkwin));
gcValues.graphics_exposures = False;
- instancePtr->gc = Tk_GetGCColor(tkwin,
- GCForeground|GCBackground|GCGraphicsExposures, &gcValues,
- white, black);
+ instancePtr->gc = Tk_GetGC(tkwin,
+ GCForeground|GCBackground|GCGraphicsExposures, &gcValues);
/*
* Set configuration options and finish the initialization of the instance.
*/
if (masterPtr->validRegion != NULL) {
TkDestroyRegion(masterPtr->validRegion);
}
- if (masterPtr->dataObj != NULL) {
- Tcl_DecrRefCount(masterPtr->dataObj);
+ if (masterPtr->dataString != NULL) {
+ Tcl_DecrRefCount(masterPtr->dataString);
+ }
+ if (masterPtr->format != NULL) {
+ Tcl_DecrRefCount(masterPtr->format);
}
Tk_FreeOptions(configSpecs, (char *) masterPtr, (Display *) NULL, 0);
ckfree((char *) masterPtr);
*/
static int
-MatchFileFormat(interp, chan, fileName, formatString, imageFormatPtr,
- widthPtr, heightPtr)
+MatchFileFormat(interp, chan, fileName, formatObj, imageFormatPtr,
+ widthPtr, heightPtr, oldformat)
Tcl_Interp *interp; /* Interpreter to use for reporting errors. */
Tcl_Channel chan; /* The image file, open for reading. */
char *fileName; /* The name of the image file. */
- char *formatString; /* User-specified format string, or NULL. */
+ Tcl_Obj *formatObj; /* User-specified format string, or NULL. */
Tk_PhotoImageFormat **imageFormatPtr;
/* A pointer to the photo image format
* record is returned here. */
int *widthPtr, *heightPtr; /* The dimensions of the image are
* returned here. */
+ int *oldformat;
{
int matched;
+ int useoldformat = 0;
Tk_PhotoImageFormat *formatPtr;
+ ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
+ Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
+ char *formatString = NULL;
+
+ if (formatObj) {
+ formatString = Tcl_GetString(formatObj);
+ }
/*
* Scan through the table of file format handlers to find
*/
matched = 0;
- for (formatPtr = formatList; formatPtr != NULL;
+ for (formatPtr = tsdPtr->formatList; formatPtr != NULL;
formatPtr = formatPtr->nextPtr) {
- if (formatString != NULL) {
- if (strncasecmp(formatString, formatPtr->name,
- strlen(formatPtr->name)) != 0) {
+ if (formatObj != NULL) {
+ if (strncasecmp(formatString,
+ formatPtr->name, strlen(formatPtr->name)) != 0) {
continue;
}
matched = 1;
if (formatPtr->fileMatchProc != NULL) {
(void) Tcl_Seek(chan, 0L, SEEK_SET);
- if ((*formatPtr->fileMatchProc)(chan, fileName, formatString,
- widthPtr, heightPtr)) {
+ if ((*formatPtr->fileMatchProc)(chan, fileName, formatObj,
+ widthPtr, heightPtr, interp)) {
if (*widthPtr < 1) {
*widthPtr = 1;
}
}
}
}
+ if (formatPtr == NULL) {
+ useoldformat = 1;
+ for (formatPtr = tsdPtr->oldFormatList; formatPtr != NULL;
+ formatPtr = formatPtr->nextPtr) {
+ if (formatString != NULL) {
+ if (strncasecmp(formatString,
+ formatPtr->name, strlen(formatPtr->name)) != 0) {
+ continue;
+ }
+ matched = 1;
+ if (formatPtr->fileMatchProc == NULL) {
+ Tcl_AppendResult(interp, "-file option isn't supported for ",
+ formatString, " images", (char *) NULL);
+ return TCL_ERROR;
+ }
+ }
+ if (formatPtr->fileMatchProc != NULL) {
+ (void) Tcl_Seek(chan, 0L, SEEK_SET);
+ if ((*formatPtr->fileMatchProc)(chan, fileName, (Tcl_Obj *) formatString,
+ widthPtr, heightPtr, interp)) {
+ if (*widthPtr < 1) {
+ *widthPtr = 1;
+ }
+ if (*heightPtr < 1) {
+ *heightPtr = 1;
+ }
+ break;
+ }
+ }
+ }
+ }
if (formatPtr == NULL) {
- if ((formatString != NULL) && !matched) {
- Tcl_AppendResult(interp, "image file format \"", formatString,
+ if ((formatObj != NULL) && !matched) {
+ Tcl_AppendResult(interp, "image file format \"",
+ formatString,
"\" is not supported", (char *) NULL);
} else {
Tcl_AppendResult(interp,
}
*imageFormatPtr = formatPtr;
+ *oldformat = useoldformat;
(void) Tcl_Seek(chan, 0L, SEEK_SET);
return TCL_OK;
}
*/
static int
-MatchStringFormat(interp, dataObj, formatString, imageFormatPtr,
- widthPtr, heightPtr)
+MatchStringFormat(interp, data, formatObj, imageFormatPtr,
+ widthPtr, heightPtr, oldformat)
Tcl_Interp *interp; /* Interpreter to use for reporting errors. */
- Tcl_Obj *dataObj; /* Object containing the image data. */
- char *formatString; /* User-specified format string, or NULL. */
+ Tcl_Obj *data; /* Object containing the image data. */
+ Tcl_Obj *formatObj; /* User-specified format string, or NULL. */
Tk_PhotoImageFormat **imageFormatPtr;
/* A pointer to the photo image format
* record is returned here. */
int *widthPtr, *heightPtr; /* The dimensions of the image are
* returned here. */
+ int *oldformat; /* returns 1 if the old image API is used */
{
int matched;
+ int useoldformat = 0;
Tk_PhotoImageFormat *formatPtr;
+ ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
+ Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
+ char *formatString = NULL;
+
+ if (formatObj) {
+ formatString = Tcl_GetString(formatObj);
+ }
/*
* Scan through the table of file format handlers to find
*/
matched = 0;
- for (formatPtr = formatList; formatPtr != NULL;
+ for (formatPtr = tsdPtr->formatList; formatPtr != NULL;
formatPtr = formatPtr->nextPtr) {
- if (formatString != NULL) {
- if (strncasecmp(formatString, formatPtr->name,
- strlen(formatPtr->name)) != 0) {
+ if (formatObj != NULL) {
+ if (strncasecmp(formatString,
+ formatPtr->name, strlen(formatPtr->name)) != 0) {
continue;
}
matched = 1;
}
if ((formatPtr->stringMatchProc != NULL)
&& (formatPtr->stringReadProc != NULL)
- && (*formatPtr->stringMatchProc)(dataObj, formatString,
- widthPtr, heightPtr)) {
+ && (*formatPtr->stringMatchProc)(data, formatObj,
+ widthPtr, heightPtr, interp)) {
break;
}
}
if (formatPtr == NULL) {
- if ((formatString != NULL) && !matched) {
- Tcl_AppendResult(interp, "image format \"", formatString,
+ 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;
+ }
+ }
+ 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,
"\" is not supported", (char *) NULL);
} else {
Tcl_AppendResult(interp, "couldn't recognize image data",
}
*imageFormatPtr = formatPtr;
+ *oldformat = useoldformat;
return TCL_OK;
}
\f
greenOffset = blockPtr->offset[1] - blockPtr->offset[0];
blueOffset = blockPtr->offset[2] - blockPtr->offset[0];
- alphaOffset = 0;
- while ((alphaOffset != blockPtr->offset[0]) &&
- (alphaOffset != blockPtr->offset[1]) &&
- (alphaOffset != blockPtr->offset[2])) {
- alphaOffset++;
- }
- if (alphaOffset >= blockPtr->pixelSize) {
+ alphaOffset = blockPtr->offset[3];
+ if ((alphaOffset >= blockPtr->pixelSize) || (alphaOffset < 0)) {
alphaOffset = 0;
} else {
alphaOffset -= blockPtr->offset[0];
destLinePtr = masterPtr->pix24 + (y * masterPtr->width + x) * 4;
pitch = masterPtr->width * 4;
- if ((blockPtr->pixelSize == 4) && (greenOffset == 1) && (blueOffset == 2)
+ /*
+ * This test is probably too restrictive. We should also be able to
+ * do a memcpy if pixelSize == 3 and alphaOffset == 0. Maybe other cases
+ * too.
+ */
+ if ((blockPtr->pixelSize == 4)
+ && (greenOffset == 1) && (blueOffset == 2) && (alphaOffset == 3)
&& (width <= blockPtr->width) && (height <= blockPtr->height)
&& ((height == 1) || ((x == 0) && (width == masterPtr->width)
&& (blockPtr->pitch == pitch)))) {
wLeft -= wCopy;
srcPtr = srcLinePtr;
for (; wCopy > 0; --wCopy) {
+ if (!destPtr[3]) {
+ destPtr[0] = destPtr[1] = destPtr[2] = 0xd9;
+ }
+ if (!alphaOffset || (srcPtr[alphaOffset] == 255)) {
*destPtr++ = srcPtr[0];
*destPtr++ = srcPtr[greenOffset];
*destPtr++ = srcPtr[blueOffset];
- *destPtr++ = alphaOffset ? srcPtr[alphaOffset] : 255;
- srcPtr += blockPtr->pixelSize;
+ *destPtr++ = 255;
+ } else {
+ if (srcPtr[alphaOffset]) {
+ destPtr[0] += (srcPtr[0] - destPtr[0]) * srcPtr[alphaOffset] / 255;
+ destPtr[1] += (srcPtr[greenOffset] - destPtr[1]) * srcPtr[alphaOffset] / 255;
+ destPtr[2] += (srcPtr[blueOffset] - destPtr[2]) * srcPtr[alphaOffset] / 255;
+ destPtr[3] += (255 - destPtr[3]) * srcPtr[alphaOffset] / 255;
+ }
+ destPtr+=4;
+ }
+ srcPtr += blockPtr->pixelSize;
}
}
srcLinePtr += blockPtr->pitch;
* Add this new block to the region which specifies which data is valid.
*/
+ if (alphaOffset) {
+ int x1, y1, end;
+
+ /*
+ * This block is grossly inefficient. For each row in the image, it
+ * finds each continguous string of transparent pixels, then marks those
+ * areas as invalid in the validRegion mask. This makes drawing very
+ * efficient, because of the way we use X: we just say, here's your
+ * mask, and here's your data. We need not worry about the current
+ * background color, etc. But this costs us a lot on the image setup.
+ * Still, image setup only happens once, whereas the drawing happens
+ * many times, so this might be the best way to go.
+ *
+ * An alternative might be to not set up this mask, and instead, at
+ * drawing time, for each transparent pixel, set its color to the
+ * color of the background behind that pixel. This is what I suspect
+ * most of programs do. However, they don't have to deal with the canvas,
+ * which could have many different background colors. Determining the
+ * correct bg color for a given pixel might be expensive.
+ */
+
+ destLinePtr = masterPtr->pix24 + (y * masterPtr->width + x) * 4 + 3;
+ for (y1 = 0; y1 < height; y1++) {
+ x1 = 0;
+ destPtr = destLinePtr;
+ while (x1 < width) {
+ /* search for first non-transparent pixel */
+ while ((x1 < width) && !*destPtr) {
+ x1++; destPtr += 4;
+ }
+ end = x1;
+ /* search for first transparent pixel */
+ while ((end < width) && *destPtr) {
+ end++; destPtr += 4;
+ }
+ if (end > x1) {
+ rect.x = x + x1;
+ rect.y = y + y1;
+ rect.width = end - x1;
+ rect.height = 1;
+ TkUnionRectWithRegion(&rect, masterPtr->validRegion,
+ masterPtr->validRegion);
+ }
+ x1 = end;
+ }
+ destLinePtr += masterPtr->width * 4;
+ }
+ } else {
rect.x = x;
rect.y = y;
rect.width = width;
rect.height = height;
TkUnionRectWithRegion(&rect, masterPtr->validRegion,
masterPtr->validRegion);
+ }
/*
* Update each instance.
*/
- Dither(masterPtr, x, y, width, height);
+ Tk_DitherPhoto((Tk_PhotoHandle)masterPtr, x, y, width, height);
/*
* Tell the core image code that this image has changed.
greenOffset = blockPtr->offset[1] - blockPtr->offset[0];
blueOffset = blockPtr->offset[2] - blockPtr->offset[0];
- alphaOffset = 0;
- while ((alphaOffset != blockPtr->offset[0]) &&
- (alphaOffset != blockPtr->offset[1]) &&
- (alphaOffset != blockPtr->offset[2])) {
- alphaOffset++;
- }
- if (alphaOffset >= blockPtr->pixelSize) {
+ alphaOffset = blockPtr->offset[3];
+ if ((alphaOffset >= blockPtr->pixelSize) || (alphaOffset < 0)) {
alphaOffset = 0;
} else {
alphaOffset -= blockPtr->offset[0];
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++ = alphaOffset ? srcPtr[alphaOffset] : 255;
+ *destPtr++ = 255;
+ } else {
+ if (srcPtr[alphaOffset]) {
+ destPtr[0] += (srcPtr[0] - destPtr[0]) * srcPtr[alphaOffset] / 255;
+ destPtr[1] += (srcPtr[greenOffset] - destPtr[1]) * srcPtr[alphaOffset] / 255;
+ destPtr[2] += (srcPtr[blueOffset] - destPtr[2]) * srcPtr[alphaOffset] / 255;
+ destPtr[3] += (255 - destPtr[3]) * srcPtr[alphaOffset] / 255;
+ }
+ destPtr+=4;
+ }
}
srcPtr += blockXSkip;
}
* Add this new block to the region that specifies which data is valid.
*/
+ if (alphaOffset) {
+ int x1, y1, end;
+
+ destLinePtr = masterPtr->pix24 + (y * masterPtr->width + x) * 4 + 3;
+ for (y1 = 0; y1 < height; y1++) {
+ x1 = 0;
+ destPtr = destLinePtr;
+ while (x1 < width) {
+ /* search for first non-transparent pixel */
+ while ((x1 < width) && !*destPtr) {
+ x1++; destPtr += 4;
+ }
+ end = x1;
+ /* search for first transparent pixel */
+ while ((end < width) && *destPtr) {
+ end++; destPtr += 4;
+ }
+ if (end > x1) {
+ rect.x = x + x1;
+ rect.y = y + y1;
+ rect.width = end - x1;
+ rect.height = 1;
+ TkUnionRectWithRegion(&rect, masterPtr->validRegion,
+ masterPtr->validRegion);
+ }
+ x1 = end;
+ }
+ destLinePtr += masterPtr->width * 4;
+ }
+ } else {
rect.x = x;
rect.y = y;
rect.width = width;
rect.height = height;
TkUnionRectWithRegion(&rect, masterPtr->validRegion,
masterPtr->validRegion);
+ }
/*
* Update each instance.
*/
- Dither(masterPtr, x, y, width, height);
+ Tk_DitherPhoto((Tk_PhotoHandle)masterPtr, x, y, width, height);
/*
* Tell the core image code that this image has changed.
/*
*----------------------------------------------------------------------
*
- * Dither --
+ * Tk_DitherPhoto --
*
* This procedure is called to update an area of each instance's
* pixmap by dithering the corresponding area of the image master.
*----------------------------------------------------------------------
*/
-static void
-Dither(masterPtr, x, y, width, height)
- PhotoMaster *masterPtr; /* Image master whose instances are
+void
+Tk_DitherPhoto(photo, x, y, width, height)
+ Tk_PhotoHandle photo; /* Image master whose instances are
* to be updated. */
int x, y; /* Coordinates of the top-left pixel
* in the area to be dithered. */
int width, height; /* Dimensions of the area to be dithered. */
{
+ PhotoMaster *masterPtr = (PhotoMaster *) photo;
PhotoInstance *instancePtr;
if ((width <= 0) || (height <= 0)) {
if ((greenOffset || blueOffset) && !(optPtr->options & OPT_GRAYSCALE)) {
newPixelSize += 2;
}
- data = ckalloc(newPixelSize * blockPtr->width * blockPtr->height);
+ data = ckalloc((unsigned int) (newPixelSize *
+ blockPtr->width * blockPtr->height));
srcPtr = blockPtr->pixelPtr + blockPtr->offset[0];
destPtr = (unsigned char *) data;
if (!greenOffset && !blueOffset) {
*/
static int
-ImgStringWrite (interp, dataPtr, formatString, blockPtr)
+ImgStringWrite(interp, formatString, blockPtr)
Tcl_Interp *interp;
- Tcl_DString *dataPtr;
- char *formatString;
+ Tcl_Obj *formatString;
Tk_PhotoImageBlock *blockPtr;
{
int row,col;
char *line, *linePtr;
unsigned char *pixelPtr;
int greenOffset, blueOffset;
+ Tcl_DString data;
greenOffset = blockPtr->offset[1] - blockPtr->offset[0];
blueOffset = blockPtr->offset[2] - blockPtr->offset[0];
+ Tcl_DStringInit(&data);
if ((blockPtr->width > 0) && (blockPtr->height > 0)) {
- line = (char *) ckalloc(8 * blockPtr->width + 2);
+ line = (char *) ckalloc((unsigned int) ((8 * blockPtr->width) + 2));
for (row=0; row<blockPtr->height; row++) {
pixelPtr = blockPtr->pixelPtr + blockPtr->offset[0] +
row * blockPtr->pitch;
pixelPtr += blockPtr->pixelSize;
linePtr += 8;
}
- Tcl_DStringAppendElement(dataPtr, line+1);
+ Tcl_DStringAppendElement(&data, line+1);
}
ckfree (line);
}
+ Tcl_DStringResult(interp, &data);
return TCL_OK;
}
\f
blockPtr->offset[0] = 0;
blockPtr->offset[1] = 1;
blockPtr->offset[2] = 2;
+ blockPtr->offset[3] = 3;
return 1;
}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * PhotoOptionFind --
+ *
+ * Finds a specific Photo option.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * After commands are removed.
+ *
+ *----------------------------------------------------------------------
+ */
+
+typedef struct OptionAssocData {
+ struct OptionAssocData *nextPtr; /* pointer to next OptionAssocData */
+ Tcl_ObjCmdProc *command; /* command associated with this
+ * option */
+ char name[1]; /* name of option (remaining chars) */
+} OptionAssocData;
+
+static Tcl_ObjCmdProc *
+PhotoOptionFind(interp, obj)
+ Tcl_Interp *interp; /* Interpreter that is being deleted. */
+ Tcl_Obj *obj; /* Name of option to be found. */
+{
+ size_t length;
+ char *name = Tcl_GetStringFromObj(obj, (int *) &length);
+ OptionAssocData *list;
+ char *prevname = NULL;
+ Tcl_ObjCmdProc *proc = (Tcl_ObjCmdProc *) NULL;
+ list = (OptionAssocData *) Tcl_GetAssocData(interp, "photoOption",
+ (Tcl_InterpDeleteProc **) NULL);
+ while (list != (OptionAssocData *) NULL) {
+ if (strncmp(name, list->name, length) == 0) {
+ if (proc != (Tcl_ObjCmdProc *) NULL) {
+ Tcl_ResetResult(interp);
+ Tcl_AppendResult(interp, "ambiguous option \"", name,
+ "\": must be ", prevname, (char *) NULL);
+ while (list->nextPtr != (OptionAssocData *) NULL) {
+ Tcl_AppendResult(interp, prevname, ", ",(char *) NULL);
+ list = list->nextPtr;
+ prevname = list->name;
+ }
+ Tcl_AppendResult(interp, ", or", prevname, (char *) NULL);
+ return (Tcl_ObjCmdProc *) NULL;
+ }
+ proc = list->command;
+ prevname = list->name;
+ }
+ list = list->nextPtr;
+ }
+ if (proc != (Tcl_ObjCmdProc *) NULL) {
+ Tcl_ResetResult(interp);
+ }
+ return proc;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * PhotoOptionCleanupProc --
+ *
+ * This procedure is invoked whenever an interpreter is deleted
+ * to cleanup the AssocData for "photoVisitor".
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Photo Visitor options are removed.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+PhotoOptionCleanupProc(clientData, interp)
+ ClientData clientData; /* Points to "photoVisitor" AssocData
+ * for the interpreter. */
+ Tcl_Interp *interp; /* Interpreter that is being deleted. */
+{
+ OptionAssocData *list = (OptionAssocData *) clientData;
+ OptionAssocData *ptr;
+
+ while (list != NULL) {
+ list = (ptr = list)->nextPtr;
+ ckfree((char *) ptr);
+ }
+}
+
+/*
+ *--------------------------------------------------------------
+ *
+ * Tk_CreatePhotoOption --
+ *
+ * This procedure may be invoked to add a new kind of photo
+ * option to the core photo command supported by Tk.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * From now on, the new option will be useable by the
+ * photo command.
+ *
+ *--------------------------------------------------------------
+ */
+
+void
+Tk_CreatePhotoOption(interp, name, proc)
+ Tcl_Interp *interp; /* interpreter */
+ CONST char *name; /* option name */
+ Tcl_ObjCmdProc *proc; /* proc to execute command */
+{
+ OptionAssocData *typePtr2, *prevPtr, *ptr;
+ OptionAssocData *list;
+
+ list = (OptionAssocData *) Tcl_GetAssocData(interp, "photoOption",
+ (Tcl_InterpDeleteProc **) NULL);
+
+ /*
+ * If there's already a photo option with the given name, remove it.
+ */
+
+ for (typePtr2 = list, prevPtr = NULL; typePtr2 != NULL;
+ prevPtr = typePtr2, typePtr2 = typePtr2->nextPtr) {
+ if (strcmp(typePtr2->name, name) == 0) {
+ if (prevPtr == NULL) {
+ list = typePtr2->nextPtr;
+ } else {
+ prevPtr->nextPtr = typePtr2->nextPtr;
+ }
+ ckfree((char *) typePtr2);
+ break;
+ }
+ }
+ ptr = (OptionAssocData *) ckalloc(sizeof(OptionAssocData) + strlen(name));
+ strcpy(&(ptr->name[0]), name);
+ ptr->command = proc;
+ ptr->nextPtr = list;
+ Tcl_SetAssocData(interp, "photoOption", PhotoOptionCleanupProc,
+ (ClientData) ptr);
+}
+\f
+/*
+ *--------------------------------------------------------------
+ *
+ * TkPostscriptPhoto --
+ *
+ * This procedure is called to output the contents of a
+ * photo image in Postscript by calling the Tk_PostscriptPhoto
+ * function.
+ *
+ * Results:
+ * Returns a standard Tcl return value.
+ *
+ * Side effects:
+ * None.
+ *
+ *--------------------------------------------------------------
+ */
+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;
+{
+ Tk_PhotoImageBlock block;
+
+ Tk_PhotoGetImage((Tk_PhotoHandle) clientData, &block);
+ block.pixelPtr += y * block.pitch + x * block.pixelSize;
+
+ return Tk_PostscriptPhoto(interp, &block, psInfo, width, height);
+}
+