#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <tcl.h>
#include <unistd.h>
#include "gd.h"
#include "tclhandle.h"
#ifdef WIN32
#include <windows.h>
#endif
void *GDHandleTable;
typedef struct {
tblHeader_pt handleTbl;
} GdData;
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 struct {
char *cmd;
int (*f)();
int minargs, maxargs;
int subcmds;
int ishandle;
char *usage;
} cmdOptions;
typedef struct {
char *buf;
int buflen;
} BuffSinkContext;
static cmdOptions subcmdVec[] = {
{"create", tclGdCreateCmd, 2, 2, 0, 0,
"width height"},
{"createFromGD", tclGdCreateCmd, 1, 1, 0, 0,
"filehandle"},
#ifdef HAVE_LIBZ
{"createFromGD2", tclGdCreateCmd, 1, 1, 0, 0,
"filehandle"},
#endif
#ifdef WITH_GIF
{"createFromGIF", tclGdCreateCmd, 1, 1, 0, 0,
"filehandle"},
#endif
#ifdef HAVE_LIBJPEG
{"createFromJPEG", tclGdCreateCmd, 1, 1, 0, 0,
"filehandle"},
#endif
#ifdef HAVE_LIBPNG
#ifdef HAVE_LIBZ
{"createFromPNG", tclGdCreateCmd, 1, 1, 0, 0,
"filehandle"},
#endif
#endif
{"createFromWBMP", tclGdCreateCmd, 1, 1, 0, 0,
"filehandle"},
#ifdef HAVE_LIBXPM
{"createFromXBM", tclGdCreateCmd, 1, 1, 0, 0,
"filehandle"},
#endif
{"destroy", tclGdDestroyCmd, 1, 1, 0, 1,
"gdhandle"},
{"writeGD", tclGdWriteCmd, 2, 2, 0, 1,
"gdhandle filehandle"},
#ifdef HAVE_LIBZ
{"writeGD2", tclGdWriteCmd, 2, 2, 0, 1,
"gdhandle filehandle"},
#endif
#ifdef WITH_GIF
{"writeGIF", tclGdWriteCmd, 2, 2, 0, 1,
"gdhandle filehandle"},
#endif
#ifdef HAVE_LIBJPEG
{"writeJPEG", tclGdWriteCmd, 2, 2, 0, 1,
"gdhandle filehandle"},
#endif
#ifdef HAVE_LIBPNG
#ifdef HAVE_LIBZ
{"writePNG", tclGdWriteCmd, 2, 2, 0, 1,
"gdhandle filehandle"},
#endif
#endif
{"writeWBMP", tclGdWriteCmd, 2, 2, 0, 1,
"gdhandle filehandle"},
#if 0
#ifdef HAVE_LIBXPM
{"writeXBM", tclGdWriteCmd, 2, 2, 0, 1,
"gdhandle filehandle"},
#endif
#endif
#ifdef HAVE_LIBPNG
#ifdef HAVE_LIBZ
{"writePNGvar", tclGdWriteBufCmd, 2, 2, 0, 1,
"gdhandle var"},
#endif
#endif
{"interlace", tclGdInterlaceCmd, 1, 2, 0, 1,
"gdhandle ?on-off?"},
{"color", tclGdColorCmd, 2, 5, 1, 1,
"option values..."},
{"brush", tclGdBrushCmd, 2, 2, 0, 2,
"gdhandle brushhandle"},
{"style", tclGdStyleCmd, 2, 999, 0, 1,
"gdhandle color..."},
{"tile", tclGdTileCmd, 2, 2, 0, 2,
"gdhandle tilehandle"},
{"set", tclGdSetCmd, 4, 4, 0, 1,
"gdhandle color x y"},
{"line", tclGdLineCmd, 6, 6, 0, 1,
"gdhandle color x1 y1 x2 y2"},
{"rectangle", tclGdRectCmd, 6, 6, 0, 1,
"gdhandle color x1 y1 x2 y2"},
{"fillrectangle", tclGdRectCmd, 6, 6, 0, 1,
"gdhandle color x1 y1 x2 y2"},
{"arc", tclGdArcCmd, 8, 8, 0, 1,
"gdhandle color cx cy width height start end"},
{"fillarc", tclGdArcCmd, 8, 8, 0, 1,
"gdhandle color cx cy width height start end"},
{"polygon", tclGdPolygonCmd, 2, 999, 0, 1,
"gdhandle color x1 y1 x2 y2 x3 y3 ..."},
{"fillpolygon", tclGdPolygonCmd, 3, 999, 0, 1,
"gdhandle color x1 y1 x2 y2 x3 y3 ..."},
{"fill", tclGdFillCmd, 4, 5, 0, 1,
"gdhandle color x y ?bordercolor?"},
{"text", tclGdTextCmd, 8, 8, 0, 0,
"gdhandle color fontpathname size angle x y string"},
{"copy", tclGdCopyCmd, 8, 10, 0, 2,
"desthandle srchandle destx desty srcx srcy destw desth ?srcw srch?"},
{"get", tclGdGetCmd, 3, 3, 0, 1,
"gdhandle x y"},
{"size", tclGdSizeCmd, 1, 1, 0, 1,
"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 int
tclGd_GetColor(Tcl_Interp *interp, Tcl_Obj *obj, int *color)
{
int nlist, retval = TCL_OK;
Tcl_Obj **theList;
char *firsttag, *secondtag;
if (Tcl_GetIntFromObj(interp, obj, color) == TCL_OK)
return TCL_OK;
else
{
Tcl_ResetResult(interp);
if (Tcl_ListObjGetElements(interp, obj, &nlist, &theList) != TCL_OK)
return TCL_ERROR;
if (nlist < 1 || nlist > 2)
retval = TCL_ERROR;
else
{
firsttag = Tcl_GetString(theList[0]);
switch (firsttag[0]) {
case 'b':
*color = gdBrushed;
if (nlist == 2) {
secondtag = Tcl_GetString(theList[1]);
if (secondtag[0] == 's') {
*color = gdStyledBrushed;
} else {
retval = TCL_ERROR;
}
}
break;
case 's':
*color = gdStyled;
if (nlist == 2) {
secondtag = Tcl_GetString(theList[1]);
if (secondtag[0] == 'b') {
*color = gdStyledBrushed;
} else {
retval = TCL_ERROR;
}
}
break;
case 't':
*color = gdTiled;
break;
default:
retval = TCL_ERROR;
}
}
}
if (retval == TCL_ERROR)
Tcl_SetResult(interp, "Malformed special color value", TCL_STATIC);
return retval;
}
int
gdCmd(ClientData clientData, Tcl_Interp *interp,
int argc, Tcl_Obj *CONST objv[])
{
GdData *gdData = (GdData *)clientData;
int argi, subi;
char buf[100];
if (argc < 2) {
Tcl_SetResult(interp,
"wrong # args: should be \"gd option ...\"", TCL_STATIC);
return TCL_ERROR;
}
for (subi = 0; subi < (sizeof subcmdVec) / (sizeof subcmdVec[0]); subi++) {
if (strcmp(subcmdVec[subi].cmd, Tcl_GetString(objv[1])) == 0) {
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);
return TCL_ERROR;
}
if (subcmdVec[subi].ishandle > 0) {
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;
}
if (2+subcmdVec[subi].subcmds+subcmdVec[subi].ishandle > argc) {
Tcl_SetResult(interp, "GD handle(s) not specified", TCL_STATIC);
return TCL_ERROR;
}
for (argi = 2 + subcmdVec[subi].subcmds;
argi < (2 + subcmdVec[subi].subcmds +
subcmdVec[subi].ishandle);
argi++) {
if (! tclhandleXlate(gdData->handleTbl,
Tcl_GetString(objv[argi])))
return TCL_ERROR;
}
}
return (*subcmdVec[subi].f)(interp, gdData, argc, objv);
}
}
Tcl_AppendResult(interp, "bad option \"",
Tcl_GetString(objv[1]), "\": should be ", 0);
for (subi = 0; subi < (sizeof subcmdVec) / (sizeof subcmdVec[0]); subi++)
Tcl_AppendResult(interp, (subi > 0 ? ", " : ""),
subcmdVec[subi].cmd, 0);
return TCL_ERROR;
}
static int
tclGdCreateCmd(Tcl_Interp *interp, GdData *gdData,
int argc, Tcl_Obj *CONST objv[])
{
int w, h;
unsigned long idx;
gdImagePtr im=NULL;
FILE *filePtr;
ClientData clientdata;
char *cmd, buf[50];
int fileByName;
cmd = Tcl_GetString(objv[1]);
if (strcmp(cmd, "create") == 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;
im = gdImageCreate(w, h);
if (im == NULL)
{
sprintf(buf, "GD unable to allocate %d X %d image", w, h);
Tcl_SetResult(interp, buf, TCL_VOLATILE);
return TCL_ERROR;
}
} else {
fileByName = 0;
if (Tcl_GetOpenFile(interp, Tcl_GetString(objv[2]), 0, 1, &clientdata) == TCL_OK) {
filePtr = (FILE *)clientdata;
} else {
fileByName++;
if ((filePtr = fopen(Tcl_GetString(objv[2]),"rb")) == NULL) {
return TCL_ERROR;
}
Tcl_ResetResult(interp);
}
if (strcmp(&cmd[10], "GD") == 0) {
im = gdImageCreateFromGd(filePtr);
#ifdef HAVE_LIBZ
} else if (strcmp(&cmd[10], "GD2") == 0) {
im = gdImageCreateFromGd2(filePtr);
#endif
#ifdef WITH_GIF
} else if (strcmp(&cmd[10], "GIF") == 0) {
im = gdImageCreateFromGif(filePtr);
#endif
#ifdef HAVE_LIBJPEG
} else if (strcmp(&cmd[10], "JPEG") == 0) {
im = gdImageCreateFromJpeg(filePtr);
#endif
#ifdef HAVE_LIBPNG
#ifdef HAVE_LIBZ
} else if (strcmp(&cmd[10], "PNG") == 0) {
im = gdImageCreateFromPng(filePtr);
#endif
#endif
} else if (strcmp(&cmd[10], "WBMP") == 0) {
im = gdImageCreateFromWBMP(filePtr);
#ifdef HAVE_LIBXPM
} else if (strcmp(&cmd[10], "XBM") == 0) {
im = gdImageCreateFromXbm(filePtr);
#endif
} else {
}
if (fileByName) {
fclose(filePtr);
}
if (im == NULL) {
Tcl_SetResult(interp,"GD unable to read image file", TCL_STATIC);
return TCL_ERROR;
}
}
*(gdImagePtr *)(tclhandleAlloc(gdData->handleTbl, buf, &idx)) = im;
Tcl_SetResult(interp, buf, TCL_VOLATILE);
return TCL_OK;
}
static int
tclGdDestroyCmd(Tcl_Interp *interp, GdData *gdData, int argc, Tcl_Obj *CONST objv[])
{
gdImagePtr im;
void *hdl;
hdl = (void *)tclhandleXlate(gdData->handleTbl,
Tcl_GetString(objv[2]));
im = *(gdImagePtr *)hdl;
tclhandleFree(gdData->handleTbl, hdl);
gdImageDestroy(im);
return TCL_OK;
}
static int
tclGdWriteCmd(Tcl_Interp *interp, GdData *gdData, int argc, Tcl_Obj *CONST objv[])
{
gdImagePtr im;
FILE *filePtr;
ClientData clientdata;
char *cmd;
int fileByName;
cmd = Tcl_GetString(objv[1]);
im = *(gdImagePtr *)tclhandleXlate(gdData->handleTbl,
Tcl_GetString(objv[2]));
fileByName = 0;
if (Tcl_GetOpenFile(interp, Tcl_GetString(objv[3]), 1, 1, &clientdata) == TCL_OK) {
filePtr = (FILE *)clientdata;
} else {
fileByName++;
if ((filePtr = fopen(Tcl_GetString(objv[3]),"wb")) == NULL) {
return TCL_ERROR;
}
Tcl_ResetResult(interp);
}
if (strcmp(&cmd[5], "GD") == 0) {
gdImageGd(im, filePtr);
} else if (strcmp(&cmd[5], "GD2") == 0) {
#ifdef HAVE_LIBZ
#define GD2_CHUNKSIZE 128
#define GD2_COMPRESSED 2
gdImageGd2(im, filePtr, GD2_CHUNKSIZE, GD2_COMPRESSED);
#endif
#ifdef WITH_GIF
} else if (strcmp(&cmd[5], "GIF") == 0) {
gdImageGif(im, filePtr);
#endif
#ifdef HAVE_LIBJPEG
} else if (strcmp(&cmd[5], "JPEG") == 0) {
#define JPEG_QUALITY -1
gdImageJpeg(im, filePtr, JPEG_QUALITY);
#endif
#ifdef HAVE_LIBPNG
#ifdef HAVE_LIBZ
} else if (strcmp(&cmd[5], "PNG") == 0) {
gdImagePng(im, filePtr);
#endif
#endif
} else if (strcmp(&cmd[5], "WBMP") == 0) {
int foreground = gdImageColorClosest(im, 0, 0, 0);
gdImageWBMP(im, foreground, filePtr);
#if 0
#ifdef HAVE_LIBXPM
} else if (strcmp(&cmd[5], "XBM") == 0) {
gdImageXbm(im, filePtr);
#endif
#endif
} else {
}
if (fileByName) {
fclose(filePtr);
} else {
fflush(filePtr);
}
return TCL_OK;
}
static int
tclGdInterlaceCmd(Tcl_Interp *interp, GdData *gdData,
int argc, Tcl_Obj *CONST objv[])
{
gdImagePtr im;
int on_off;
im = *(gdImagePtr *)tclhandleXlate(gdData->handleTbl,
Tcl_GetString(objv[2]));
if (argc == 4) {
if (Tcl_GetBooleanFromObj(interp, objv[3], &on_off) != TCL_OK)
return TCL_ERROR;
gdImageInterlace(im, on_off);
} else {
on_off = gdImageGetInterlaced(im);
}
Tcl_SetObjResult(interp, Tcl_NewBooleanObj(on_off));
return TCL_OK;
}
static int
tclGdColorCmd(Tcl_Interp *interp, GdData *gdData,
int argc, Tcl_Obj *CONST objv[])
{
gdImagePtr im;
int subi, nsub, i, args[3];
nsub = (sizeof colorCmdVec) / (sizeof colorCmdVec[0]);
if (argc >= 3) {
for (subi = 0; subi < nsub; subi++)
{
if (strcmp(colorCmdVec[subi].cmd, Tcl_GetString(objv[2])) == 0)
{
if (argc - 2 < colorCmdVec[subi].minargs ||
argc - 2 > colorCmdVec[subi].maxargs)
{
Tcl_AppendResult(interp,
"wrong # args: should be \"gd color ",
colorCmdVec[subi].cmd, " ",
colorCmdVec[subi].usage, "\"", 0);
return TCL_ERROR;
}
im = *(gdImagePtr *)tclhandleXlate(gdData->handleTbl,
Tcl_GetString(objv[3]));
for (i = 0; i < argc - 4; i++) {
if (Tcl_GetIntFromObj(interp, objv[i+4], &args[i]) != TCL_OK) {
#if 0
if (args[i] < 0 || args[i] > 255) {
#else
if (args[i] < -255 || args[i] > 255) {
#endif
Tcl_SetResult(interp, "argument out of range 0-255", TCL_STATIC);
return TCL_ERROR;
}
}
}
return (*colorCmdVec[subi].f)(interp, im, argc - 4, args);
}
}
}
if (argc > 2) {
Tcl_AppendResult(interp, "bad option \"",
Tcl_GetString(objv[2]), "\": ", 0);
} else {
Tcl_AppendResult(interp, "wrong # args: ", 0);
}
Tcl_AppendResult(interp, "should be ", 0);
for (subi = 0; subi < nsub; subi++)
Tcl_AppendResult(interp, (subi > 0 ? ", " : ""),
colorCmdVec[subi].cmd, 0);
return TCL_ERROR;
}
static int
tclGdColorNewCmd(Tcl_Interp *interp, gdImagePtr im, int argc, int args[])
{
int color;
color = gdImageColorAllocate(im, args[0], args[1], args[2]);
Tcl_SetObjResult(interp, Tcl_NewIntObj(color));
return TCL_OK;
}
static int
tclGdColorExactCmd(Tcl_Interp *interp, gdImagePtr im, int argc, int args[])
{
int color;
color = gdImageColorExact(im, args[0], args[1], args[2]);
Tcl_SetObjResult(interp, Tcl_NewIntObj(color));
return TCL_OK;
}
static int
tclGdColorClosestCmd(Tcl_Interp *interp, gdImagePtr im, int argc, int args[])
{
int color;
color = gdImageColorClosest(im, args[0], args[1], args[2]);
Tcl_SetObjResult(interp, Tcl_NewIntObj(color));
return TCL_OK;
}
static int
tclGdColorResolveCmd(Tcl_Interp *interp, gdImagePtr im, int argc, int args[])
{
int color;
color = gdImageColorResolve(im, args[0], args[1], args[2]);
Tcl_SetObjResult(interp, Tcl_NewIntObj(color));
return TCL_OK;
}
static int
tclGdColorFreeCmd(Tcl_Interp *interp, gdImagePtr im, int argc, int args[])
{
gdImageColorDeallocate(im, args[0]);
return TCL_OK;
}
static int
tclGdColorTranspCmd(Tcl_Interp *interp, gdImagePtr im, int argc, int args[])
{
int color;
if (argc > 0) {
color = args[0];
gdImageColorTransparent(im, color);
}
else {
color = gdImageGetTransparent(im);
}
Tcl_SetObjResult(interp, Tcl_NewIntObj(color));
return TCL_OK;
}
static int
tclGdColorGetCmd(Tcl_Interp *interp, gdImagePtr im, int argc, int args[])
{
char buf[30];
int i;
if (argc == 1)
{
i = args[0];
if (i >= gdImageColorsTotal(im) || 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);
} else {
for (i = 0; i < gdImageColorsTotal(im); 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);
}
}
return TCL_OK;
}
static int
tclGdBrushCmd(Tcl_Interp *interp, GdData *gdData,
int argc, Tcl_Obj *CONST objv[])
{
gdImagePtr im, imbrush;
im = *(gdImagePtr *)tclhandleXlate(gdData->handleTbl,
Tcl_GetString(objv[2]));
imbrush = *(gdImagePtr *)tclhandleXlate(gdData->handleTbl,
Tcl_GetString(objv[3]));
gdImageSetBrush(im, imbrush);
return TCL_OK;
}
static int
tclGdTileCmd(Tcl_Interp *interp, GdData *gdData,
int argc, Tcl_Obj *CONST objv[])
{
gdImagePtr im, tile;
im = *(gdImagePtr *)tclhandleXlate(gdData->handleTbl,
Tcl_GetString(objv[2]));
tile = *(gdImagePtr *)tclhandleXlate(gdData->handleTbl,
Tcl_GetString(objv[3]));
gdImageSetTile(im, tile);
return TCL_OK;
}
static int
tclGdStyleCmd(Tcl_Interp *interp, GdData *gdData,
int argc, Tcl_Obj *CONST objv[])
{
gdImagePtr im;
int ncolor, *colors = NULL, i;
Tcl_Obj **colorObjv = (Tcl_Obj **)(&objv[3]);
int retval = TCL_OK;
im = *(gdImagePtr *)tclhandleXlate(gdData->handleTbl,
Tcl_GetString(objv[2]));
ncolor = argc - 3;
if (ncolor == 1)
if (Tcl_ListObjGetElements(interp, objv[3],
&ncolor, &colorObjv) != TCL_OK)
return TCL_ERROR;
colors = (int *)Tcl_Alloc(ncolor * sizeof(int));
if (colors == NULL)
{
Tcl_SetResult(interp, "Memory allocation failed", TCL_STATIC);
retval = TCL_ERROR;
goto out;
}
for (i = 0; i < ncolor; i++)
if (Tcl_GetIntFromObj(interp, colorObjv[i], &colors[i]) != TCL_OK)
{
retval = TCL_ERROR;
break;
}
if (retval == TCL_OK)
gdImageSetStyle(im, colors, ncolor);
out:
if (colors != NULL)
Tcl_Free((char *)colors);
return retval;
}
static int
tclGdSetCmd(Tcl_Interp *interp, GdData *gdData,
int argc, Tcl_Obj *CONST objv[])
{
gdImagePtr im;
int color, x, y;
im = *(gdImagePtr *)tclhandleXlate(gdData->handleTbl,
Tcl_GetString(objv[2]));
if (tclGd_GetColor(interp, objv[3], &color) != TCL_OK)
return TCL_ERROR;
if (Tcl_GetIntFromObj(interp, objv[4], &x) != TCL_OK)
return TCL_ERROR;
if (Tcl_GetIntFromObj(interp, objv[5], &y) != TCL_OK)
return TCL_ERROR;
gdImageSetPixel(im, x, y, color);
return TCL_OK;
}
static int
tclGdLineCmd(Tcl_Interp *interp, GdData *gdData,
int argc, Tcl_Obj *CONST objv[])
{
gdImagePtr im;
int color, x1, y1, x2, y2;
im = *(gdImagePtr *)tclhandleXlate(gdData->handleTbl,
Tcl_GetString(objv[2]));
if (tclGd_GetColor(interp, objv[3], &color) != TCL_OK)
return TCL_ERROR;
if (Tcl_GetIntFromObj(interp, objv[4], &x1) != TCL_OK)
return TCL_ERROR;
if (Tcl_GetIntFromObj(interp, objv[5], &y1) != TCL_OK)
return TCL_ERROR;
if (Tcl_GetIntFromObj(interp, objv[6], &x2) != TCL_OK)
return TCL_ERROR;
if (Tcl_GetIntFromObj(interp, objv[7], &y2) != TCL_OK)
return TCL_ERROR;
gdImageLine(im, x1, y1, x2, y2, color);
return TCL_OK;
}
static int
tclGdRectCmd(Tcl_Interp *interp, GdData *gdData,
int argc, Tcl_Obj *CONST objv[])
{
gdImagePtr im;
int color, x1, y1, x2, y2;
char *cmd;
im = *(gdImagePtr *)tclhandleXlate(gdData->handleTbl,
Tcl_GetString(objv[2]));
if (tclGd_GetColor(interp, objv[3], &color) != TCL_OK)
return TCL_ERROR;
if (Tcl_GetIntFromObj(interp, objv[4], &x1) != TCL_OK)
return TCL_ERROR;
if (Tcl_GetIntFromObj(interp, objv[5], &y1) != TCL_OK)
return TCL_ERROR;
if (Tcl_GetIntFromObj(interp, objv[6], &x2) != TCL_OK)
return TCL_ERROR;
if (Tcl_GetIntFromObj(interp, objv[7], &y2) != TCL_OK)
return TCL_ERROR;
cmd = Tcl_GetString(objv[1]);
if (cmd[0] == 'r')
gdImageRectangle(im, x1, y1, x2, y2, color);
else
gdImageFilledRectangle(im, x1, y1, x2, y2, color);
return TCL_OK;
}
static int
tclGdArcCmd(Tcl_Interp *interp, GdData *gdData,
int argc, Tcl_Obj *CONST objv[])
{
gdImagePtr im;
int color, cx, cy, width, height, start, end;
char *cmd;
im = *(gdImagePtr *)tclhandleXlate(gdData->handleTbl,
Tcl_GetString(objv[2]));
if (tclGd_GetColor(interp, objv[3], &color) != TCL_OK)
return TCL_ERROR;
if (Tcl_GetIntFromObj(interp, objv[4], &cx) != TCL_OK)
return TCL_ERROR;
if (Tcl_GetIntFromObj(interp, objv[5], &cy) != TCL_OK)
return TCL_ERROR;
if (Tcl_GetIntFromObj(interp, objv[6], &width) != TCL_OK)
return TCL_ERROR;
if (Tcl_GetIntFromObj(interp, objv[7], &height) != TCL_OK)
return TCL_ERROR;
if (Tcl_GetIntFromObj(interp, objv[8], &start) != TCL_OK)
return TCL_ERROR;
if (Tcl_GetIntFromObj(interp, objv[9], &end) != TCL_OK)
return TCL_ERROR;
cmd = Tcl_GetString(objv[1]);
if (cmd[0] == 'a')
gdImageArc(im, cx, cy, width, height, start, end, color);
else {
Tcl_SetResult(interp, "gdImageFilledArc not supported in gd1.2", TCL_STATIC);
return TCL_ERROR;
}
return TCL_OK;
}
static int
tclGdPolygonCmd(Tcl_Interp *interp, GdData *gdData,
int argc, Tcl_Obj *CONST objv[])
{
gdImagePtr im;
int color, npoints, i;
Tcl_Obj **pointObjv = (Tcl_Obj **)(&objv[4]);
gdPointPtr points = NULL;
int retval = TCL_OK;
char *cmd;
im = *(gdImagePtr *)tclhandleXlate(gdData->handleTbl,
Tcl_GetString(objv[2]));
if (tclGd_GetColor(interp, objv[3], &color) != TCL_OK)
return TCL_ERROR;
npoints = argc - 4;
if (npoints == 1)
if (Tcl_ListObjGetElements(interp, objv[4],
&npoints, &pointObjv) != TCL_OK)
return TCL_ERROR;
if (npoints % 2 != 0)
{
Tcl_SetResult(interp, "Number of coordinates must be even", TCL_STATIC);
retval = TCL_ERROR;
goto out;
}
npoints /= 2;
if (npoints < 3)
{
Tcl_SetResult(interp, "Must specify at least 3 points.", TCL_STATIC);
retval = TCL_ERROR;
goto out;
}
points = (gdPointPtr)Tcl_Alloc(npoints * sizeof(gdPoint));
if (points == NULL)
{
Tcl_SetResult(interp, "Memory allocation failed", TCL_STATIC);
retval = TCL_ERROR;
goto out;
}
for (i = 0; i < npoints; i++)
if (Tcl_GetIntFromObj(interp, pointObjv[i*2], &points[i].x) != TCL_OK ||
Tcl_GetIntFromObj(interp, pointObjv[i*2+1], &points[i].y) != TCL_OK)
{
retval = TCL_ERROR;
break;
}
cmd = Tcl_GetString(objv[1]);
if (cmd[0] == 'p')
gdImagePolygon(im, points, npoints, color);
else
gdImageFilledPolygon(im, points, npoints, color);
out:
if (points != NULL)
Tcl_Free((char *)points);
return retval;
}
static int
tclGdFillCmd(Tcl_Interp *interp, GdData *gdData,
int argc, Tcl_Obj *CONST objv[])
{
gdImagePtr im;
int color, x, y, border;
im = *(gdImagePtr *)tclhandleXlate(gdData->handleTbl,
Tcl_GetString(objv[2]));
if (tclGd_GetColor(interp, objv[3], &color) != TCL_OK)
return TCL_ERROR;
if (Tcl_GetIntFromObj(interp, objv[4], &x) != TCL_OK)
return TCL_ERROR;
if (Tcl_GetIntFromObj(interp, objv[5], &y) != TCL_OK)
return TCL_ERROR;
if (argc - 2 == 5) {
if (Tcl_GetIntFromObj(interp, objv[6], &border) != TCL_OK)
return TCL_ERROR;
gdImageFillToBorder(im, x, y, border, color);
} else {
gdImageFill(im, x, y, color);
}
return TCL_OK;
}
static int
tclGdCopyCmd(Tcl_Interp *interp, GdData *gdData,
int argc, Tcl_Obj *CONST objv[])
{
gdImagePtr imdest, imsrc;
int destx, desty, srcx, srcy, destw, desth, srcw, srch;
imdest = *(gdImagePtr *)tclhandleXlate(gdData->handleTbl,
Tcl_GetString(objv[2]));
imsrc = *(gdImagePtr *)tclhandleXlate(gdData->handleTbl,
Tcl_GetString(objv[3]));
if (Tcl_GetIntFromObj(interp, objv[4], &destx) != TCL_OK)
return TCL_ERROR;
if (Tcl_GetIntFromObj(interp, objv[5], &desty) != TCL_OK)
return TCL_ERROR;
if (Tcl_GetIntFromObj(interp, objv[6], &srcx) != TCL_OK)
return TCL_ERROR;
if (Tcl_GetIntFromObj(interp, objv[7], &srcy) != TCL_OK)
return TCL_ERROR;
if (Tcl_GetIntFromObj(interp, objv[8], &destw) != TCL_OK)
return TCL_ERROR;
if (Tcl_GetIntFromObj(interp, objv[9], &desth) != TCL_OK)
return TCL_ERROR;
if (argc - 2 == 10) {
if (Tcl_GetIntFromObj(interp, objv[10], &srcw) != TCL_OK)
return TCL_ERROR;
if (Tcl_GetIntFromObj(interp, objv[11], &srch) != TCL_OK)
return TCL_ERROR;
gdImageCopyResized(imdest, imsrc, destx, desty, srcx, srcy,
destw, desth, srcw, srch);
}
else
gdImageCopy(imdest, imsrc, destx, desty, srcx, srcy, destw, desth);
return TCL_OK;
}
static int
tclGdGetCmd(Tcl_Interp *interp, GdData *gdData,
int argc, Tcl_Obj *CONST objv[])
{
gdImagePtr im;
int color, x, y;
im = *(gdImagePtr *)tclhandleXlate(gdData->handleTbl,
Tcl_GetString(objv[2]));
if (Tcl_GetIntFromObj(interp, objv[3], &x) != TCL_OK)
return TCL_ERROR;
if (Tcl_GetIntFromObj(interp, objv[4], &y) != TCL_OK)
return TCL_ERROR;
color = gdImageGetPixel(im, x, y);
Tcl_SetObjResult(interp, Tcl_NewIntObj(color));
return TCL_OK;
}
static int
tclGdSizeCmd(Tcl_Interp *interp, GdData *gdData,
int argc, Tcl_Obj *CONST objv[])
{
gdImagePtr im;
char buf[30];
im = *(gdImagePtr *)tclhandleXlate(gdData->handleTbl,
Tcl_GetString(objv[2]));
sprintf(buf, "%d %d", gdImageSX(im), gdImageSY(im));
Tcl_SetResult(interp, buf, TCL_VOLATILE);
return TCL_OK;
}
static int
tclGdTextCmd(Tcl_Interp *interp, GdData *gdData,
int argc, Tcl_Obj *CONST objv[])
{
gdImagePtr im;
int color, x, y;
double ptsize, angle;
char *error, buf[32], *font, *handle;
int i, brect[8], len;
char *str;
handle = Tcl_GetString(objv[2]);
if (! handle || *handle == '\0') {
im = (gdImagePtr)NULL;
}
else {
im = *(gdImagePtr *)tclhandleXlate(gdData->handleTbl, handle);
}
if (tclGd_GetColor(interp, objv[3], &color) != TCL_OK) {
return TCL_ERROR;
}
if (Tcl_GetDoubleFromObj(interp, objv[5], &ptsize) != TCL_OK) {
return TCL_ERROR;
}
if (Tcl_GetDoubleFromObj(interp, objv[6], &angle) != TCL_OK) {
return TCL_ERROR;
}
if (Tcl_GetIntFromObj(interp, objv[7], &x) != TCL_OK) {
return TCL_ERROR;
}
if (Tcl_GetIntFromObj(interp, objv[8], &y) != TCL_OK) {
return TCL_ERROR;
}
str = Tcl_GetStringFromObj(objv[9], &len);
font = Tcl_GetString(objv[4]);
error = gdImageStringFT(im,brect,color,font,ptsize,angle,x,y,str);
if (error) {
Tcl_SetResult(interp, error, TCL_VOLATILE);
return TCL_ERROR;
}
for (i=0; i<8; i++) {
sprintf(buf, "%d", brect[i]);
Tcl_AppendElement(interp, buf);
}
return TCL_OK;
}
#ifdef __CYGWIN__
int Gdtclft_Init(Tcl_Interp *interp)
#else
#ifdef __WIN32__
EXPORT(int,Gdtclft_Init)(interp)
#else
int Gdtclft_Init(Tcl_Interp *interp)
#endif
#endif
{
static GdData gdData;
#ifdef USE_TCL_STUBS
if (Tcl_InitStubs(interp, TCL_VERSION, 0) == NULL) {
return TCL_ERROR;
}
#else
if (Tcl_PkgRequire(interp, "Tcl", TCL_VERSION, 0) == NULL) {
return TCL_ERROR;
}
#endif
if (Tcl_PkgProvide(interp, "Gdtclft", VERSION) != TCL_OK) {
return TCL_ERROR;
}
GDHandleTable = gdData.handleTbl = tclhandleInit("gd", sizeof(gdImagePtr), 2);
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);
return TCL_OK;
}
#ifdef __CYGWIN__
int Gdtclft_SafeInit(Tcl_Interp *interp)
#else
#ifdef __WIN32__
EXPORT(int,Gdtclft_SafeInit)(interp)
#else
int Gdtclft_SafeInit(Tcl_Interp *interp)
#endif
#endif
{
return Gdtclft_Init(interp);
}
#ifndef __CYGWIN__
#ifdef __WIN32__
BOOL APIENTRY
DllEntryPoint(hInst, reason, reserved)
HINSTANCE hInst;
DWORD reason;
LPVOID reserved;
{
return TRUE;
}
#endif
#endif
static int
BufferSinkFunc(void *context, const char *buffer, int len)
{
BuffSinkContext *p = context;
char *bufend;
if (p->buflen == 0)
{
p->buf = Tcl_Alloc(len + 1);
memcpy(p->buf, buffer, len);
p->buf[len] = '\0';
p->buflen = len;
} else {
p->buf = Tcl_Realloc(p->buf, len + p->buflen + 1);
bufend = p->buf + p->buflen;
memmove(bufend, buffer, len);
p->buf[len + p->buflen] = '\0';
p->buflen += len;
}
return len;
}
static int
tclGdWriteBufCmd(Tcl_Interp *interp, GdData *gdData, int argc, Tcl_Obj *CONST objv[])
{
#ifdef HAVE_LIBPNG
#ifdef HAVE_LIBZ
gdImagePtr im;
Tcl_Obj *output;
char *result = NULL;
BuffSinkContext bsc = {
NULL,
0
};
BuffSinkContext *res;
gdSink buffsink;
buffsink.sink = BufferSinkFunc;
buffsink.context = (void *)&bsc;
Tcl_GetString(objv[1]);
im = *(gdImagePtr *)tclhandleXlate(gdData->handleTbl, Tcl_GetString(objv[2]));
gdImagePngToSink(im, &buffsink);
res = buffsink.context;
result = res->buf;
output = Tcl_NewByteArrayObj((unsigned char*)result, res->buflen);
if (output == NULL)
return TCL_ERROR;
else
Tcl_IncrRefCount(output);
if (Tcl_ObjSetVar2(interp, objv[3], NULL, output, 0) == NULL)
return TCL_ERROR;
else
#endif
#endif
return TCL_OK;
}