1363 lines
39 KiB
Plaintext
1363 lines
39 KiB
Plaintext
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: "À"
|
|
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;
|
|
|
|
/*
|