aboutsummaryrefslogtreecommitdiff
path: root/graphics/gdtclft
diff options
context:
space:
mode:
authorMikhail Teterin <mi@FreeBSD.org>2014-11-18 23:54:17 +0000
committerMikhail Teterin <mi@FreeBSD.org>2014-11-18 23:54:17 +0000
commitbef44812562739bbe3621ef7270dde65aed534ff (patch)
tree7fceea44817b66596d03a186578019a79eab21d5 /graphics/gdtclft
parent817763946d970c5958724d3a1fba9457500c2ee4 (diff)
downloadports-bef44812562739bbe3621ef7270dde65aed534ff.tar.gz
ports-bef44812562739bbe3621ef7270dde65aed534ff.zip
Notes
Diffstat (limited to 'graphics/gdtclft')
-rw-r--r--graphics/gdtclft/Makefile37
-rw-r--r--graphics/gdtclft/distinfo2
-rw-r--r--graphics/gdtclft/files/Makefile.bsd33
-rw-r--r--graphics/gdtclft/files/patch-improve1362
-rw-r--r--graphics/gdtclft/pkg-descr10
5 files changed, 1444 insertions, 0 deletions
diff --git a/graphics/gdtclft/Makefile b/graphics/gdtclft/Makefile
new file mode 100644
index 000000000000..35e955d0ca8a
--- /dev/null
+++ b/graphics/gdtclft/Makefile
@@ -0,0 +1,37 @@
+# Created by: Mikhail Teterin <mi@aldan.algebra.com>
+# $FreeBSD$
+
+PORTNAME= Gdtclft
+PORTVERSION= 2.2.5
+PORTREVISION= 14
+CATEGORIES= graphics tcl
+MASTER_SITES=
+DISTNAME= ${PORTNAME}${PORTVERSION}
+
+MAINTAINER= mi@aldan.algebra.com
+COMMENT= TCL interface to the Thomas Boutell's Gd library
+
+LIB_DEPENDS= libgd.so:${PORTSDIR}/graphics/gd
+
+USES= tcl:84+ uidfix
+
+MAKEFILE= ${FILESDIR}/Makefile.bsd
+MAKE_ENV= TCL_VER=${TCL_VER} MKDIR="${MKDIR}" \
+ TCL_SHLIB_VER=${TCL_SHLIB_VER} \
+ INSTALL_DATA="${INSTALL_DATA}" STAGEDIR="${STAGEDIR}"
+ALL_TARGET= all
+
+MANNPAGE= gdtclft.n
+GDTCLDIR= lib/tcl${TCL_VER}/gdtclft
+PLIST_DIRS= ${GDTCLDIR}
+PLIST_FILES= ${GDTCLDIR}/pkgIndex.tcl
+PLIST_FILES+= ${GDTCLDIR}/libGdtclft2.so
+PLIST_FILES+= man/mann/${MANNPAGE}.gz
+
+post-patch:
+ ${REINPLACE_CMD} -Ee 's,[[:space:]]+$$,,' ${WRKSRC}/${MANNPAGE}
+
+post-install:
+ ${GZIP_CMD} -9 -f < ${WRKSRC}/${MANNPAGE} > ${STAGEDIR}${PREFIX}/man/mann/${MANNPAGE}.gz
+
+.include <bsd.port.mk>
diff --git a/graphics/gdtclft/distinfo b/graphics/gdtclft/distinfo
new file mode 100644
index 000000000000..d79f8eddbc8f
--- /dev/null
+++ b/graphics/gdtclft/distinfo
@@ -0,0 +1,2 @@
+SHA256 (Gdtclft2.2.5.tar.gz) = 34aa5414f74aa93269c03268e95f2cde85836488e8b6820c5b8bb6a088bc698e
+SIZE (Gdtclft2.2.5.tar.gz) = 47257
diff --git a/graphics/gdtclft/files/Makefile.bsd b/graphics/gdtclft/files/Makefile.bsd
new file mode 100644
index 000000000000..a75addfe8e40
--- /dev/null
+++ b/graphics/gdtclft/files/Makefile.bsd
@@ -0,0 +1,33 @@
+PACKAGE = Gdtclft
+VERSION = 2.3
+SHLIB_NAME = lib${PACKAGE}2.so
+
+SRCS = gdCmd.c
+
+LOCALBASE ?=/usr/local
+PREFIX ?=/usr/local
+TCL_VER ?=8.4
+WARNS = 3
+
+LDADD = -L${LOCALBASE}/lib -lgd -lpng -lz -lm -ltcl${TCL_SHLIB_VER}
+
+CFLAGS +=-I${LOCALBASE}/include/tcl${TCL_VER} -I${LOCALBASE}/include/gd
+CFLAGS +=-DNDEBUG -Wall -I. -I${LOCALBASE}/include
+CFLAGS +=-DVERSION=\"${VERSION}\"
+
+all: pkgIndex.tcl
+
+pkgIndex.tcl:
+ echo 'package ifneeded $(PACKAGE) $(VERSION) [list load [file join $$dir $(SHLIB_NAME)] $(PACKAGE)]' > pkgIndex.tcl
+
+DIR = lib/tcl${TCL_VER}/gdtclft
+LIBDIR = ${PREFIX}/${DIR}
+MANDIR = ${PREFIX}/man/man
+
+${STAGEDIR}${LIBDIR}:
+ ${MKDIR} $@
+
+beforeinstall: ${STAGEDIR}${LIBDIR}
+ ${INSTALL_DATA} pkgIndex.tcl ${STAGEDIR}${LIBDIR}
+
+.include <bsd.lib.mk>
diff --git a/graphics/gdtclft/files/patch-improve b/graphics/gdtclft/files/patch-improve
new file mode 100644
index 000000000000..8c53a2d6a7ea
--- /dev/null
+++ b/graphics/gdtclft/files/patch-improve
@@ -0,0 +1,1362 @@
+This patch adds support for GIF, XPM, WBMP, and JPEG file formats, which
+are supported by the underlying GD.
+
+GIF, JPEG, and WBMP formats are also added as _output_ formats.
+
+Also, in case of file-opening failure, a useful error string is
+returned.
+
+Dispense with our own table of handles and use Tcl-objects capability
+instead.
+
+Compiler-warning fixes now allow compiling on FreeBSD with WARNS=3.
+
+When used in a safe interpreter, the functionality is limited to
+disallow access to filesystem.
+
+Use freely and get yourself a pademelon...
+
+ -mi (http://cafepress.com/buy/pademelon?pid=5934485)
+
+--- gdCmd.c Fri Aug 4 17:11:05 2000
++++ gdCmd.c 2014-04-29 19:42:13.000000000 -0400
+@@ -19,4 +19,5 @@
+ */
+
++#include <errno.h>
+ #include <stdio.h>
+ #include <string.h>
+@@ -24,5 +25,4 @@
+ #include <tcl.h>
+ #include "gd.h"
+-#include "gdhandle.h"
+
+ #ifdef WIN32
+@@ -30,28 +30,47 @@
+ #endif
+
+-void *GDHandleTable;
++static Tcl_UpdateStringProc GdPtrTypeUpdate;
++static Tcl_SetFromAnyProc GdPtrTypeSet;
++static Tcl_ObjType GdPtrType = {
++ .name = "gd",
++ .updateStringProc = GdPtrTypeUpdate,
++ .setFromAnyProc = GdPtrTypeSet
++};
++#define IMGPTR(O) (O->internalRep.otherValuePtr)
+
+-/* global data */
+-typedef struct {
+- tblHeader_pt handleTbl;
+-} GdData;
++/* The only two symbols exported */
++Tcl_AppInitProc Gdtclft_Init, Gdtclft_SafeInit;
+
+-static int tclGdCreateCmd(), tclGdDestroyCmd(), tclGdWriteCmd(),
+- tclGdColorCmd(), tclGdInterlaceCmd(), tclGdSetCmd(), tclGdLineCmd(),
+- tclGdRectCmd(), tclGdArcCmd(), tclGdFillCmd(), tclGdSizeCmd(),
+- tclGdTextCmd(), tclGdCopyCmd(), tclGdGetCmd(),
+- tclGdBrushCmd(), tclGdStyleCmd(), tclGdTileCmd(), tclGdPolygonCmd(),
+- tclGdColorNewCmd(), tclGdColorExactCmd(), tclGdColorClosestCmd(),
+- tclGdColorResolveCmd(), tclGdColorFreeCmd(), tclGdColorTranspCmd(),
+- tclGdColorGetCmd(), tclGdWriteBufCmd();
++typedef int (GdDataFunction)(Tcl_Interp *interp,
++ int argc, Tcl_Obj *CONST objv[]);
++typedef int (GdImgFunction)(Tcl_Interp *interp, gdImagePtr gdImg,
++ int argc, const int args[]);
++
++static GdDataFunction tclGdCreateCmd, tclGdDestroyCmd, tclGdWriteCmd,
++ tclGdColorCmd, tclGdInterlaceCmd, tclGdSetCmd, tclGdLineCmd,
++ tclGdRectCmd, tclGdArcCmd, tclGdFillCmd, tclGdSizeCmd,
++ tclGdTextCmd, tclGdCopyCmd, tclGdGetCmd, tclGdWriteBufCmd,
++ tclGdBrushCmd, tclGdStyleCmd, tclGdTileCmd, tclGdPolygonCmd;
++
++static GdImgFunction tclGdColorNewCmd, tclGdColorExactCmd,
++ tclGdColorClosestCmd, tclGdColorResolveCmd, tclGdColorFreeCmd,
++ tclGdColorTranspCmd, tclGdColorGetCmd;
+
+ typedef struct {
+- char *cmd;
+- int (*f)();
+- int minargs, maxargs;
+- int subcmds;
+- int ishandle;
+- char *usage;
+-} cmdOptions;
++ const char *cmd;
++ GdDataFunction *f;
++ unsigned int minargs, maxargs;
++ unsigned int subcmds;
++ unsigned int ishandle;
++ unsigned int unsafearg;
++ const char *usage;
++} cmdDataOptions;
++
++typedef struct {
++ const char *cmd;
++ GdImgFunction *f;
++ unsigned int minargs, maxargs;
++ const char *usage;
++} cmdImgOptions;
+
+ typedef struct {
+@@ -60,53 +79,81 @@
+ } BuffSinkContext;
+
+-static cmdOptions subcmdVec[] = {
+- {"create", tclGdCreateCmd, 2, 2, 0, 0,
+- "width height"},
+- {"createFromPNG", tclGdCreateCmd, 1, 1, 0, 0,
++static cmdDataOptions subcmdVec[] = {
++ {"create", tclGdCreateCmd, 2, 3, 0, 0, 0,
++ "width height ?true?"},
++ {"createFromPNG", tclGdCreateCmd, 1, 1, 0, 0, 2,
++ "filehandle"},
++ {"createFromGIF", tclGdCreateCmd, 1, 1, 0, 0, 2,
++ "filehandle"},
++ {"createFromGD", tclGdCreateCmd, 1, 1, 0, 0, 2,
+ "filehandle"},
+- {"createFromGD", tclGdCreateCmd, 1, 1, 0, 0,
++ {"createFromGD2", tclGdCreateCmd, 1, 1, 0, 0, 2,
+ "filehandle"},
+- {"createFromXBM", tclGdCreateCmd, 1, 1, 0, 0,
++ {"createFromXBM", tclGdCreateCmd, 1, 1, 0, 0, 2,
++ "filehandle"},
++#ifdef NOX11
++ {"createFromXPM-NOT-AVAILABLE", tclGdCreateCmd, 1, 1, 0, 0, 2,
++ "filename"},
++#else
++ {"createFromXPM", tclGdCreateCmd, 1, 1, 0, 0, 2,
++ "filename"},
++#endif
++ {"createFromJPG", tclGdCreateCmd, 1, 1, 0, 0, 2,
++ "filehandle"},
++ {"createFromJPEG", tclGdCreateCmd, 1, 1, 0, 0, 2,
++ "filehandle"},
++ {"createFromWBMP", tclGdCreateCmd, 1, 1, 0, 0, 2,
+ "filehandle"},
+
+- {"destroy", tclGdDestroyCmd, 1, 1, 0, 1,
++ {"destroy", tclGdDestroyCmd, 1, 1, 0, 1, 0,
+ "gdhandle"},
+
+- {"writePNG", tclGdWriteCmd, 2, 2, 0, 1,
++ {"writeGIF", tclGdWriteCmd, 2, 2, 0, 1, 3,
++ "gdhandle filehandle"},
++ {"writeJPG", tclGdWriteCmd, 2, 3, 0, 1, 3,
++ "gdhandle filehandle ?quality?"},
++ {"writeJPEG", tclGdWriteCmd, 2, 3, 0, 1, 3,
++ "gdhandle filehandle ?quality?"},
++ {"writePNG", tclGdWriteCmd, 2, 2, 0, 1, 3,
+ "gdhandle filehandle"},
+- {"writePNGvar", tclGdWriteBufCmd, 2, 2, 0, 1,
++ {"writePNGvar", tclGdWriteBufCmd, 2, 2, 0, 1, 0,
+ "gdhandle var"},
+- {"writeGD", tclGdWriteCmd, 2, 2, 0, 1,
++ {"writeGD", tclGdWriteCmd, 2, 2, 0, 1, 3,
+ "gdhandle filehandle"},
+-
+- {"interlace", tclGdInterlaceCmd, 1, 2, 0, 1,
++ {"writeGD2", tclGdWriteCmd, 2, 2, 0, 1, 3,
++ "gdhandle filehandle"},
++ {"writeWBMP", tclGdWriteCmd, 3, 3, 0, 1, 3,
++ "gdhandle filehandle foreground"},
++ {"writeGD2", tclGdWriteCmd, 2, 2, 0, 1, 3,
++ "gdhandle filehandle"},
++ {"interlace", tclGdInterlaceCmd, 1, 2, 0, 1, 0,
+ "gdhandle ?on-off?"},
+
+- {"color", tclGdColorCmd, 2, 5, 1, 1,
++ {"color", tclGdColorCmd, 2, 5, 1, 1, 0,
+ "option values..."},
+- {"brush", tclGdBrushCmd, 2, 2, 0, 2,
++ {"brush", tclGdBrushCmd, 2, 2, 0, 2, 0,
+ "gdhandle brushhandle"},
+- {"style", tclGdStyleCmd, 2, 999, 0, 1,
++ {"style", tclGdStyleCmd, 2, 999, 0, 1, 0,
+ "gdhandle color..."},
+- {"tile", tclGdTileCmd, 2, 2, 0, 2,
++ {"tile", tclGdTileCmd, 2, 2, 0, 2, 0,
+ "gdhandle tilehandle"},
+
+- {"set", tclGdSetCmd, 4, 4, 0, 1,
++ {"set", tclGdSetCmd, 4, 4, 0, 1, 0,
+ "gdhandle color x y"},
+- {"line", tclGdLineCmd, 6, 6, 0, 1,
++ {"line", tclGdLineCmd, 6, 6, 0, 1, 0,
+ "gdhandle color x1 y1 x2 y2"},
+- {"rectangle", tclGdRectCmd, 6, 6, 0, 1,
++ {"rectangle", tclGdRectCmd, 6, 6, 0, 1, 0,
+ "gdhandle color x1 y1 x2 y2"},
+- {"fillrectangle", tclGdRectCmd, 6, 6, 0, 1,
++ {"fillrectangle", tclGdRectCmd, 6, 6, 0, 1, 0,
+ "gdhandle color x1 y1 x2 y2"},
+- {"arc", tclGdArcCmd, 8, 8, 0, 1,
++ {"arc", tclGdArcCmd, 8, 8, 0, 1, 0,
+ "gdhandle color cx cy width height start end"},
+- {"fillarc", tclGdArcCmd, 8, 8, 0, 1,
++ {"fillarc", tclGdArcCmd, 8, 8, 0, 1, 0,
+ "gdhandle color cx cy width height start end"},
+- {"polygon", tclGdPolygonCmd, 2, 999, 0, 1,
++ {"polygon", tclGdPolygonCmd, 2, 999, 0, 1, 0,
+ "gdhandle color x1 y1 x2 y2 x3 y3 ..."},
+- {"fillpolygon", tclGdPolygonCmd, 3, 999, 0, 1,
++ {"fillpolygon", tclGdPolygonCmd, 3, 999, 0, 1, 0,
+ "gdhandle color x1 y1 x2 y2 x3 y3 ..."},
+- {"fill", tclGdFillCmd, 4, 5, 0, 1,
++ {"fill", tclGdFillCmd, 4, 5, 0, 1, 0,
+ "gdhandle color x y ?bordercolor?"},
+ /*
+@@ -114,32 +161,25 @@
+ * of text string, so the text command provides its own handle processing and checking
+ */
+- {"text", tclGdTextCmd, 8, 8, 0, 0,
++ {"text", tclGdTextCmd, 8, 8, 0, 0, 4,
+ "gdhandle color fontpathname size angle x y string"},
+
+
+- {"copy", tclGdCopyCmd, 8, 10, 0, 2,
++ {"copy", tclGdCopyCmd, 8, 10, 0, 2, 0,
+ "desthandle srchandle destx desty srcx srcy destw desth ?srcw srch?"},
+
+- {"get", tclGdGetCmd, 3, 3, 0, 1,
++ {"get", tclGdGetCmd, 3, 3, 0, 1, 0,
+ "gdhandle x y"},
+- {"size", tclGdSizeCmd, 1, 1, 0, 1,
++ {"size", tclGdSizeCmd, 1, 1, 0, 1, 0,
+ "gdhandle"},
+ };
+
+-static cmdOptions colorCmdVec[] = {
+- {"new", tclGdColorNewCmd, 5, 5, 1, 1,
+- "gdhandle red green blue"},
+- {"exact", tclGdColorExactCmd, 5, 5, 1, 1,
+- "gdhandle red green blue"},
+- {"closest", tclGdColorClosestCmd, 5, 5, 1, 1,
+- "gdhandle red green blue"},
+- {"resolve", tclGdColorResolveCmd, 5, 5, 1, 1,
+- "gdhandle red green blue"},
+- {"free", tclGdColorFreeCmd, 3, 3, 1, 1,
+- "gdhandle color"},
+- {"transparent", tclGdColorTranspCmd, 2, 3, 1, 1,
+- "gdhandle ?color?"},
+- {"get", tclGdColorGetCmd, 2, 3, 1, 1,
+- "gdhandle ?color?"}
++static cmdImgOptions colorCmdVec[] = {
++ {"new", tclGdColorNewCmd, 5, 5, "red green blue"},
++ {"exact", tclGdColorExactCmd, 5, 5, "red green blue"},
++ {"closest", tclGdColorClosestCmd, 5, 5, "red green blue"},
++ {"resolve", tclGdColorResolveCmd, 5, 5, "red green blue"},
++ {"free", tclGdColorFreeCmd, 3, 3, "color"},
++ {"transparent", tclGdColorTranspCmd, 2, 3, "?color?"},
++ {"get", tclGdColorGetCmd, 2, 3, "?color?"}
+ };
+
+@@ -317,11 +357,10 @@
+ *
+ */
+-int
++static int
+ gdCmd(ClientData clientData, Tcl_Interp *interp,
+ int argc, Tcl_Obj *CONST objv[])
+ {
+- GdData *gdData = (GdData *)clientData;
+- int argi, subi;
+- char buf[100];
++ unsigned int argi;
++ size_t subi;
+ /* Check for subcommand. */
+ if (argc < 2) {
+@@ -336,9 +375,7 @@
+
+ /* Check arg count. */
+- if (argc - 2 < subcmdVec[subi].minargs ||
+- argc - 2 > subcmdVec[subi].maxargs) {
+- sprintf(buf, "wrong # args: should be \"gd %s %s\"",
+- subcmdVec[subi].cmd, subcmdVec[subi].usage);
+- Tcl_SetResult(interp, buf, TCL_VOLATILE);
++ if ((unsigned)argc - 2 < subcmdVec[subi].minargs ||
++ (unsigned)argc - 2 > subcmdVec[subi].maxargs) {
++ Tcl_WrongNumArgs(interp, 2, objv, subcmdVec[subi].usage);
+ return TCL_ERROR;
+ }
+@@ -346,20 +383,6 @@
+ /* Check for valid handle(s). */
+ if (subcmdVec[subi].ishandle > 0) {
+- /* Are any handles allocated? */
+- if (gdData->handleTbl == NULL) {
+- sprintf(buf, "no such handle%s: ",
+- subcmdVec[subi].ishandle > 1 ? "s" : "");
+- Tcl_SetResult(interp, buf, TCL_VOLATILE);
+- for (argi = 2 + subcmdVec[subi].subcmds;
+- argi < 2 + subcmdVec[subi].subcmds +
+- subcmdVec[subi].ishandle;
+- argi++) {
+- Tcl_AppendResult(interp,
+- Tcl_GetString(objv[argi]), " ", 0);
+- }
+- return TCL_ERROR;
+- }
+ /* Check each handle to see if it's a valid handle. */
+- if (2+subcmdVec[subi].subcmds+subcmdVec[subi].ishandle > argc) {
++ if (2+subcmdVec[subi].subcmds+subcmdVec[subi].ishandle > (unsigned)argc) {
+ Tcl_SetResult(interp, "GD handle(s) not specified", TCL_STATIC);
+ return TCL_ERROR;
+@@ -369,12 +392,27 @@
+ subcmdVec[subi].ishandle);
+ argi++) {
+- if (! gdHandleXlate(interp, gdData->handleTbl,
+- Tcl_GetString(objv[argi])))
++ if (objv[argi]->typePtr != &GdPtrType &&
++ GdPtrTypeSet(interp, objv[argi]) != TCL_OK)
+ return TCL_ERROR;
+ }
+ }
+
++ /*
++ * If we are operating in a safe interpreter, check,
++ * if this command is suspect -- and only let existing
++ * filehandles through, if so.
++ */
++ if (clientData != NULL && subcmdVec[subi].unsafearg != 0) {
++ const char *fname =
++ Tcl_GetString(objv[subcmdVec[subi].unsafearg]);
++ if (!Tcl_IsChannelExisting(fname)) {
++ Tcl_AppendResult(interp, "Access to ", fname,
++ " not allowed in safe interpreter", TCL_STATIC);
++ return TCL_ERROR;
++ }
++ }
++
+ /* Call the subcommand function. */
+- return (*subcmdVec[subi].f)(interp, gdData, argc, objv);
++ return (*subcmdVec[subi].f)(interp, argc, objv);
+ }
+ }
+@@ -390,5 +427,5 @@
+
+ static int
+-tclGdCreateCmd(Tcl_Interp *interp, GdData *gdData,
++tclGdCreateCmd(Tcl_Interp *interp,
+ int argc, Tcl_Obj *CONST objv[])
+ {
+@@ -397,16 +434,29 @@
+ FILE *filePtr;
+ ClientData clientdata;
+- char *cmd, buf[50];
++ char *cmd;
++ Tcl_Obj *result;
+ int fileByName;
+
+ cmd = Tcl_GetString(objv[1]);
+ if (strcmp(cmd, "create") == 0) {
++ int trueColor = 0;
++
+ if (Tcl_GetIntFromObj(interp, objv[2], &w) != TCL_OK)
+ return TCL_ERROR;
+ if (Tcl_GetIntFromObj(interp, objv[3], &h) != TCL_OK)
+ return TCL_ERROR;
++ /* An optional argument may specify true for "TrueColor" */
++ if (argc == 5 && Tcl_GetBooleanFromObj(interp, objv[4],
++ &trueColor) == TCL_ERROR)
++ return TCL_ERROR;
++
++ if (trueColor)
++ im = gdImageCreateTrueColor(w, h);
++ else
+ im = gdImageCreate(w, h);
++
+ if (im == NULL)
+ {
++ char buf[255];
+ sprintf(buf, "GD unable to allocate %d X %d image", w, h);
+ Tcl_SetResult(interp, buf, TCL_VOLATILE);
+@@ -414,6 +464,19 @@
+ }
+ } else {
++ char *arg2 = Tcl_GetString(objv[2]);
+ fileByName = 0; /* first try to get file from open channel */
+- if (Tcl_GetOpenFile(interp, Tcl_GetString(objv[2]), 0, 1, &clientdata) == TCL_OK) {
++
++ if (cmd[10] == 'X' && cmd[11] == 'P' && cmd[12] == 'M') {
++#ifdef NOX11
++ Tcl_SetResult(interp, "Support for XPM-files not "
++ "compiled in", TCL_STATIC);
++ return TCL_ERROR;
++#else
++ /* gdImageCreateFromXpm() takes fileNAME */
++ im = gdImageCreateFromXpm(arg2);
++#endif
++ } else {
++ if (Tcl_GetOpenFile(interp, arg2, 0, 1, &clientdata)
++ == TCL_OK) {
+ filePtr = (FILE *)clientdata;
+ } else {
+@@ -422,43 +485,68 @@
+ */
+ fileByName++;
+- if ((filePtr = fopen(Tcl_GetString(objv[2]),"rb")) == NULL) {
++ if ((filePtr = fopen(arg2, "rb")) == NULL) {
++ Tcl_AppendResult(interp,
++ "could not open :", arg2, "': ",
++ strerror(errno), NULL);
+ return TCL_ERROR;
+ }
+ Tcl_ResetResult(interp);
+ }
++
+ /* Read PNG, XBM, or GD file? */
+- if (cmd[10] == 'P') {
++ switch (cmd[10]) {
++ case 'P':
+ im = gdImageCreateFromPng(filePtr);
+- } else if (cmd[10] == 'X') {
++ break;
++ case 'X':
+ im = gdImageCreateFromXbm(filePtr);
+- } else {
++ break;
++ case 'G': /* GIF, GD2, and GD */
++ if (cmd[11] == 'I')
++ im = gdImageCreateFromGif(filePtr);
++ else if (cmd[12] == '2')
++ im = gdImageCreateFromGd2(filePtr);
++ else
+ im = gdImageCreateFromGd(filePtr);
++ break;
++ case 'J':
++ im = gdImageCreateFromJpeg(filePtr);
++ break;
++ case 'W':
++ im = gdImageCreateFromWBMP(filePtr);
++ break;
++ default:
++ Tcl_AppendResult(interp, cmd + 10,
++ "unrecognizable format requested", NULL);
++ return TCL_ERROR;
+ }
+ if (fileByName) {
+ fclose(filePtr);
+ }
++ }
++
+ if (im == NULL) {
+- Tcl_SetResult(interp,"GD unable to read image file", TCL_STATIC);
++ Tcl_AppendResult(interp,
++ "GD unable to read image file `", arg2, "' as ",
++ cmd + 10, NULL);
+ return TCL_ERROR;
+ }
+ }
+
+- *(gdImagePtr *)(gdHandleAlloc(gdData->handleTbl, buf)) = im;
+- Tcl_SetResult(interp, buf, TCL_VOLATILE);
++ result = Tcl_NewObj();
++ IMGPTR(result) = im;
++ result->typePtr = &GdPtrType;
++ result->bytes = NULL;
++ Tcl_SetObjResult(interp, result);
+ return TCL_OK;
+ }
+
+ static int
+-tclGdDestroyCmd(Tcl_Interp *interp, GdData *gdData, int argc, Tcl_Obj *CONST objv[])
++tclGdDestroyCmd(Tcl_Interp *interp, int argc, Tcl_Obj *CONST objv[])
+ {
+ gdImagePtr im;
+- void *hdl;
+
+- /* Get the handle, and the image pointer. */
+- hdl = (void *)gdHandleXlate(interp, gdData->handleTbl,
+- Tcl_GetString(objv[2]));
+- im = *(gdImagePtr *)hdl;
+- /* Release the handle, destroy the image. */
+- gdHandleFree(gdData->handleTbl, hdl);
++ /* Get the image pointer and destroy it */
++ im = IMGPTR(objv[2]);
+ gdImageDestroy(im);
+
+@@ -467,20 +555,45 @@
+
+ static int
+-tclGdWriteCmd(Tcl_Interp *interp, GdData *gdData, int argc, Tcl_Obj *CONST objv[])
++tclGdWriteCmd(Tcl_Interp *interp, int argc, Tcl_Obj *CONST objv[])
+ {
+ gdImagePtr im;
+ FILE *filePtr;
+ ClientData clientdata;
+- char *cmd;
++ const char *cmd, *fname;
+ int fileByName;
++ int arg4;
+
+ cmd = Tcl_GetString(objv[1]);
++ if (cmd[5] == 'J' || cmd[5] == 'W') {
++ /* JPEG and WBMP expect an extra (integer) argument */
++ if (argc < 5) {
++ if (cmd[5] == 'J')
++ arg4 = -1; /* default quality-level */
++ else {
++ Tcl_SetResult(interp, "WBMP saving requires"
++ " the foreground pixel value", TCL_STATIC);
++ return TCL_ERROR;
++ }
++ } else if (Tcl_GetIntFromObj(interp, objv[4], &arg4) != TCL_OK)
++ return TCL_ERROR;
++
++ if (cmd[5] == 'J' && argc > 4 && (arg4 > 100 || arg4 < 1)) {
++ Tcl_SetObjResult(interp, objv[4]);
++ Tcl_AppendResult(interp, ": JPEG image quality, if "
++ "specified, must be an integer from 1 to 100, "
++ "or -1 for default", NULL);
++ return TCL_ERROR;
++ }
++ /* XXX no error-checking for the WBMP case here */
++ }
++
+ /* Get the image pointer. */
+- im = *(gdImagePtr *)gdHandleXlate(interp, gdData->handleTbl,
+- Tcl_GetString(objv[2]));
++ im = IMGPTR(objv[2]);
++
++ fname = Tcl_GetString(objv[3]);
+
+ /* Get the file reference. */
+ fileByName = 0; /* first try to get file from open channel */
+- if (Tcl_GetOpenFile(interp, Tcl_GetString(objv[3]), 1, 1, &clientdata) == TCL_OK) {
++ if (Tcl_GetOpenFile(interp, fname, 1, 1, &clientdata) == TCL_OK) {
+ filePtr = (FILE *)clientdata;
+ } else {
+@@ -489,5 +602,7 @@
+ */
+ fileByName++;
+- if ((filePtr = fopen(Tcl_GetString(objv[3]),"wb")) == NULL) {
++ if ((filePtr = fopen(fname, "wb")) == NULL) {
++ Tcl_AppendResult(interp, "could not open :", fname,
++ "': ", strerror(errno), NULL);
+ return TCL_ERROR;
+ }
+@@ -496,8 +611,22 @@
+
+ /* Do it. */
+- if (cmd[5] == 'P') {
++ switch (cmd[5]) {
++ case 'P':
+ gdImagePng(im, filePtr);
+- } else {
++ break;
++ case 'G':
++ if (cmd[6] == 'I')
++ gdImageGif(im, filePtr);
++ else if (cmd[7] == '2')
++ gdImageGd2(im, filePtr, GD2_CHUNKSIZE, GD2_FMT_COMPRESSED);
++ else
+ gdImageGd(im, filePtr);
++ break;
++ case 'J':
++ gdImageJpeg(im, filePtr, arg4);
++ break;
++ case 'B':
++ gdImageWBMP(im, arg4, filePtr);
++ break;
+ }
+ if (fileByName) {
+@@ -510,5 +639,5 @@
+
+ static int
+-tclGdInterlaceCmd(Tcl_Interp *interp, GdData *gdData,
++tclGdInterlaceCmd(Tcl_Interp *interp,
+ int argc, Tcl_Obj *CONST objv[])
+ {
+@@ -517,6 +646,5 @@
+
+ /* Get the image pointer. */
+- im = *(gdImagePtr *)gdHandleXlate(interp, gdData->handleTbl,
+- Tcl_GetString(objv[2]));
++ im = IMGPTR(objv[2]);
+
+ if (argc == 4) {
+@@ -535,7 +663,6 @@
+ }
+
+-
+ static int
+-tclGdColorCmd(Tcl_Interp *interp, GdData *gdData,
++tclGdColorCmd(Tcl_Interp *interp,
+ int argc, Tcl_Obj *CONST objv[])
+ {
+@@ -551,17 +678,14 @@
+ {
+ /* Check arg count. */
+- if (argc - 2 < colorCmdVec[subi].minargs ||
+- argc - 2 > colorCmdVec[subi].maxargs)
++ if ((unsigned)argc - 2 < colorCmdVec[subi].minargs ||
++ (unsigned)argc - 2 > colorCmdVec[subi].maxargs)
+ {
+- Tcl_AppendResult(interp,
+- "wrong # args: should be \"gd color ",
+- colorCmdVec[subi].cmd, " ",
+- colorCmdVec[subi].usage, "\"", 0);
++ Tcl_WrongNumArgs(interp, 3, objv,
++ colorCmdVec[subi].usage);
+ return TCL_ERROR;
+ }
+
+ /* Get the image pointer. */
+- im = *(gdImagePtr *)gdHandleXlate(interp, gdData->handleTbl,
+- Tcl_GetString(objv[3]));
++ im = IMGPTR(objv[3]);
+ /* Parse off integer arguments.
+ * 1st 4 are gd color <opt> <handle>
+@@ -605,5 +729,5 @@
+
+ static int
+-tclGdColorNewCmd(Tcl_Interp *interp, gdImagePtr im, int argc, int args[])
++tclGdColorNewCmd(Tcl_Interp *interp, gdImagePtr im, int argc, const int args[])
+ {
+ int color;
+@@ -615,5 +739,5 @@
+
+ static int
+-tclGdColorExactCmd(Tcl_Interp *interp, gdImagePtr im, int argc, int args[])
++tclGdColorExactCmd(Tcl_Interp *interp, gdImagePtr im, int argc, const int args[])
+ {
+ int color;
+@@ -625,5 +749,5 @@
+
+ static int
+-tclGdColorClosestCmd(Tcl_Interp *interp, gdImagePtr im, int argc, int args[])
++tclGdColorClosestCmd(Tcl_Interp *interp, gdImagePtr im, int argc, const int args[])
+ {
+ int color;
+@@ -635,5 +759,5 @@
+
+ static int
+-tclGdColorResolveCmd(Tcl_Interp *interp, gdImagePtr im, int argc, int args[])
++tclGdColorResolveCmd(Tcl_Interp *interp, gdImagePtr im, int argc, const int args[])
+ {
+ int color;
+@@ -645,5 +769,5 @@
+
+ static int
+-tclGdColorFreeCmd(Tcl_Interp *interp, gdImagePtr im, int argc, int args[])
++tclGdColorFreeCmd(Tcl_Interp *interp, gdImagePtr im, int argc, const int args[])
+ {
+ gdImageColorDeallocate(im, args[0]);
+@@ -652,5 +776,5 @@
+
+ static int
+-tclGdColorTranspCmd(Tcl_Interp *interp, gdImagePtr im, int argc, int args[])
++tclGdColorTranspCmd(Tcl_Interp *interp, gdImagePtr im, int argc, const int args[])
+ {
+ int color;
+@@ -668,33 +792,37 @@
+
+ static int
+-tclGdColorGetCmd(Tcl_Interp *interp, gdImagePtr im, int argc, int args[])
++tclGdColorGetCmd(Tcl_Interp *interp, gdImagePtr im, int argc, const int args[])
+ {
+- char buf[30];
+- int i;
++ int i, ncolors;
++ Tcl_Obj *tuple[4], *result;
+
++ ncolors = gdImageColorsTotal(im);
+ /* IF one arg, return the single color, else return list of all colors. */
+ if (argc == 1)
+ {
+ i = args[0];
+- if (i >= gdImageColorsTotal(im) || im->open[i]) {
++ if (i >= ncolors || im->open[i]) {
+ Tcl_SetResult(interp, "No such color", TCL_STATIC);
+ return TCL_ERROR;
+ }
+- sprintf(buf, "%d %d %d %d", i,
+- gdImageRed(im,i),
+- gdImageGreen(im,i),
+- gdImageBlue(im,i));
+- Tcl_SetResult(interp, buf, TCL_VOLATILE);
++ tuple[0] = Tcl_NewIntObj(i);
++ tuple[1] = Tcl_NewIntObj(gdImageRed(im,i));
++ tuple[2] = Tcl_NewIntObj(gdImageGreen(im,i));
++ tuple[3] = Tcl_NewIntObj(gdImageBlue(im,i));
++ Tcl_SetObjResult(interp, Tcl_NewListObj(4, tuple));
+ } else {
+- for (i = 0; i < gdImageColorsTotal(im); i++)
++ result = Tcl_NewListObj(0, NULL);
++ for (i = 0; i < ncolors; i++)
+ {
+ if (im->open[i])
+ continue;
+- sprintf(buf, "%d %d %d %d", i,
+- gdImageRed(im,i),
+- gdImageGreen(im,i),
+- gdImageBlue(im,i));
+- Tcl_AppendElement(interp, buf);
++ tuple[0] = Tcl_NewIntObj(i);
++ tuple[1] = Tcl_NewIntObj(gdImageRed(im,i));
++ tuple[2] = Tcl_NewIntObj(gdImageGreen(im,i));
++ tuple[3] = Tcl_NewIntObj(gdImageBlue(im,i));
++ Tcl_ListObjAppendElement(NULL, result,
++ Tcl_NewListObj(4, tuple));
+ }
++ Tcl_SetObjResult(interp, result);
+ }
+
+@@ -703,5 +831,5 @@
+
+ static int
+-tclGdBrushCmd(Tcl_Interp *interp, GdData *gdData,
++tclGdBrushCmd(Tcl_Interp *interp,
+ int argc, Tcl_Obj *CONST objv[])
+ {
+@@ -709,8 +837,6 @@
+
+ /* Get the image pointers. */
+- im = *(gdImagePtr *)gdHandleXlate(interp, gdData->handleTbl,
+- Tcl_GetString(objv[2]));
+- imbrush = *(gdImagePtr *)gdHandleXlate(interp, gdData->handleTbl,
+- Tcl_GetString(objv[3]));
++ im = IMGPTR(objv[2]);
++ imbrush = IMGPTR(objv[3]);
+
+ /* Do it. */
+@@ -721,5 +847,5 @@
+
+ static int
+-tclGdTileCmd(Tcl_Interp *interp, GdData *gdData,
++tclGdTileCmd(Tcl_Interp *interp,
+ int argc, Tcl_Obj *CONST objv[])
+ {
+@@ -727,8 +853,6 @@
+
+ /* Get the image pointers. */
+- im = *(gdImagePtr *)gdHandleXlate(interp, gdData->handleTbl,
+- Tcl_GetString(objv[2]));
+- tile = *(gdImagePtr *)gdHandleXlate(interp, gdData->handleTbl,
+- Tcl_GetString(objv[3]));
++ im = IMGPTR(objv[2]);
++ tile = IMGPTR(objv[3]);
+
+ /* Do it. */
+@@ -740,5 +864,5 @@
+
+ static int
+-tclGdStyleCmd(Tcl_Interp *interp, GdData *gdData,
++tclGdStyleCmd(Tcl_Interp *interp,
+ int argc, Tcl_Obj *CONST objv[])
+ {
+@@ -749,6 +873,5 @@
+
+ /* Get the image pointer. */
+- im = *(gdImagePtr *)gdHandleXlate(interp, gdData->handleTbl,
+- Tcl_GetString(objv[2]));
++ im = IMGPTR(objv[2]);
+
+ /* Figure out how many colors in the style list and allocate memory. */
+@@ -788,5 +911,5 @@
+
+ static int
+-tclGdSetCmd(Tcl_Interp *interp, GdData *gdData,
++tclGdSetCmd(Tcl_Interp *interp,
+ int argc, Tcl_Obj *CONST objv[])
+ {
+@@ -795,6 +918,5 @@
+
+ /* Get the image pointer. */
+- im = *(gdImagePtr *)gdHandleXlate(interp, gdData->handleTbl,
+- Tcl_GetString(objv[2]));
++ im = IMGPTR(objv[2]);
+
+ /* Get the color, x, y values. */
+@@ -813,5 +935,5 @@
+
+ static int
+-tclGdLineCmd(Tcl_Interp *interp, GdData *gdData,
++tclGdLineCmd(Tcl_Interp *interp,
+ int argc, Tcl_Obj *CONST objv[])
+ {
+@@ -820,6 +942,5 @@
+
+ /* Get the image pointer. */
+- im = *(gdImagePtr *)gdHandleXlate(interp, gdData->handleTbl,
+- Tcl_GetString(objv[2]));
++ im = IMGPTR(objv[2]);
+
+ /* Get the color, x, y values. */
+@@ -842,14 +963,13 @@
+
+ static int
+-tclGdRectCmd(Tcl_Interp *interp, GdData *gdData,
++tclGdRectCmd(Tcl_Interp *interp,
+ int argc, Tcl_Obj *CONST objv[])
+ {
+ gdImagePtr im;
+ int color, x1, y1, x2, y2;
+- char *cmd;
++ const char *cmd;
+
+ /* Get the image pointer. */
+- im = *(gdImagePtr *)gdHandleXlate(interp, gdData->handleTbl,
+- Tcl_GetString(objv[2]));
++ im = IMGPTR(objv[2]);
+
+ /* Get the color, x, y values. */
+@@ -876,14 +996,13 @@
+
+ static int
+-tclGdArcCmd(Tcl_Interp *interp, GdData *gdData,
++tclGdArcCmd(Tcl_Interp *interp,
+ int argc, Tcl_Obj *CONST objv[])
+ {
+ gdImagePtr im;
+ int color, cx, cy, width, height, start, end;
+- char *cmd;
++ const char *cmd;
+
+ /* Get the image pointer. */
+- im = *(gdImagePtr *)gdHandleXlate(interp, gdData->handleTbl,
+- Tcl_GetString(objv[2]));
++ im = IMGPTR(objv[2]);
+
+ /* Get the color, x, y values. */
+@@ -917,5 +1036,5 @@
+
+ static int
+-tclGdPolygonCmd(Tcl_Interp *interp, GdData *gdData,
++tclGdPolygonCmd(Tcl_Interp *interp,
+ int argc, Tcl_Obj *CONST objv[])
+ {
+@@ -925,9 +1044,8 @@
+ gdPointPtr points = NULL;
+ int retval = TCL_OK;
+- char *cmd;
++ const char *cmd;
+
+ /* Get the image pointer. */
+- im = *(gdImagePtr *)gdHandleXlate(interp, gdData->handleTbl,
+- Tcl_GetString(objv[2]));
++ im = IMGPTR(objv[2]);
+
+ /* Get the color, x, y values. */
+@@ -974,5 +1092,5 @@
+ {
+ retval = TCL_ERROR;
+- break;
++ goto out;
+ }
+
+@@ -989,9 +1107,9 @@
+ Tcl_Free((char *)points);
+
+- return TCL_OK;
++ return retval;
+ }
+
+ static int
+-tclGdFillCmd(Tcl_Interp *interp, GdData *gdData,
++tclGdFillCmd(Tcl_Interp *interp,
+ int argc, Tcl_Obj *CONST objv[])
+ {
+@@ -1000,6 +1118,5 @@
+
+ /* Get the image pointer. */
+- im = *(gdImagePtr *)gdHandleXlate(interp, gdData->handleTbl,
+- Tcl_GetString(objv[2]));
++ im = IMGPTR(objv[2]);
+
+ /* Get the color, x, y and possibly bordercolor values. */
+@@ -1024,5 +1141,5 @@
+
+ static int
+-tclGdCopyCmd(Tcl_Interp *interp, GdData *gdData,
++tclGdCopyCmd(Tcl_Interp *interp,
+ int argc, Tcl_Obj *CONST objv[])
+ {
+@@ -1031,8 +1148,6 @@
+
+ /* Get the image pointer. */
+- imdest = *(gdImagePtr *)gdHandleXlate(interp, gdData->handleTbl,
+- Tcl_GetString(objv[2]));
+- imsrc = *(gdImagePtr *)gdHandleXlate(interp, gdData->handleTbl,
+- Tcl_GetString(objv[3]));
++ imdest = IMGPTR(objv[2]);
++ imsrc = IMGPTR(objv[3]);
+
+ /* Get the x, y, etc. values. */
+@@ -1067,5 +1182,5 @@
+
+ static int
+-tclGdGetCmd(Tcl_Interp *interp, GdData *gdData,
++tclGdGetCmd(Tcl_Interp *interp,
+ int argc, Tcl_Obj *CONST objv[])
+ {
+@@ -1074,6 +1189,5 @@
+
+ /* Get the image pointer. */
+- im = *(gdImagePtr *)gdHandleXlate(interp, gdData->handleTbl,
+- Tcl_GetString(objv[2]));
++ im = IMGPTR(objv[2]);
+
+ /* Get the x, y values. */
+@@ -1090,21 +1204,21 @@
+
+ static int
+-tclGdSizeCmd(Tcl_Interp *interp, GdData *gdData,
++tclGdSizeCmd(Tcl_Interp *interp,
+ int argc, Tcl_Obj *CONST objv[])
+ {
+ gdImagePtr im;
+- char buf[30];
++ Tcl_Obj *answers[2];
+
+ /* Get the image pointer. */
+- im = *(gdImagePtr *)gdHandleXlate(interp, gdData->handleTbl,
+- Tcl_GetString(objv[2]));
++ im = IMGPTR(objv[2]);
+
+- sprintf(buf, "%d %d", gdImageSX(im), gdImageSY(im));
+- Tcl_SetResult(interp, buf, TCL_VOLATILE);
++ answers[0] = Tcl_NewIntObj(gdImageSX(im));
++ answers[1] = Tcl_NewIntObj(gdImageSY(im));
++ Tcl_SetObjResult(interp, Tcl_NewListObj(2, answers));
+ return TCL_OK;
+ }
+
+ static int
+-tclGdTextCmd(Tcl_Interp *interp, GdData *gdData,
++tclGdTextCmd(Tcl_Interp *interp,
+ int argc, Tcl_Obj *CONST objv[])
+ {
+@@ -1113,16 +1227,17 @@
+ int color, x, y;
+ double ptsize, angle;
+- char *error, buf[32], *font, *handle;
++ char *error, *font;
+ int i, brect[8], len;
+ unsigned char *str;
++ Tcl_Obj *orect[8];
+
+ /* Get the image pointer. (an invalid or null arg[2] will result in string
+ size calculation but no rendering */
+- handle = Tcl_GetString(objv[2]);
+- if (! handle || *handle == '\0') {
+- im = (gdImagePtr)NULL;
++ if (argc == 2 || (objv[2]->typePtr != &GdPtrType &&
++ GdPtrTypeSet(NULL, objv[2]) != TCL_OK)) {
++ im = NULL;
+ }
+ else {
+- im = *(gdImagePtr *)gdHandleXlate(interp, gdData->handleTbl, handle);
++ im = IMGPTR(objv[2]);
+ }
+
+@@ -1159,8 +1274,8 @@
+ return TCL_ERROR;
+ }
+- for (i=0; i<8; i++) {
+- sprintf(buf, "%d", brect[i]);
+- Tcl_AppendElement(interp, buf);
+- }
++ for (i=0; i<8; i++)
++ orect[i] = Tcl_NewIntObj(brect[i]);
++
++ Tcl_SetObjResult(interp, Tcl_NewListObj(8, orect));
+ return TCL_OK;
+ }
+@@ -1176,6 +1291,4 @@
+ #endif
+ {
+- static GdData gdData;
+-
+ #ifdef USE_TCL_STUBS
+ if (Tcl_InitStubs(interp, TCL_VERSION, 0) == NULL) {
+@@ -1183,5 +1296,5 @@
+ }
+ #else
+- if (Tcl_PkgRequired(interp, "Tcl", TCL_VERSION, 0) == NULL) {
++ if (Tcl_PkgRequire(interp, "Tcl", TCL_VERSION, 0) == NULL) {
+ return TCL_ERROR;
+ }
+@@ -1191,11 +1304,5 @@
+ }
+
+- GDHandleTable = gdData.handleTbl = gdHandleTblInit("gd", sizeof(gdImagePtr), 1);
+- if (gdData.handleTbl == NULL) {
+- Tcl_AppendResult(interp, "unable to create table for GD handles.", 0);
+- return TCL_ERROR;
+- }
+-
+- Tcl_CreateObjCommand(interp, "gd", gdCmd, (ClientData)&gdData, (Tcl_CmdDeleteProc *)NULL);
++ Tcl_CreateObjCommand(interp, "gd", gdCmd, NULL, (Tcl_CmdDeleteProc *)NULL);
+ return TCL_OK;
+ }
+@@ -1207,5 +1314,12 @@
+ #endif
+ {
+- return Gdtclft_Init(interp);
++ Tcl_CmdInfo info;
++ if (Gdtclft_Init(interp) != TCL_OK ||
++ Tcl_GetCommandInfo(interp, "gd", &info) != 1)
++ return TCL_ERROR;
++ info.objClientData = (char *)info.objClientData + 1; /* Non-NULL */
++ if (Tcl_SetCommandInfo(interp, "gd", &info) != 1)
++ return TCL_ERROR;
++ return TCL_OK;
+ }
+
+@@ -1264,9 +1378,8 @@
+
+ static int
+-tclGdWriteBufCmd(Tcl_Interp *interp, GdData *gdData, int argc, Tcl_Obj *CONST objv[])
++tclGdWriteBufCmd(Tcl_Interp *interp, int argc, Tcl_Obj *CONST objv[])
+ {
+ gdImagePtr im;
+ Tcl_Obj *output;
+- char *cmd;
+ char *result = NULL;
+
+@@ -1282,8 +1395,6 @@
+ };
+
+- cmd = Tcl_GetString(objv[1]);
+ /* Get the image pointer. */
+- im = *(gdImagePtr *)gdHandleXlate(interp, gdData->handleTbl,
+- Tcl_GetString(objv[2]));
++ im = IMGPTR(objv[2]);
+
+ gdImagePngToSink(im, &buffsink);
+@@ -1305,2 +1416,26 @@
+ return TCL_OK;
+ }
++
++static void
++GdPtrTypeUpdate(struct Tcl_Obj *O)
++{
++ O->bytes = Tcl_Alloc(strlen(GdPtrType.name) +
++ (sizeof(void *) + 1) * 2 + 1);
++ O->length = sprintf(O->bytes, "%s%p", GdPtrType.name, IMGPTR(O));
++}
++
++static int
++GdPtrTypeSet(Tcl_Interp *I, struct Tcl_Obj *O)
++{
++ if (O->bytes == NULL || O->bytes[0] == '\0' ||
++ strncmp(GdPtrType.name, O->bytes, strlen(GdPtrType.name)) != 0 ||
++ sscanf(O->bytes + strlen(GdPtrType.name), "%p", &IMGPTR(O)) != 1) {
++ if (I != NULL)
++ Tcl_AppendResult(I, O->bytes, " is not a ",
++ GdPtrType.name, "-handle", NULL);
++ return TCL_ERROR;
++ }
++
++ O->typePtr = &GdPtrType;
++ return TCL_OK;
++}
+--- gdtclft.n Fri Aug 4 17:11:41 2000
++++ gdtclft.n Mon Dec 4 03:52:10 2006
+@@ -9,98 +9,89 @@
+
+ TCL GD EXTENSION
+-
++
+ Thomas Boutell's Gd package provides a convenient way to generate
+ PNG images with a C program. If you, like me, prefer Tcl for CGI
+- applications, you'll want my TCL GD extension. You can get it by
+- anonymous FTP from ftp://guraldi.hgp.med.umich.edu/pub/gdtcl.shar.
+-
+- Here's a quick overview of the package.
+- * Overview
+- * Installation
+- * Reference
+- * Examples
+- + gdsample -- sample program written in Tcl.
+- + Gddemo -- demo program written in Tcl.
+- + gdshow -- procedure to display an image.
+-
++ applications, you'll want my TCL GD extension.
++
+ A TCL INTERFACE TO THE GD PACKAGE
+-
++
+ Spencer W. Thomas
+ Human Genome Center
+ University of Michigan
+ Ann Arbor, MI 48109
+-
++
+ spencer.thomas@med.umich.edu
+
+ TrueType font support using the FreeType library was added by
+- John Ellson (ellson@graphviz.org)
++ John Ellson (ellson@graphviz.org).
+
+- Latest sources available from:
++ FreeBSD port maintained by Mikhail Teterin (mi@aldan.algebra.com).
+
+- http://www.graphviz.org/pub/
+-
+-
+ Overview
+
+ This package provides a simple Tcl interface to the gd (PNG drawing)
+- package, version 1.1. It includes an interface to all the gd functions
++ package. It includes an interface to most of the gd functions
+ and data structures from Tcl commands.
+-
+-
+-
+-Installation
+-
+- ./configure
+- make
+- make install
+-
++
++
+ Reference
+
+ One Tcl command, 'gd', is added. All gd package actions are
+ sub-commands (or "options" in Tcl terminology) of this command.
+-
++
+ Each active gd image is referred to with a "handle". The handle is a
+ name of the form gd# (e.g., gd0) returned by the gd create options.
+-
++
+ Almost all the gd commands take a handle as the first argument (after
+ the option). All the drawing commands take a color_idx as the next
+ argument.
+-
++
+- gd create <width> <height>
++ gd create <width> <height> ?true?
+ Return a handle to a new gdImage that is width X height.
++ If "true" is specified, the new image is "TrueColor".
+-
+- gd createFromPNG <filehandle>
+-
+- gd createFromGD <filehandle>
+-
+- gd createFromXBM <filehandle>
++
++ gd createFromGD <file>
++ gd createFromGD2 <file>
++ gd createFromGIF <file>
++ gd createFromJPG <file>
++ gd createFromPNG <file>
++ gd createFromWBMP <file>
++ gd createFromXBM <file>
++ gd createFromXPM <filename>
++
+ Return a handle to a new gdImage created by reading a PNG
+- (resp. GD or XBM) image from the file open on filehandle.
+-
++ (resp. GD or XBM) image from the <file>, which is either
++ a TCl filehandle, or a filename (except for XPM, which only
++ accepts filenames).
++
+ gd destroy <gdhandle>
+ Destroy the gdImage referred to by gdhandle.
+-
+- gd writePNG <gdhandle> <filehandle>
+-
+- gd writeGD <gdhandle> <filehandle>
+- Write the image in gdhandle to filehandle as a PNG (resp. GD)
+- file.
++
++ gd writeGD <gdhandle> <file>
++ gd writeGD2 <gdhandle> <file>
++ gd writeGIF <gdhandle> <file>
++ gd writeJPG <gdhandle> <file> ?quality?
++ gd writePNG <gdhandle> <file>
++ gd writeWBMP <gdhandle> <file> fgpixel
++
++ Write the image in gdhandle to <file> (filehandle or filename)
++ in one of the specified formats.
+
+ gd writePNGvar <gdhandle> <varname>
+ Write the image in gdhandle to Tcl variable "varname" as a binary
+ coded PNG object.
+-
++
+ gd interlace <gdhandle> <on-off>
+ Make the output image interlaced (if on-off is true) or not (if
+ on-off is false).
+-
++
+ gd color new <gdhandle> <red> <green> <blue>
+ Allocate a new color with the given RGB values. Returns the
+ color_idx, or -1 on failure (256 colors already allocated).
+-
++
+ gd color exact <gdhandle> <red> <green> <blue>
+- Find a color_idx in the image that exactly matches the given RGB
++ Find a color_idx in the image that exactly matches the given RGB
+ color. Returns the color_idx, or -1 if no exact match.
+-
++
+ gd color closest <gdhandle> <red> <green> <blue>
+ Find a color in the image that is closest to the given RGB color.
+@@ -114,23 +104,23 @@
+ set idx [gd color closest $gd $r $g $b]
+ }
+- }
+-
++ }
++
+ gd color free <gdhandle> <color_idx>
+ Free the color at the given color_idx for reuse.
+-
++
+ gd color transparent <gdhandle> [<color_idx>]
+ Mark the color at <color_idx> as the transparent background color. Or,
+ return the transparent color_idx if no color_idx specified.
+-
++
+ gd color get <gdhandle> [<color_idx>]
+ Return the RGB value at <color_idx>, or {} if it is not allocated.
+ If <color_idx> is not specified, return a list of {color_idx R G B}
+ values for all allocated colors.
+-
++
+ gd brush <gdhandle> <brushhandle>
+ Set the brush image to be used for brushed lines. Transparent
+ pixels in the brush will not change the image when the brush is
+ applied.
+-
++
+ gd style <gdhandle> <color_idx> ...
+ Set the line style to the list of color indices. This is
+@@ -141,10 +131,10 @@
+ means not to fill the pixel, and a non-zero value means to
+ apply the brush.
+-
++
+ gd tile <gdhandle> <tilehandle>
+ Set the tile image to be used for tiled fills. Transparent
+ pixels in the tile will not change the underlying image during
+ tiling.
+-
++
+ In all drawing functions, the color_idx is a number, or may
+ be one of the strings styled, brushed, tiled, "styled brushed"
+@@ -152,56 +142,55 @@
+ effect will be used. Brushing and styling apply to lines,
+ tiling to filled areas.
+-
++
+ gd set <gdhandle> <color_idx> <x> <y>
+ Set the pixel at (x,y) to color <color_idx>.
+-
++
+ gd line <gdhandle> <color_idx> <x1> <y1> <x2> <y2>
+-
++
+ gd rectangle <gdhandle> <color_idx> <x1> <y1> <x2> <y2>
+-
++
+ gd fillrectangle <gdhandle> <color_idx> <x1> <y1> <x2> <y2>
+ Draw the outline of (resp. fill) a rectangle in color <color_idx>
+ with corners at (x1,y1) and (x2,y2).
+-
++
+ gd arc <gdhandle> <color_idx> <cx> <cy> <width> <height> <start> <end>
+ Draw an arc in color <color_idx>, centered at (cx,cy) in a rectangle width
+ x height, starting at start degrees and ending at end degrees.
+ start must be > end.
+-
++
+ gd polygon <gdhandle> <color_idx> <x1> <y1> ...
+-
++
+ gd fillpolygon <gdhandle> <color_idx> <x1> <y1> ...
+ Draw the outline of, or fill, a polygon specified by the x, y
+ coordinate list. There must be at least 3 points specified.
+-
++
+ gd fill <gdhandle> <color_idx> <x> <y>
+-
++
+ gd fill <gdhandle> <color_idx> <x> <y> <borderindex>
+ Fill with color <color_idx>, starting from (x,y) within a region of
+ pixels all the color of the pixel at (x,y) (resp., within a
+ border colored borderindex).
+-
++
+ gd size <gdhandle>
+ Returns a list {width height} of the image.
+-
+- gd text <gdhandle> <color_idx> <fontpath> <size> <angle> <x> <y> <string>
+- Draw text using the .ttf font in <fontpath> in color <color_idx>,
+- with pointsize <size>, rotation in radians <angle>, with lower left
++
++ gd text <gdhandle> <color_idx> <fontpath> <size> <angle> <x> <y> <string>
++ Draw text using the .ttf font in <fontpath> in color <color_idx>,
++ with pointsize <size>, rotation in radians <angle>, with lower left
+ corner at (x,y). String may contain UTF8 sequences like: "&#192;"
+ Returns 4 corner coords of bounding rectangle.
+ Use gdhandle = {} to get boundary without rendering.
+ Use negative of color_idx to disable antialiasing.
+-
++
+ gd copy <desthandle> <srchandle> <destx> <desty> <srcx> <srcy> <w> <h>
+-
+- gd copy <desthandle> <srchandle> <destx> <desty> <srcx> <srcy> \
+- <destw> <desth> <srcw> <srch> Copy a subimage from
+- srchandle(srcx, srcy) to desthandle(destx, desty), size w x h.
++
++ gd copy <desthandle> <srchandle> <destx> <desty> <srcx> <srcy> \\
++ <destw> <desth> <srcw> <srch>
++ Copy a subimage from srchandle(srcx, srcy) to desthandle(destx,
++ desty), size w x h.
+ Or, resize the subimage in copying from srcw x srch to destw x
+ desth.
+-
+-
+-
+-Examples
++
++.SH EXAMPLES
+
+ The sample program from the gd documentation can be written thusly:
+@@ -234,8 +223,8 @@
+ gd destroy $im
+
+-
+-
++
++
+ GDDEMO
+-
++
+ Here's the gddemo.c program translated to tcl.
+
+@@ -312,8 +301,8 @@
+ gd destroy $im_out
+
+-
+-
++
++
+ GDSHOW
+-
++
+ A quick Tcl procedure to display a GD image using the xv program.
+
+@@ -331,2 +320,6 @@
+ }
+ }
++
++.SH SEE ALSO
++ You will find Thomas Boutell's documentation for the underlying GD
++ library quite useful, especially, if you are dealing with WBMP format.
+--- gdhandle.c 2000-02-11 00:24:31.000000000 -0500
++++ gdhandle.c 2014-04-29 13:25:00.000000000 -0400
+@@ -45,5 +45,5 @@
+ * It is set on the first table initialization.
+ */
+-static int entryAlignment = 0;
++static size_t entryAlignment = 0;
+
+ /*
diff --git a/graphics/gdtclft/pkg-descr b/graphics/gdtclft/pkg-descr
new file mode 100644
index 000000000000..ea18fed48fdf
--- /dev/null
+++ b/graphics/gdtclft/pkg-descr
@@ -0,0 +1,10 @@
+Spencer Thomas said about the original TCL GD:
+
+ Thomas Boutell's Gd package provides a convenient way to
+ generate PNG images with a C program. If you, like me, prefer
+ Tcl for CGI applications, you'll want my TCL GD extension.
+
+The software is now maintained by John Ellson <ellson@lucent.com>, it
+seems.
+
+WWW: http://graphviz.org/cgi-bin/man?gdtclft