OSDN Git Service

touched all tk files to ease next import
[pf3gnuchains/pf3gnuchains4x.git] / tk / generic / tkImgPhoto.c
index 72fddfe..7416771 100644 (file)
@@ -2,7 +2,7 @@
  * 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
@@ -121,6 +129,9 @@ typedef struct ColorTable {
  * 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
@@ -147,8 +158,8 @@ typedef struct PhotoMaster {
                                 * 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
@@ -211,14 +222,14 @@ typedef struct PhotoInstance {
 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. */
 };
 
@@ -270,7 +281,7 @@ static char *optionNames[] = {
  */
 
 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,
@@ -282,6 +293,10 @@ static void                ImgPhotoDisplay _ANSI_ARGS_((ClientData clientData,
 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 */
@@ -290,9 +305,18 @@ Tk_ImageType tkPhotoImageType = {
     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
  */
@@ -306,8 +330,6 @@ Tk_ImageType tkPhotoImageType = {
  * 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,
@@ -332,26 +354,20 @@ static int imgPhotoColorHashInitialized;
 #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,
@@ -359,7 +375,7 @@ 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,
@@ -376,18 +392,19 @@ static void               DisposeInstance _ANSI_ARGS_((ClientData clientData));
 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))
@@ -397,7 +414,7 @@ static void         DitherInstance _ANSI_ARGS_((PhotoInstance *instancePtr,
 /*
  *----------------------------------------------------------------------
  *
- * 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
@@ -413,6 +430,25 @@ static void                DitherInstance _ANSI_ARGS_((PhotoInstance *instancePtr,
  *
  *----------------------------------------------------------------------
  */
+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)
@@ -423,13 +459,20 @@ 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
 /*
@@ -451,11 +494,11 @@ Tk_CreatePhotoImageFormat(formatPtr)
  */
 
 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). */
@@ -485,7 +528,7 @@ ImgPhotoCreate(interp, name, argc, objv, typePtr, master, clientDataPtr)
      * 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;
     }
@@ -513,14 +556,24 @@ ImgPhotoCreate(interp, name, argc, objv, typePtr, master, clientDataPtr)
  */
 
 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;
@@ -530,7 +583,6 @@ ImgPhotoCmd(clientData, interp, argc, objv)
     unsigned char *pixelPtr;
     Tk_PhotoImageBlock block;
     Tk_Window tkwin;
-    char string[16];
     XColor color;
     Tk_PhotoImageFormat *imageFormat;
     int imageWidth, imageHeight;
@@ -538,96 +590,126 @@ ImgPhotoCmd(clientData, interp, argc, objv)
     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.
         */
@@ -639,14 +721,12 @@ ImgPhotoCmd(clientData, interp, argc, objv)
        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;
        }
 
@@ -655,8 +735,9 @@ ImgPhotoCmd(clientData, interp, argc, objv)
         * 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;
        }
@@ -722,8 +803,9 @@ ImgPhotoCmd(clientData, interp, argc, objv)
                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;
 
        /*
@@ -739,13 +821,11 @@ ImgPhotoCmd(clientData, interp, argc, objv)
        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)
@@ -771,10 +851,10 @@ ImgPhotoCmd(clientData, interp, argc, objv)
         */
 
        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;
@@ -782,7 +862,8 @@ ImgPhotoCmd(clientData, interp, argc, objv)
                }
            }
            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;
            }
@@ -796,39 +877,37 @@ ImgPhotoCmd(clientData, interp, argc, objv)
         */
 
        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;
        }
@@ -841,7 +920,9 @@ ImgPhotoCmd(clientData, interp, argc, objv)
        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.
         */
@@ -850,19 +931,19 @@ ImgPhotoCmd(clientData, interp, argc, objv)
        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;
@@ -873,8 +954,16 @@ ImgPhotoCmd(clientData, interp, argc, objv)
            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;
@@ -886,7 +975,8 @@ ImgPhotoCmd(clientData, interp, argc, objv)
            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;
        }
@@ -955,30 +1045,31 @@ ImgPhotoCmd(clientData, interp, argc, objv)
        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;
        }
 
@@ -996,7 +1087,8 @@ ImgPhotoCmd(clientData, interp, argc, objv)
         * 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;
        }
@@ -1004,8 +1096,14 @@ ImgPhotoCmd(clientData, interp, argc, objv)
                != 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;
        }
@@ -1044,17 +1142,22 @@ ImgPhotoCmd(clientData, interp, argc, objv)
         * 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.
@@ -1063,11 +1166,11 @@ ImgPhotoCmd(clientData, interp, argc, objv)
            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);
            }
 
@@ -1082,12 +1185,15 @@ ImgPhotoCmd(clientData, interp, argc, objv)
            }
 
        } 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.
          */
@@ -1108,13 +1214,11 @@ ImgPhotoCmd(clientData, interp, argc, objv)
        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)
@@ -1141,16 +1245,30 @@ ImgPhotoCmd(clientData, interp, argc, objv)
         */
 
        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) {
@@ -1158,10 +1276,12 @@ ImgPhotoCmd(clientData, interp, argc, objv)
                        "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;
@@ -1173,8 +1293,13 @@ ImgPhotoCmd(clientData, interp, argc, objv)
         */
 
        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);
        }
@@ -1182,11 +1307,8 @@ ImgPhotoCmd(clientData, interp, argc, objv)
            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;
@@ -1211,7 +1333,7 @@ ImgPhotoCmd(clientData, interp, argc, objv)
  */
 
 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. */
@@ -1219,27 +1341,27 @@ ParseSubcommandOptions(optPtr, interp, allowedOptions, optIndexPtr, argc, argv)
     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;
@@ -1249,13 +1371,12 @@ ParseSubcommandOptions(optPtr, interp, allowedOptions, optIndexPtr, argc, argv)
         * 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;
@@ -1271,7 +1392,8 @@ ParseSubcommandOptions(optPtr, interp, allowedOptions, optIndexPtr, argc, argv)
         */
 
        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) {
@@ -1300,10 +1422,10 @@ ParseSubcommandOptions(optPtr, interp, allowedOptions, optIndexPtr, argc, argv)
             * 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;
                }
@@ -1317,22 +1439,26 @@ ParseSubcommandOptions(optPtr, interp, allowedOptions, optIndexPtr, argc, argv)
             * 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;
                    }
@@ -1343,7 +1469,7 @@ ParseSubcommandOptions(optPtr, interp, allowedOptions, optIndexPtr, argc, argv)
            }
 
            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;
@@ -1442,7 +1568,7 @@ ParseSubcommandOptions(optPtr, interp, allowedOptions, optIndexPtr, argc, argv)
  *
  * 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
@@ -1452,38 +1578,48 @@ ParseSubcommandOptions(optPtr, interp, allowedOptions, optIndexPtr, argc, argv)
  */
 
 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.
@@ -1494,7 +1630,7 @@ ImgPhotoConfigureMaster(interp, masterPtr, argc, objv, flags)
      */
 
     oldFileString = masterPtr->fileString;
-    oldDataObj = (oldFileString == NULL) ? masterPtr->dataObj: NULL;
+    oldData = (oldFileString == NULL) ? masterPtr->dataString: NULL;
     oldFormat = masterPtr->format;
     oldPaletteString = masterPtr->palette;
     oldGamma = masterPtr->gamma;
@@ -1504,9 +1640,11 @@ ImgPhotoConfigureMaster(interp, masterPtr, argc, objv, flags)
      */
 
     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
@@ -1517,22 +1655,30 @@ ImgPhotoConfigureMaster(interp, masterPtr, argc, objv, flags)
        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.
@@ -1567,15 +1713,23 @@ ImgPhotoConfigureMaster(interp, masterPtr, argc, objv, flags)
                != 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);
@@ -1583,25 +1737,35 @@ ImgPhotoConfigureMaster(interp, masterPtr, argc, objv, flags)
            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;
     }
 
@@ -1814,7 +1978,7 @@ ImgPhotoGet(tkwin, masterData)
     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;
@@ -1955,9 +2119,8 @@ ImgPhotoGet(tkwin, masterData)
     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.
      */
@@ -2133,8 +2296,11 @@ ImgPhotoDelete(masterData)
     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);
@@ -3225,20 +3391,29 @@ DisposeInstance(clientData)
  */
 
 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
@@ -3246,11 +3421,11 @@ MatchFileFormat(interp, chan, fileName, formatString, imageFormatPtr,
      */
 
     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;
@@ -3263,8 +3438,8 @@ MatchFileFormat(interp, chan, fileName, formatString, imageFormatPtr,
        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;
                }
@@ -3275,10 +3450,42 @@ MatchFileFormat(interp, chan, fileName, formatString, imageFormatPtr,
            }
        }
     }
+    if (formatPtr == NULL) {
+      useoldformat = 1;
+      for (formatPtr = tsdPtr->oldFormatList; formatPtr != NULL;
+        formatPtr = formatPtr->nextPtr) {
+       if (formatString != NULL) {
+           if (strncasecmp(formatString,
+                   formatPtr->name, strlen(formatPtr->name)) != 0) {
+               continue;
+           }
+           matched = 1;
+           if (formatPtr->fileMatchProc == NULL) {
+               Tcl_AppendResult(interp, "-file option isn't supported for ",
+                       formatString, " images", (char *) NULL);
+               return TCL_ERROR;
+           }
+       }
+       if (formatPtr->fileMatchProc != NULL) {
+           (void) Tcl_Seek(chan, 0L, SEEK_SET);
+           if ((*formatPtr->fileMatchProc)(chan, fileName, (Tcl_Obj *) formatString,
+                   widthPtr, heightPtr, interp)) {
+               if (*widthPtr < 1) {
+                   *widthPtr = 1;
+               }
+               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,
@@ -3289,6 +3496,7 @@ MatchFileFormat(interp, chan, fileName, formatString, imageFormatPtr,
     }
 
     *imageFormatPtr = formatPtr;
+    *oldformat = useoldformat;
     (void) Tcl_Seek(chan, 0L, SEEK_SET);
     return TCL_OK;
 }
@@ -3316,19 +3524,28 @@ MatchFileFormat(interp, chan, fileName, formatString, imageFormatPtr,
  */
 
 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
@@ -3336,11 +3553,11 @@ MatchStringFormat(interp, dataObj, formatString, imageFormatPtr,
      */
 
     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;
@@ -3352,15 +3569,41 @@ MatchStringFormat(interp, dataObj, formatString, imageFormatPtr,
        }
        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",
@@ -3370,6 +3613,7 @@ MatchStringFormat(interp, dataObj, formatString, imageFormatPtr,
     }
 
     *imageFormatPtr = formatPtr;
+    *oldformat = useoldformat;
     return TCL_OK;
 }
 \f
@@ -3482,13 +3726,8 @@ Tk_PhotoPutBlock(handle, blockPtr, x, y, width, height)
 
     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];
@@ -3505,7 +3744,13 @@ Tk_PhotoPutBlock(handle, blockPtr, x, y, width, height)
     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)))) {
@@ -3524,11 +3769,24 @@ Tk_PhotoPutBlock(handle, blockPtr, x, y, width, height)
                    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;
@@ -3541,18 +3799,67 @@ Tk_PhotoPutBlock(handle, blockPtr, x, y, width, height)
      * Add this new block to the region which specifies which data is valid.
      */
 
+  if (alphaOffset) {
+    int x1, y1, end;
+    
+    /*
+     * This block is grossly inefficient.  For each row in the image, it
+     * finds each continguous string of transparent pixels, then marks those
+     * areas as invalid in the validRegion mask.  This makes drawing very
+     * efficient, because of the way we use X:  we just say, here's your
+     * mask, and here's your data.  We need not worry about the current
+     * background color, etc.  But this costs us a lot on the image setup.
+     * Still, image setup only happens once, whereas the drawing happens
+     * many times, so this might be the best way to go.
+     *
+     * An alternative might be to not set up this mask, and instead, at
+     * drawing time, for each transparent pixel, set its color to the
+     * color of the background behind that pixel.  This is what I suspect
+     * most of programs do.  However, they don't have to deal with the canvas,
+     * which could have many different background colors.  Determining the
+     * correct bg color for a given pixel might be expensive.
+     */
+     
+    destLinePtr = masterPtr->pix24 + (y * masterPtr->width + x) * 4 + 3;
+    for (y1 = 0; y1 < height; y1++) {
+       x1 = 0;
+       destPtr = destLinePtr;
+       while (x1 < width) {
+           /* search for first non-transparent pixel */
+           while ((x1 < width) && !*destPtr) {
+                   x1++; destPtr += 4;
+           }
+           end = x1;
+           /* search for first transparent pixel */
+           while ((end < width) && *destPtr) {
+               end++; destPtr += 4;
+           }
+           if (end > x1) {
+               rect.x = x + x1;
+               rect.y = y + y1;
+               rect.width = end - x1;
+               rect.height = 1;
+               TkUnionRectWithRegion(&rect, masterPtr->validRegion,
+                       masterPtr->validRegion);
+           }
+           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.
@@ -3656,13 +3963,8 @@ Tk_PhotoPutZoomedBlock(handle, blockPtr, x, y, width, height, zoomX, zoomY,
 
     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];
@@ -3718,10 +4020,23 @@ 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++ = 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;
                }
@@ -3739,18 +4054,49 @@ Tk_PhotoPutZoomedBlock(handle, blockPtr, x, y, width, height, zoomX, zoomY,
      * 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.
@@ -3763,7 +4109,7 @@ Tk_PhotoPutZoomedBlock(handle, blockPtr, x, y, width, height, zoomX, zoomY,
 /*
  *----------------------------------------------------------------------
  *
- * 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.
@@ -3779,14 +4125,15 @@ Tk_PhotoPutZoomedBlock(handle, blockPtr, x, y, width, height, zoomX, zoomY,
  *----------------------------------------------------------------------
  */
 
-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)) {
@@ -4431,7 +4778,8 @@ ImgGetPhoto(masterPtr, blockPtr, optPtr)
        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) {
@@ -4546,22 +4894,23 @@ ImgGetPhoto(masterPtr, blockPtr, optPtr)
  */
 
 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;
@@ -4572,10 +4921,11 @@ ImgStringWrite (interp, dataPtr, formatString, blockPtr)
                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
@@ -4618,5 +4968,189 @@ Tk_PhotoGetImage(handle, blockPtr)
     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);
+}
+