summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--generic/tk.h10
-rw-r--r--generic/tkImgGIF.c156
-rw-r--r--generic/tkImgPNG.c25
-rw-r--r--generic/tkImgPhoto.c109
-rw-r--r--generic/tkImgSVGnano.c1547
-rw-r--r--generic/tkInt.h2
-rw-r--r--generic/tkWindow.c2
-rw-r--r--tests/imgPhoto.test228
-rw-r--r--tests/imgSVGnano.test116
9 files changed, 418 insertions, 1777 deletions
diff --git a/generic/tk.h b/generic/tk.h
index e8bcae4..910c22a 100644
--- a/generic/tk.h
+++ b/generic/tk.h
@@ -1445,22 +1445,20 @@ typedef struct Tk_PhotoImageFormatVersion3 Tk_PhotoImageFormatVersion3;
typedef int (Tk_ImageFileMatchProcVersion3) (Tcl_Interp *interp,
Tcl_Channel chan, const char *fileName, Tcl_Obj *format,
Tcl_Obj *metadataIn, int *widthPtr, int *heightPtr,
- Tcl_Obj *metadataOut, int *closeChannelPtr,
- Tcl_DString *driverInternalPtr);
+ Tcl_Obj *metadataOut);
typedef int (Tk_ImageStringMatchProcVersion3) (Tcl_Interp *interp,
Tcl_Obj *dataObj, Tcl_Obj *format, Tcl_Obj *metadataIn, int *widthPtr,
- int *heightPtr, Tcl_Obj *metadataOut, Tcl_DString *driverInternalPtr);
+ int *heightPtr, Tcl_Obj *metadataOut);
typedef int (Tk_ImageFileReadProcVersion3) (Tcl_Interp *interp,
Tcl_Channel chan,
const char *fileName, Tcl_Obj *format, Tcl_Obj *metadataIn,
Tk_PhotoHandle imageHandle,
int destX, int destY, int width, int height, int srcX, int srcY,
- Tcl_Obj *metadataOut, Tcl_DString *driverInternalPtr);
+ Tcl_Obj *metadataOut);
typedef int (Tk_ImageStringReadProcVersion3) (Tcl_Interp *interp,
Tcl_Obj *dataObj, Tcl_Obj *format, Tcl_Obj *metadataIn,
Tk_PhotoHandle imageHandle, int destX, int destY, int width, int height,
- int srcX, int srcY, Tcl_Obj *metadataOut,
- Tcl_DString *driverInternalPtr);
+ int srcX, int srcY, Tcl_Obj *metadataOut);
typedef int (Tk_ImageFileWriteProcVersion3) (Tcl_Interp *interp,
const char *fileName, Tcl_Obj *format, Tcl_Obj *metadataIn,
Tk_PhotoImageBlock *blockPtr);
diff --git a/generic/tkImgGIF.c b/generic/tkImgGIF.c
index 06a44ac..7dc78d8 100644
--- a/generic/tkImgGIF.c
+++ b/generic/tkImgGIF.c
@@ -121,25 +121,21 @@ typedef size_t (WriteBytesFunc) (ClientData clientData, const char *bytes,
static int FileMatchGIF(Tcl_Interp *interp, Tcl_Channel chan,
const char *fileName, Tcl_Obj *format,
Tcl_Obj *metadataInObj, int *widthPtr,
- int *heightPtr, Tcl_Obj *metadataOutObj,
- int *closeChannelPtr, Tcl_DString *driverInternal);
+ int *heightPtr, Tcl_Obj *metadataOutObj);
static int FileReadGIF(Tcl_Interp *interp, Tcl_Channel chan,
const char *fileName, Tcl_Obj *format,
Tcl_Obj *metadataInObj, Tk_PhotoHandle imageHandle,
int destX, int destY, int width, int height,
- int srcX, int srcY, Tcl_Obj *metadataOutObj,
- Tcl_DString *driverInternal);
+ int srcX, int srcY, Tcl_Obj *metadataOutObj);
static int StringMatchGIF(Tcl_Interp *interp, Tcl_Obj *dataObj,
Tcl_Obj *format, Tcl_Obj *metadataInObj,
int *widthPtr, int *heightPtr,
- Tcl_Obj *metadataOutObj,
- Tcl_DString *driverInternal);
+ Tcl_Obj *metadataOutObj);
static int StringReadGIF(Tcl_Interp *interp, Tcl_Obj *dataObj,
Tcl_Obj *format, Tcl_Obj *metadataInObj,
Tk_PhotoHandle imageHandle,
int destX, int destY, int width, int height,
- int srcX, int srcY, Tcl_Obj *metadataOutObj,
- Tcl_DString *driverInternal);
+ int srcX, int srcY, Tcl_Obj *metadataOutObj);
static int FileWriteGIF(Tcl_Interp *interp, const char *filename,
Tcl_Obj *format, Tcl_Obj *metadataInObj,
Tk_PhotoImageBlock *blockPtr);
@@ -368,9 +364,7 @@ FileMatchGIF(
int *widthPtr, int *heightPtr,
/* The dimensions of the image are returned
* here if the file is a valid raw GIF file. */
- Tcl_Obj *metadataOutObj, /* metadata return dict, may be NULL */
- int *closeChannelPtr, /* Return if the channel may be closed */
- Tcl_DString *driverInternal)/* memory passed to FileReadGIF */
+ Tcl_Obj *metadataOutObj) /* metadata return dict, may be NULL */
{
GIFImageConfig gifConf;
(void)fileName;
@@ -414,8 +408,7 @@ FileReadGIF(
* written to. */
int srcX, int srcY, /* Coordinates of top-left pixel to be used in
* image being read. */
- Tcl_Obj *metadataOutObj, /* metadata return dict, may be NULL */
- Tcl_DString *driverInternal)/* memory passed from FileMatchGIF */
+ Tcl_Obj *metadataOutObj) /* metadata return dict, may be NULL */
{
int fileWidth, fileHeight, imageWidth, imageHeight;
unsigned int nBytes;
@@ -859,8 +852,7 @@ StringMatchGIF(
Tcl_Obj *metadataInObj, /* metadata input, may be NULL */
int *widthPtr, /* where to put the string width */
int *heightPtr, /* where to put the string height */
- Tcl_Obj *metadataOutObj, /* metadata return dict, may be NULL */
- Tcl_DString *driverInternal)/* memory to pass to StringReadGIF */
+ Tcl_Obj *metadataOutObj) /* metadata return dict, may be NULL */
{
unsigned char *data, header[10];
TkSizeT got, length;
@@ -933,8 +925,7 @@ StringReadGIF(
int destX, int destY, /* The rectangular region of the */
int width, int height, /* image to copy */
int srcX, int srcY,
- Tcl_Obj *metadataOutObj, /* metadata return dict, may be NULL */
- Tcl_DString *driverInternal)/* memory passed from StringReadGIF */
+ Tcl_Obj *metadataOutObj) /* metadata return dict, may be NULL */
{
MFile handle, *hdlPtr = &handle;
TkSizeT length;
@@ -964,7 +955,7 @@ StringReadGIF(
return FileReadGIF(interp, (Tcl_Channel) hdlPtr, xferFormat, format,
metadataInObj, imageHandle, destX, destY, width, height, srcX, srcY,
- metadataOutObj, driverInternal);
+ metadataOutObj);
}
/*
@@ -1058,8 +1049,6 @@ ReadColorMap(
* The transparent color is set if present in current extensions
* The data of the following extensions are saved to the metadata dict:
* - Application extension
-* - XMP data is stored in key "XMP"
-* - any other under the key Application_<name><code>
* - Comment extension in key "comment"
* Plain text extensions are currently ignored.
*
@@ -1077,9 +1066,9 @@ DoExtension(
{
int count;
/* Prepare extension name
- * Maximum string size: "Application_"(12) + App(8) + Code(3) + trailing zero
+ * Maximum string size: "comment" + Code(3) + trailing zero
*/
- char extensionStreamName[24];
+ char extensionStreamName[8];
extensionStreamName[0] = '\0';
switch (label) {
@@ -1099,84 +1088,6 @@ DoExtension(
strcpy(extensionStreamName,"comment");
/* copy the extension data below */
break;
- case 0xff: /* Application Extension */
- /* Length: 11
- * Application Identifier: 8 bytes
- * Application Authentication code: 3 Bytes
- */
- count = GetDataBlock(gifConfPtr, chan, buf);
- if (count != 11) {
- return -1;
- }
- /* Detect XMP extension */
- if (NULL != metadataOutObj
- && 0 == memcmp(buf,"XMP DataXMP",11)) {
- /* XMP format does not use the block structure of GIF
- * The data is utf-8 which never contains 0's
- * A magic trailer of 258 bytes is added with the following data:
- * 0x01 0xff 0xfe ... 0x01 0x00 0x00
- */
- Tcl_Encoding encoding;
- Tcl_DString recodedDString;
- Tcl_DString dataDString;
- int length;
- int result;
- unsigned char lastbyte = 1;
- Tcl_DStringInit(&dataDString);
-
- for (;;) {
- unsigned char byte;
- if (1 != Fread(gifConfPtr, &byte, 1, 1, chan)) {
- /* read error */
- Tcl_DStringFree(&dataDString);
- return -1;
- }
- Tcl_DStringAppend(&dataDString,(char *)&byte,1);
- /* check for end of xmp header */
- if (byte == 0 && lastbyte == 0) {
- break;
- }
- lastbyte = byte;
- }
-
- /* check if trailer of 258 bytes is present */
- length = Tcl_DStringLength(&dataDString);
- if (length < 258) {
- Tcl_DStringFree(&dataDString);
- return -1;
- }
- /* Remove the trailer from the data */
- length -= 258;
- /* save the utf-8 data in the metadata dict key "XMP" */
- encoding = Tcl_GetEncoding(NULL, "utf-8");
- Tcl_DStringInit(&recodedDString);
- Tcl_ExternalToUtfDString(encoding, Tcl_DStringValue(&dataDString), length, &recodedDString);
- result = Tcl_DictObjPut(NULL, metadataOutObj,
- Tcl_NewStringObj("XMP",-1),
- Tcl_NewStringObj(Tcl_DStringValue(&recodedDString),
- Tcl_DStringLength(&recodedDString)));
- Tcl_DStringFree(&recodedDString);
- Tcl_DStringFree(&dataDString);
- Tcl_FreeEncoding(encoding);
- if ( TCL_OK != result ) {
- return -1;
- }
- return 0;
- } else {
- /*
- * Other extension
- * Name the extension: Application_xxxxxxxxxxx
- * 012345678901234567890123
- */
- /* Untested code commented out, no use case
- */
- /*
- strcpy(extensionStreamName,"Application_");
- memcpy(extensionStreamName+12,buf,11);
- extensionStreamName[23]='\0';
- */
- }
- break;
}
/* Add extension to dict */
if (NULL != metadataOutObj
@@ -2131,51 +2042,6 @@ CommonWriteGIF(
writeProc(handle, (char *) &c, 1);
}
}
-
- /*
- * Check and code XMP block
- */
-
- if (TCL_ERROR == Tcl_DictObjGet(interp, metadataInObj,
- Tcl_NewStringObj("XMP",-1),
- &itemData)) {
- return TCL_ERROR;
- }
- if (itemData != NULL) {
- Tcl_Encoding encoding;
- Tcl_DString recodedDString;
- char * itemString;
- int itemLength;
- int trailerChar;
-
- /* write header */
- writeProc(handle, "\x21\xff\x0bXMP DataXMP", 14);
-
- /* write utf-8 coded data */
- encoding = Tcl_GetEncoding(NULL, "utf-8");
- Tcl_DStringInit(&recodedDString);
- itemString = Tcl_GetStringFromObj(itemData, &itemLength);
- Tcl_UtfToExternalDString(encoding, itemString, itemLength,
- &recodedDString);
- writeProc(handle, Tcl_DStringValue(&recodedDString),
- Tcl_DStringLength(&recodedDString));
- Tcl_DStringFree(&recodedDString);
- Tcl_FreeEncoding(encoding);
-
- /* XMP format does not use the block structure of GIF
- * The data is utf-8 which never contains 0's
- * A magic trailer of 258 bytes is added with the following data:
- * 0x01 0xff 0xfe ... 0x01 0x00 0x00
- */
- c = 1;
- writeProc(handle, (char *) &c, 1);
- for (trailerChar = 0xff; trailerChar >= 0; trailerChar--) {
- c = (unsigned char)trailerChar;
- writeProc(handle, (char *) &c, 1);
- }
- c = 0;
- writeProc(handle, (char *) &c, 1);
- }
}
c = GIF_TERMINATOR;
writeProc(handle, (char *) &c, 1);
diff --git a/generic/tkImgPNG.c b/generic/tkImgPNG.c
index 91eb393..1ead8c0 100644
--- a/generic/tkImgPNG.c
+++ b/generic/tkImgPNG.c
@@ -212,14 +212,12 @@ static int EncodePNG(Tcl_Interp *interp,
static int FileMatchPNG(Tcl_Interp *interp, Tcl_Channel chan,
const char *fileName, Tcl_Obj *fmtObj,
Tcl_Obj *metadataInObj, int *widthPtr,
- int *heightPtr, Tcl_Obj *metadataOut,
- int *closeChannelPtr, Tcl_DString *driverInternal);
+ int *heightPtr, Tcl_Obj *metadataOut);
static int FileReadPNG(Tcl_Interp *interp, Tcl_Channel chan,
const char *fileName, Tcl_Obj *fmtObj,
Tcl_Obj *metadataInObj, Tk_PhotoHandle imageHandle,
int destX, int destY, int width, int height,
- int srcX, int srcY, Tcl_Obj *metadataOutPtr,
- Tcl_DString *driverInternal);
+ int srcX, int srcY, Tcl_Obj *metadataOutPtr);
static int FileWritePNG(Tcl_Interp *interp, const char *filename,
Tcl_Obj *fmtObj, Tcl_Obj *metadataInObj,
Tk_PhotoImageBlock *blockPtr);
@@ -254,14 +252,12 @@ static int SkipChunk(Tcl_Interp *interp, PNGImage *pngPtr,
static int StringMatchPNG(Tcl_Interp *interp, Tcl_Obj *pObjData,
Tcl_Obj *fmtObj, Tcl_Obj *metadataInObj,
int *widthPtr, int *heightPtr,
- Tcl_Obj *metadataOutObj,
- Tcl_DString *driverInternal);
+ Tcl_Obj *metadataOutObj);
static int StringReadPNG(Tcl_Interp *interp, Tcl_Obj *pObjData,
Tcl_Obj *fmtObj, Tcl_Obj *metadataInObj,
Tk_PhotoHandle imageHandle,
int destX, int destY, int width, int height,
- int srcX, int srcY, Tcl_Obj *metadataOutObj,
- Tcl_DString *driverInternal);
+ int srcX, int srcY, Tcl_Obj *metadataOutObj);
static int StringWritePNG(Tcl_Interp *interp, Tcl_Obj *fmtObj,
Tcl_Obj *metadataInObj,
@@ -2827,9 +2823,7 @@ FileMatchPNG(
int *widthPtr, int *heightPtr,
/* The dimensions of the image are returned
* here if the file is a valid raw GIF file. */
- Tcl_Obj *metadataOutObj, /* metadata return dict, may be NULL */
- int *closeChannelPtr, /* Return if the channel may be closed */
- Tcl_DString *driverInternal)/* memory passed to FileReadGIF */
+ Tcl_Obj *metadataOutObj) /* metadata return dict, may be NULL */
{
PNGImage png;
int match = 0;
@@ -2882,8 +2876,7 @@ FileReadPNG(
* written to. */
int srcX, int srcY, /* Coordinates of top-left pixel to be used in
* image being read. */
- Tcl_Obj *metadataOutObj, /* metadata return dict, may be NULL */
- Tcl_DString *driverInternal)/* memory passed from FileMatchGIF */
+ Tcl_Obj *metadataOutObj) /* metadata return dict, may be NULL */
{
PNGImage png;
int result = TCL_ERROR;
@@ -2941,8 +2934,7 @@ StringMatchPNG(
Tcl_Obj *metadataInObj, /* metadata input, may be NULL */
int *widthPtr, /* where to put the string width */
int *heightPtr, /* where to put the string height */
- Tcl_Obj *metadataOutObj, /* metadata return dict, may be NULL */
- Tcl_DString *driverInternal)/* memory to pass to StringReadGIF */
+ Tcl_Obj *metadataOutObj) /* metadata return dict, may be NULL */
{
PNGImage png;
int match = 0;
@@ -2990,8 +2982,7 @@ StringReadPNG(
int destX, int destY, /* The rectangular region of the */
int width, int height, /* image to copy */
int srcX, int srcY,
- Tcl_Obj *metadataOutObj, /* metadata return dict, may be NULL */
- Tcl_DString *driverInternal)/* memory passed from StringReadGIF */
+ Tcl_Obj *metadataOutObj) /* metadata return dict, may be NULL */
{
PNGImage png;
int result = TCL_ERROR;
diff --git a/generic/tkImgPhoto.c b/generic/tkImgPhoto.c
index f41cadd..92e4670 100644
--- a/generic/tkImgPhoto.c
+++ b/generic/tkImgPhoto.c
@@ -206,17 +206,14 @@ static int MatchFileFormat(Tcl_Interp *interp, Tcl_Channel chan,
Tcl_Obj *metadataOutObj,
Tk_PhotoImageFormat **imageFormatPtr,
Tk_PhotoImageFormatVersion3 **imageFormatVersion3Ptr,
- int *widthPtr, int *heightPtr, int *oldformat,
- int *closeChannelPtr,
- Tcl_DString *driverInternalPtr);
+ int *widthPtr, int *heightPtr, int *oldformat);
static int MatchStringFormat(Tcl_Interp *interp, Tcl_Obj *data,
Tcl_Obj *formatString,
Tcl_Obj *metadataInObj,
Tcl_Obj *metadataOutObj,
Tk_PhotoImageFormat **imageFormatPtr,
Tk_PhotoImageFormatVersion3 **imageFormatVersion3Ptr,
- int *widthPtr, int *heightPtr, int *oldformat,
- Tcl_DString *driverInternalPtr);
+ int *widthPtr, int *heightPtr, int *oldformat);
static const char * GetExtension(const char *path);
/*
@@ -981,9 +978,8 @@ ImgPhotoCmd(
}
case PHOTO_PUT: {
- int result;
Tcl_Obj *format, *data;
- Tcl_DString driverInternalDString;
+
/*
* photo put command - first parse the options.
*/
@@ -1002,12 +998,6 @@ ImgPhotoCmd(
Tcl_WrongNumArgs(interp, 2, objv, "data ?-option value ...?");
return TCL_ERROR;
}
-
- /*
- * Prepare memory connection between format match and read function
- */
-
- Tcl_DStringInit(&driverInternalDString);
/*
* See if there's a format that can read the data
@@ -1015,11 +1005,9 @@ ImgPhotoCmd(
if (MatchStringFormat(interp, objv[2], options.format,
options.metadata, NULL, &imageFormat,
- &imageFormatVersion3, &imageWidth, &imageHeight, &oldformat,
- &driverInternalDString)
+ &imageFormatVersion3, &imageWidth, &imageHeight, &oldformat)
!= TCL_OK) {
- result = TCL_ERROR;
- goto putCleanup;
+ return TCL_ERROR;
}
if (!(options.options & OPT_TO) || (options.toX2 < 0)) {
@@ -1046,8 +1034,7 @@ ImgPhotoCmd(
(Tk_PhotoHandle) masterPtr, options.toX, options.toY,
options.toX2 - options.toX,
options.toY2 - options.toY, 0, 0) != TCL_OK) {
- result = TCL_ERROR;
- goto putCleanup;
+ return TCL_ERROR;
}
} else {
if (imageFormatVersion3->stringReadProc(interp, data, format,
@@ -1055,10 +1042,9 @@ ImgPhotoCmd(
(Tk_PhotoHandle) masterPtr, options.toX, options.toY,
options.toX2 - options.toX,
options.toY2 - options.toY, 0, 0,
- NULL, &driverInternalDString)
+ NULL)
!= TCL_OK) {
- result = TCL_ERROR;
- goto putCleanup;
+ return TCL_ERROR;
}
}
@@ -1070,17 +1056,11 @@ ImgPhotoCmd(
*/
masterPtr->flags |= IMAGE_CHANGED;
- result = TCL_OK;
-putCleanup:
- Tcl_DStringFree(&driverInternalDString);
- return result;
-
+ return TCL_OK;
}
case PHOTO_READ: {
Tcl_Obj *format;
int result;
- int closeChannel = 0;
- Tcl_DString driverInternalDString;
/*
* photo read command - first parse the options specified.
@@ -1132,26 +1112,14 @@ putCleanup:
return TCL_ERROR;
}
- /*
- * Prepare memory connection between format match and read function
- */
-
- Tcl_DStringInit(&driverInternalDString);
- closeChannel = 0;
if (MatchFileFormat(interp, chan,
Tcl_GetString(options.name), options.format,
options.metadata, NULL, &imageFormat,
- &imageFormatVersion3, &imageWidth, &imageHeight, &oldformat,
- &closeChannel, &driverInternalDString)
+ &imageFormatVersion3, &imageWidth, &imageHeight, &oldformat)
!= TCL_OK) {
result = TCL_ERROR;
goto readCleanup;
}
-
- if (closeChannel) {
- Tcl_Close(NULL, chan);
- chan = NULL;
- }
/*
* Check the values given for the -from option.
@@ -1210,10 +1178,9 @@ putCleanup:
Tcl_GetString(options.name),
format, options.metadata, (Tk_PhotoHandle) masterPtr,
options.toX, options.toY, width, height, options.fromX,
- options.fromY, NULL, &driverInternalDString);
+ options.fromY, NULL);
}
readCleanup:
- Tcl_DStringFree(&driverInternalDString);
if (chan != NULL) {
Tcl_Close(NULL, chan);
}
@@ -1998,8 +1965,6 @@ ImgPhotoConfigureMaster(
Tk_PhotoImageFormat *imageFormat;
Tk_PhotoImageFormatVersion3 *imageFormatVersion3;
const char **args;
- Tcl_DString driverInternalDString;
- int closeChannel;
args = (const char **)ckalloc((objc + 1) * sizeof(char *));
for (i = 0, j = 0; i < objc; i++,j++) {
@@ -2049,12 +2014,6 @@ ImgPhotoConfigureMaster(
}
/*
- * Prepare memory connection between format match and read function
- */
-
- Tcl_DStringInit(&driverInternalDString);
-
- /*
* Save the current values for fileString and dataString, so we can tell
* if the user specifies them anew. IMPORTANT: if the format changes we
* have to interpret "-file" and "-data" again as well! It might be that
@@ -2197,8 +2156,6 @@ ImgPhotoConfigureMaster(
goto errorExit;
}
- closeChannel = 0;
-
/*
* Flag that we want the metadata result dict
*/
@@ -2215,15 +2172,10 @@ ImgPhotoConfigureMaster(
(MatchFileFormat(interp, chan, masterPtr->fileString,
masterPtr->format, masterPtr->metadata, metadataOutObj,
&imageFormat, &imageFormatVersion3,
- &imageWidth, &imageHeight, &oldformat, &closeChannel,
- &driverInternalDString) != TCL_OK)) {
+ &imageWidth, &imageHeight, &oldformat) != TCL_OK)) {
Tcl_Close(NULL, chan);
goto errorExit;
}
- if (closeChannel) {
- Tcl_Close(NULL, chan);
- chan = NULL;
- }
result = ImgPhotoSetSize(masterPtr, imageWidth, imageHeight);
if (result != TCL_OK) {
Tcl_Close(NULL, chan);
@@ -2246,11 +2198,10 @@ ImgPhotoConfigureMaster(
masterPtr->fileString, tempformat, masterPtr->metadata,
(Tk_PhotoHandle) masterPtr,
0, 0, imageWidth, imageHeight, 0, 0,
- metadataOutObj, &driverInternalDString);
- }
- if (chan != NULL) {
- Tcl_Close(NULL, chan);
+ metadataOutObj);
}
+
+ Tcl_Close(NULL, chan);
if (result != TCL_OK) {
goto errorExit;
}
@@ -2273,7 +2224,7 @@ ImgPhotoConfigureMaster(
if (MatchStringFormat(interp, masterPtr->dataString,
masterPtr->format, masterPtr->metadata, metadataOutObj,
&imageFormat, &imageFormatVersion3, &imageWidth,
- &imageHeight, &oldformat, &driverInternalDString) != TCL_OK) {
+ &imageHeight, &oldformat) != TCL_OK) {
goto errorExit;
}
if (ImgPhotoSetSize(masterPtr, imageWidth, imageHeight) != TCL_OK) {
@@ -2300,8 +2251,7 @@ ImgPhotoConfigureMaster(
if (imageFormatVersion3->stringReadProc(interp, tempdata, tempformat,
masterPtr->metadata, (Tk_PhotoHandle) masterPtr, 0, 0,
- imageWidth, imageHeight, 0, 0, metadataOutObj,
- &driverInternalDString) != TCL_OK) {
+ imageWidth, imageHeight, 0, 0, metadataOutObj) != TCL_OK) {
goto errorExit;
}
}
@@ -2352,7 +2302,7 @@ ImgPhotoConfigureMaster(
}
}
}
-
+
/*
* Enforce a reasonable value for gamma.
*/
@@ -2385,7 +2335,6 @@ ImgPhotoConfigureMaster(
masterPtr->height, masterPtr->width, masterPtr->height);
masterPtr->flags &= ~IMAGE_CHANGED;
- Tcl_DStringInit(&driverInternalDString);
if (oldData != NULL) {
Tcl_DecrRefCount(oldData);
}
@@ -2401,7 +2350,6 @@ ImgPhotoConfigureMaster(
return TCL_OK;
errorExit:
- Tcl_DStringInit(&driverInternalDString);
if (oldData != NULL) {
Tcl_DecrRefCount(oldData);
}
@@ -2776,12 +2724,10 @@ MatchFileFormat(
int *widthPtr, int *heightPtr,
/* The dimensions of the image are returned
* here. */
- int *oldformat, /* Returns 1 if the old image API is used. */
- int *closeChannelPtr, /* Is set to 1 if channel can be closed */
- Tcl_DString *driverInternalPtr)/* Memory to be passed to the corresponding
- * ReadFileFormat function */
+ int *oldformat) /* Returns 1 if the old image API is used. */
{
- int matched = 0, useoldformat = 0;
+ int matched = 0;
+ int useoldformat = 0;
Tk_PhotoImageFormat *formatPtr;
Tk_PhotoImageFormatVersion3 *formatVersion3Ptr;
ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
@@ -2907,7 +2853,7 @@ if (formatPtr == NULL) {
if (formatVersion3Ptr->fileMatchProc(interp, chan, fileName,
formatObj, metadataInObj, widthPtr, heightPtr,
- metadataOutObj, closeChannelPtr, driverInternalPtr)) {
+ metadataOutObj)) {
if (*widthPtr < 1) {
*widthPtr = 1;
}
@@ -2917,9 +2863,7 @@ if (formatPtr == NULL) {
*imageFormatVersion3Ptr = formatVersion3Ptr;
*imageFormatPtr = NULL;
*oldformat = 0;
- if (! *closeChannelPtr ) {
- (void) Tcl_Seek(chan, Tcl_LongAsWide(0L), SEEK_SET);
- }
+ (void) Tcl_Seek(chan, Tcl_LongAsWide(0L), SEEK_SET);
return TCL_OK;
}
@@ -3002,10 +2946,7 @@ MatchStringFormat(
int *widthPtr, int *heightPtr,
/* The dimensions of the image are returned
* here. */
- int *oldformat, /* Returns 1 if the old image API is used. */
- Tcl_DString *driverInternalPtr)
- /* Memory to be passed to the corresponding
- * ReadFileFormat function */
+ int *oldformat) /* Returns 1 if the old image API is used. */
{
int matched = 0, useoldformat = 0;
Tk_PhotoImageFormat *formatPtr, *defaultFormatPtr = NULL;
@@ -3125,7 +3066,7 @@ MatchStringFormat(
&& (formatVersion3Ptr->stringReadProc != NULL)
&& formatVersion3Ptr->stringMatchProc(interp, data,
formatObj, metadataInObj, widthPtr, heightPtr,
- metadataOutObj, driverInternalPtr)) {
+ metadataOutObj)) {
break;
}
diff --git a/generic/tkImgSVGnano.c b/generic/tkImgSVGnano.c
index c4eceb0..7575f86 100644
--- a/generic/tkImgSVGnano.c
+++ b/generic/tkImgSVGnano.c
@@ -27,94 +27,13 @@
#define NANOSVGRAST_IMPLEMENTATION
#include "nanosvgrast.h"
-/*
- * Serialized data version
- * This consists of "svg" plus binary '1' at byte locations in an int.
- * It serves as indication, version and endinaess check
- */
-
-#define STRUCTURE_VERSION ('s'+256*'v'+65535*'g'+16777216*1)
-
-/*
- * Serialized image data header
- */
-
-typedef struct {
- unsigned int structureVersion;
- float dpi;
- float width; // Width of the image.
- float height; // Height of the image.
- int shapeCount;
- int pathCount;
- int ptsCount;
- int gradientCount;
- int gradientStopCount;
-} serializedHeader;
-
-/*
- * Result of options parsing and first block in driver internal DString
- */
+/* Additional parameters to nsvgRasterize() */
typedef struct {
double scale;
int scaleToHeight;
int scaleToWidth;
- float dpi;
- int svgBlobFollows;
-} optionsStruct;
-
-/*
- * Serialized structures from NSCG
- * All pointers are replaced by array indexes
- */
-
-typedef struct NSVGgradientSerialized {
- float xform[6];
- char spread;
- float fx, fy;
- int nstops;
- int stops;
-} NSVGgradientSerialized;
-
-typedef struct NSVGpaintSerialized {
- char type;
- union {
- unsigned int color;
- int gradient;
- };
-} NSVGpaintSerialized;
-
-
-typedef struct NSVGpathSerialized
-{
- int pts; // Cubic bezier points: x0,y0, [cpx1,cpx1,cpx2,cpy2,x1,y1], ...
- int npts; // Total number of bezier points.
- // Caution: pair of floats
- char closed; // Flag indicating if shapes should be treated as closed.
- float bounds[4]; // Tight bounding box of the shape [minx,miny,maxx,maxy].
- int next; // Pointer to next path, or NULL if last element.
-} NSVGpathSerialized;
-
-typedef struct NSVGshapeSerialized
-{
- char id[64]; // Optional 'id' attr of the shape or its group
- NSVGpaintSerialized fill; // Fill paint
- NSVGpaintSerialized stroke; // Stroke paint
- float opacity; // Opacity of the shape.
- float strokeWidth; // Stroke width (scaled).
- float strokeDashOffset; // Stroke dash offset (scaled).
- float strokeDashArray[8]; // Stroke dash array (scaled).
- char strokeDashCount; // Number of dash values in dash array.
- char strokeLineJoin; // Stroke join type.
- char strokeLineCap; // Stroke cap type.
- float miterLimit; // Miter limit
- char fillRule; // Fill rule, see NSVGfillRule.
- unsigned char flags; // Logical or of NSVG_FLAGS_* flags
- float bounds[4]; // Tight bounding box of the shape [minx,miny,maxx,maxy].
- int paths; // Linked list of paths in the image.
- int next; // Pointer to next shape, or NULL if last element.
-} NSVGshapeSerialized;
-
+} RastOpts;
/*
* Per interp cache of last NSVGimage which was matched to
@@ -130,65 +49,45 @@ typedef struct {
ClientData dataOrChan;
Tcl_DString formatString;
NSVGimage *nsvgImage;
+ RastOpts ropts;
} NSVGcache;
-static int FileMatchSVG(Tcl_Interp *interp, Tcl_Channel chan,
- const char *fileName, Tcl_Obj *formatObj,
- Tcl_Obj *metadataInObj, int *widthPtr,
- int *heightPtr, Tcl_Obj *metadataOutObj,
- int *closeChannelPtr,
- Tcl_DString *driverInternal);
+static int FileMatchSVG(Tcl_Channel chan, const char *fileName,
+ Tcl_Obj *format, int *widthPtr, int *heightPtr,
+ Tcl_Interp *interp);
static int FileReadSVG(Tcl_Interp *interp, Tcl_Channel chan,
const char *fileName, Tcl_Obj *format,
- Tcl_Obj *metadataIn, Tk_PhotoHandle imageHandle,
- int destX, int destY, int width, int height,
- int srcX, int srcY,
- Tcl_Obj *metadataOut, Tcl_DString *driverInternal);
-static int StringMatchSVG(Tcl_Interp *interp, Tcl_Obj *dataObj,
- Tcl_Obj *format, Tcl_Obj *metadataIn, int *widthPtr,
- int *heightPtr, Tcl_Obj *metadataOutObj,
- Tcl_DString *driverInternal);
+ Tk_PhotoHandle imageHandle, int destX, int destY,
+ int width, int height, int srcX, int srcY);
+static int StringMatchSVG(Tcl_Obj *dataObj, Tcl_Obj *format,
+ int *widthPtr, int *heightPtr, Tcl_Interp *interp);
static int StringReadSVG(Tcl_Interp *interp, Tcl_Obj *dataObj,
- Tcl_Obj *format, Tcl_Obj *metadataIn,
- Tk_PhotoHandle imageHandle,
+ Tcl_Obj *format, Tk_PhotoHandle imageHandle,
int destX, int destY, int width, int height,
- int srcX, int srcY,
- Tcl_Obj *metadataOut, Tcl_DString *driverInternal);
-static int ParseOptions(Tcl_Interp *interp, Tcl_Obj *formatObj,
- optionsStruct *optionsPtr);
-static NSVGimage * ParseSVG(Tcl_Interp *interp, Tcl_Obj *dataObj, float dpi);
+ int srcX, int srcY);
+static NSVGimage * ParseSVGWithOptions(Tcl_Interp *interp,
+ const char *input, TkSizeT length, Tcl_Obj *format,
+ RastOpts *ropts);
static int RasterizeSVG(Tcl_Interp *interp,
- Tk_PhotoHandle imageHandle,
- char *svgBlob, optionsStruct * optionsPtr,
+ Tk_PhotoHandle imageHandle, NSVGimage *nsvgImage,
int destX, int destY, int width, int height,
- int srcX, int srcY);
-static double GetScaleFromParameters(
- serializedHeader *serializedHeaderPtr,
- optionsStruct * optionsPtr, int *widthPtr,
- int *heightPtr);
-static void SerializeNSVGImage(Tcl_DString *driverInternalPtr,
- NSVGimage *nsvgImage);
-static void SerializePath(struct NSVGpath *pathPtr,
- serializedHeader *serializedHeaderPtr,
- Tcl_DString *pathDStringPtr,
- Tcl_DString *ptrDStringPtr);
-static struct NSVGpaintSerialized SerializePaint(struct NSVGpaint *paintPtr,
- serializedHeader *serializedHeaderPtr,
- Tcl_DString *gradientDStringPtr,
- Tcl_DString *gradientStopDStringPtr);
-static char * StringCheckMetadata(Tcl_Obj *dataObj, Tcl_Obj *metadataInObj,
- float dpi, int *LengthPtr);
-static int SaveSVGBLOBToMetadata(Tcl_Interp *interp, Tcl_Obj *metadataOutObj,
- Tcl_DString *driverInternalPtr);
-static void nsvgRasterizeSerialized(NSVGrasterizer* r, char *svgBlobPtr, float tx,
- float ty, float scale, unsigned char* dst, int w,
- int h, int stride);
+ int srcX, int srcY, RastOpts *ropts);
+static double GetScaleFromParameters(NSVGimage *nsvgImage,
+ RastOpts *ropts, int *widthPtr, int *heightPtr);
+static NSVGcache * GetCachePtr(Tcl_Interp *interp);
+static int CacheSVG(Tcl_Interp *interp, ClientData dataOrChan,
+ Tcl_Obj *formatObj, NSVGimage *nsvgImage,
+ RastOpts *ropts);
+static NSVGimage * GetCachedSVG(Tcl_Interp *interp, ClientData dataOrChan,
+ Tcl_Obj *formatObj, RastOpts *ropts);
+static void CleanCache(Tcl_Interp *interp);
+static void FreeCache(ClientData clientData, Tcl_Interp *interp);
/*
* The format record for the SVG nano file format:
*/
-Tk_PhotoImageFormatVersion3 tkImgFmtSVGnano = {
+Tk_PhotoImageFormat tkImgFmtSVGnano = {
"svg", /* name */
FileMatchSVG, /* fileMatchProc */
StringMatchSVG, /* stringMatchProc */
@@ -219,381 +118,45 @@ Tk_PhotoImageFormatVersion3 tkImgFmtSVGnano = {
static int
FileMatchSVG(
- Tcl_Interp *interp, /* interpreter pointer */
- Tcl_Channel chan, /* The image file, open for reading. */
- const char *fileName, /* The name of the image file. */
- Tcl_Obj *formatObj, /* User-specified format object, or NULL. */
- Tcl_Obj *metadataInObj, /* metadata input, may be NULL */
+ Tcl_Channel chan,
+ const char *fileName,
+ Tcl_Obj *formatObj,
int *widthPtr, int *heightPtr,
- /* The dimensions of the image are returned
- * here if the file is a valid raw GIF file. */
- Tcl_Obj *metadataOut, /* metadata return dict, may be NULL */
- int *closeChannelPtr, /* Return if the channel may be closed */
- Tcl_DString *driverInternalPtr)
- /* memory passed to FileReadGIF */
+ Tcl_Interp *interp)
{
- Tcl_Obj *dataObj;
+ TkSizeT length;
+ Tcl_Obj *dataObj = Tcl_NewObj();
+ const char *data;
+ RastOpts ropts;
NSVGimage *nsvgImage;
- serializedHeader *serializedHeaderPtr;
- optionsStruct options;
-
(void)fileName;
- /*
- * Parse the options. Unfortunately, any error can not be returned.
- */
-
- if (TCL_OK != ParseOptions(interp, formatObj, &options) ) {
- return 0;
- }
-
- /*
- * Read the file data into a TCL object
- */
-
- dataObj = Tcl_NewObj();
+ CleanCache(interp);
if (Tcl_ReadChars(chan, dataObj, -1, 0) == TCL_IO_FAILURE) {
/* in case of an error reading the file */
Tcl_DecrRefCount(dataObj);
return 0;
}
-
- /*
- * Parse the SVG data
- */
-
- nsvgImage = ParseSVG(interp, dataObj, options.dpi);
+ data = TkGetStringFromObj(dataObj, &length);
+ nsvgImage = ParseSVGWithOptions(interp, data, length, formatObj, &ropts);
Tcl_DecrRefCount(dataObj);
if (nsvgImage != NULL) {
-
- /*
- * On successful parse, save the data in the header structure
- */
-
- Tcl_DStringSetLength(driverInternalPtr,
- sizeof(optionsStruct)+sizeof(serializedHeader));
-
- options.svgBlobFollows = 1;
- memcpy( Tcl_DStringValue(driverInternalPtr), &options,
- sizeof(optionsStruct));
-
- serializedHeaderPtr = (serializedHeader *)
- (Tcl_DStringValue(driverInternalPtr) + sizeof(optionsStruct));
-
- serializedHeaderPtr->width = nsvgImage->width;
- serializedHeaderPtr->height = nsvgImage->height;
- serializedHeaderPtr->dpi = options.dpi;
- GetScaleFromParameters(serializedHeaderPtr, &options, widthPtr,
- heightPtr);
+ GetScaleFromParameters(nsvgImage, &ropts, widthPtr, heightPtr);
if ((*widthPtr <= 0.0) || (*heightPtr <= 0.0)) {
nsvgDelete(nsvgImage);
return 0;
}
-
- /*
- * Serialize the NSVGImage structure
- * As the DString is resized, serializedHeaderPtr may get invalid
- */
-
- SerializeNSVGImage(driverInternalPtr, nsvgImage);
- nsvgDelete(nsvgImage);
+ if (!CacheSVG(interp, chan, formatObj, nsvgImage, &ropts)) {
+ nsvgDelete(nsvgImage);
+ }
return 1;
}
return 0;
-
}
/*
*----------------------------------------------------------------------
*
- * SerializeNSVGImage --
- *
- * This function saves the NSVGimage structure into the DString.
- *
- * Results:
- * none.
- *
- * Side effects:
- * The DString size is changed and thus, the value pointer may
- * change.
- *
- *----------------------------------------------------------------------
- */
-
-static void SerializeNSVGImage(Tcl_DString *driverInternalPtr,
- NSVGimage *nsvgImage) {
- serializedHeader *serializedHeaderPtr;
- Tcl_DString shapeDString, pathDString, ptsDString, gradientDString,
- gradientStopDString;
- NSVGshape *shapePtr;
-
- serializedHeaderPtr = (serializedHeader *)
- (Tcl_DStringValue(driverInternalPtr) + sizeof(optionsStruct));
- Tcl_DStringInit(&shapeDString);
- Tcl_DStringInit(&pathDString);
- Tcl_DStringInit(&ptsDString);
- Tcl_DStringInit(&gradientDString);
- Tcl_DStringInit(&gradientStopDString);
-
- serializedHeaderPtr->structureVersion = STRUCTURE_VERSION;
- serializedHeaderPtr->shapeCount = 0;
- serializedHeaderPtr->pathCount = 0;
- serializedHeaderPtr->ptsCount = 0;
- serializedHeaderPtr->gradientCount = 0;
- serializedHeaderPtr->gradientStopCount = 0;
-
- for ( shapePtr = nsvgImage->shapes; shapePtr != NULL;
- shapePtr = shapePtr->next) {
- NSVGshapeSerialized shapeSerialized;
-
- /*
- * Copy serialized shape fix data
- */
-
- memcpy(shapeSerialized.id, shapePtr->id, 64 * sizeof(char));
-
- shapeSerialized.fill = SerializePaint(&(shapePtr->fill),
- serializedHeaderPtr, &gradientDString, &gradientStopDString);
-
- shapeSerialized.stroke = SerializePaint(&(shapePtr->stroke),
- serializedHeaderPtr, &gradientDString, &gradientStopDString);
-
- shapeSerialized.opacity = shapePtr->opacity;
- shapeSerialized.strokeWidth = shapePtr->strokeWidth;
- shapeSerialized.strokeDashOffset = shapePtr->strokeDashOffset;
- memcpy(shapeSerialized.strokeDashArray, shapePtr->strokeDashArray,
- 8*sizeof(float));
- shapeSerialized.strokeDashCount = shapePtr->strokeDashCount;
- shapeSerialized.strokeLineJoin = shapePtr->strokeLineJoin;
- shapeSerialized.strokeLineCap = shapePtr->strokeLineCap;
- shapeSerialized.miterLimit = shapePtr->miterLimit;
- shapeSerialized.fillRule = shapePtr->fillRule;
- shapeSerialized.flags = shapePtr->flags;
- memcpy(shapeSerialized.bounds, shapePtr->bounds, 4*sizeof(float));
-
- /*
- * Serialize the paths linked list
- */
-
- if ( shapePtr->paths == NULL ) {
- shapeSerialized.paths = -1;
- } else {
- shapeSerialized.paths = serializedHeaderPtr->pathCount;
- SerializePath(shapePtr->paths, serializedHeaderPtr, &pathDString,
- &ptsDString);
- }
-
- /*
- * generate next array position and save to DString
- */
-
- serializedHeaderPtr->shapeCount++;
- shapeSerialized.next =
- shapePtr->next == NULL ? -1:
- serializedHeaderPtr->shapeCount;
-
- Tcl_DStringAppend(&shapeDString,
- (const char *)&shapeSerialized, sizeof(NSVGshapeSerialized));
- }
-
- /*
- * Write the DStrings into the driver memory one after the other
- * Note: serializedHeaderPtr may get invalid due to DString resize
- */
-
- if (Tcl_DStringLength(&shapeDString) > 0) {
- Tcl_DStringAppend(driverInternalPtr,
- Tcl_DStringValue(&shapeDString),
- Tcl_DStringLength(&shapeDString));
- }
- Tcl_DStringFree(&shapeDString);
-
- if (Tcl_DStringLength(&pathDString) > 0) {
- Tcl_DStringAppend(driverInternalPtr,
- Tcl_DStringValue(&pathDString),
- Tcl_DStringLength(&pathDString));
- }
- Tcl_DStringFree(&pathDString);
-
- if (Tcl_DStringLength(&ptsDString) > 0) {
- Tcl_DStringAppend(driverInternalPtr,
- Tcl_DStringValue(&ptsDString),
- Tcl_DStringLength(&ptsDString));
- }
- Tcl_DStringFree(&ptsDString);
-
- if (Tcl_DStringLength(&gradientDString) > 0) {
- Tcl_DStringAppend(driverInternalPtr,
- Tcl_DStringValue(&gradientDString),
- Tcl_DStringLength(&gradientDString));
- }
- Tcl_DStringFree(&gradientDString);
-
- if (Tcl_DStringLength(&gradientStopDString) > 0) {
- Tcl_DStringAppend(driverInternalPtr,
- Tcl_DStringValue(&gradientStopDString),
- Tcl_DStringLength(&gradientStopDString));
- }
- Tcl_DStringFree(&gradientStopDString);
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * SerializePaint --
- *
- * This function transforms the NSVGpaint structure to a serialize
- * version.
- * The child structures gradient and gradientStop are serialized into
- * their DString memory.
- *
- * Results:
- * NSVGPaintSerialized structure.
- *
- * Side effects:
- * The DString size is changed and thus, the value pointer may
- * change.
- *
- *----------------------------------------------------------------------
- */
-
-static struct NSVGpaintSerialized SerializePaint(struct NSVGpaint *paintPtr,
- serializedHeader *serializedHeaderPtr,
- Tcl_DString *gradientDStringPtr,
- Tcl_DString *gradientStopDStringPtr)
-{
- struct NSVGpaintSerialized paintSerialized;
-
- paintSerialized.type = paintPtr->type;
-
- if (paintPtr->type == NSVG_PAINT_LINEAR_GRADIENT
- || paintPtr->type == NSVG_PAINT_RADIAL_GRADIENT) {
-
- /*
- * Gradient union pointer present
- */
-
- NSVGgradient* gradientPtr;
- NSVGgradientSerialized gradientSerialized;
-
- gradientPtr = paintPtr->gradient;
- memcpy(&(gradientSerialized.xform), gradientPtr->xform,
- 6 * sizeof(float) );
- gradientSerialized.spread = gradientPtr->spread;
- gradientSerialized.fx = gradientPtr->fx;
- gradientSerialized.fy = gradientPtr->fy;
-
- /*
- * Copy gradient stop array to DString
- */
-
- gradientSerialized.nstops = gradientPtr->nstops;
- if ( gradientPtr->nstops == 0 ) {
- gradientSerialized.stops = -1;
- } else {
- gradientSerialized.stops = serializedHeaderPtr->gradientStopCount;
- Tcl_DStringAppend(gradientStopDStringPtr,
- (const char *)gradientPtr->stops,
- gradientPtr->nstops * sizeof(NSVGgradientStop));
-
- (serializedHeaderPtr->gradientStopCount) += gradientPtr->nstops;
- }
- (serializedHeaderPtr->gradientStopCount) += gradientPtr->nstops;
-
- paintSerialized.gradient = serializedHeaderPtr->gradientCount;
- Tcl_DStringAppend(gradientDStringPtr,
- (const char *) & gradientSerialized,
- sizeof(NSVGgradientSerialized));
- (serializedHeaderPtr->gradientCount) ++;
-
- } else {
-
- /*
- * Color union or nothing present
- */
-
- paintSerialized.color = paintPtr->color;
- }
- return paintSerialized;
-}
-/*
- *----------------------------------------------------------------------
- *
- * SerializePath --
- *
- * This function serializes a linked list of NSVGpath structure into
- * the corresponding DString array.
- *
- * Results:
- * none
- *
- * Side effects:
- * The DString size is changed and thus, the value pointer may
- * change.
- *
- *----------------------------------------------------------------------
- */
-
-static void SerializePath(struct NSVGpath *pathPtr,
- serializedHeader *serializedHeaderPtr,
- Tcl_DString *pathDStringPtr,
- Tcl_DString *ptsDStringPtr)
-{
-
- /*
- * loop over path linked list
- */
-
- for (;pathPtr != NULL; pathPtr = pathPtr->next) {
- NSVGpathSerialized pathSerialized;
- int index;
-
- /*
- * Save points in the ptr dstring.
- * The first index and the count is saved.
- */
-
- pathSerialized.npts = pathPtr->npts;
- if (pathPtr->npts == 0) {
- pathSerialized.pts = -1;
- } else {
-
- /*
- * Attention: npts is a pair of floats
- */
-
- pathSerialized.pts = serializedHeaderPtr->ptsCount;
- for (index = 0; index < (pathPtr->npts) * 2; index++) {
- float ptCurrent;
- ptCurrent = pathPtr->pts[index];
- Tcl_DStringAppend(ptsDStringPtr,
- (const char *)&ptCurrent, sizeof(float));
- (serializedHeaderPtr->ptsCount)++;
- }
- }
-
- /*
- * Copy the other items of the path structure
- */
-
- pathSerialized.closed = pathPtr->closed;
- memcpy(pathSerialized.bounds, pathPtr->bounds, 4*sizeof(float));
-
- /*
- * Build the next item and add to DString
- */
-
- serializedHeaderPtr->pathCount++;
- pathSerialized.next = (pathPtr->next == NULL) ? -1 :
- serializedHeaderPtr->pathCount;
-
- Tcl_DStringAppend(pathDStringPtr,
- (const char *)&pathSerialized, sizeof(NSVGpathSerialized));
- }
-}
-/*
- *----------------------------------------------------------------------
- *
* FileReadSVG --
*
* This function is called by the photo image type to read SVG format
@@ -612,48 +175,41 @@ static void SerializePath(struct NSVGpath *pathPtr,
static int
FileReadSVG(
- Tcl_Interp *interp, /* Interpreter to use for reporting errors. */
- Tcl_Channel chan, /* The image file, open for reading. */
- const char *fileName, /* The name of the image file. */
- Tcl_Obj *formatObj, /* User-specified format object, or NULL. */
- Tcl_Obj *metadataInObj, /* metadata input, may be NULL */
- Tk_PhotoHandle imageHandle, /* The photo image to write into. */
- int destX, int destY, /* Coordinates of top-left pixel in photo
- * image to be written to. */
- int width, int height, /* Dimensions of block of photo image to be
- * written to. */
- int srcX, int srcY, /* Coordinates of top-left pixel to be used in
- * image being read. */
- Tcl_Obj *metadataOutObj, /* metadata return dict, may be NULL */
- Tcl_DString *driverInternalPtr)
- /* memory passed from FileMatchGIF */
+ Tcl_Interp *interp,
+ Tcl_Channel chan,
+ const char *fileName,
+ Tcl_Obj *formatObj,
+ Tk_PhotoHandle imageHandle,
+ int destX, int destY,
+ int width, int height,
+ int srcX, int srcY)
{
- int result;
- optionsStruct * optionsPtr;
- char * svgBlob;
+ TkSizeT length;
+ const char *data;
+ RastOpts ropts;
+ NSVGimage *nsvgImage = GetCachedSVG(interp, chan, formatObj, &ropts);
(void)fileName;
-
-
- optionsPtr = (optionsStruct *) Tcl_DStringValue(driverInternalPtr);
- svgBlob = Tcl_DStringValue(driverInternalPtr) + sizeof(optionsStruct);
-
- /*
- * Raster the parsed SVG from the SVGBLOB in the driver internal DString
- */
-
- result = RasterizeSVG(interp, imageHandle, svgBlob, optionsPtr, destX,
- destY, width, height, srcX, srcY);
- /*
- * On success, output the SVGBLOB as metadata
- */
+ if (nsvgImage == NULL) {
+ Tcl_Obj *dataObj = Tcl_NewObj();
- if (result == TCL_OK) {
- result = SaveSVGBLOBToMetadata(interp, metadataOutObj,
- driverInternalPtr);
+ if (Tcl_ReadChars(chan, dataObj, -1, 0) == TCL_IO_FAILURE) {
+ /* in case of an error reading the file */
+ Tcl_DecrRefCount(dataObj);
+ Tcl_SetObjResult(interp, Tcl_NewStringObj("read error", -1));
+ Tcl_SetErrorCode(interp, "TK", "IMAGE", "SVG", "READ_ERROR", NULL);
+ return TCL_ERROR;
+ }
+ data = TkGetStringFromObj(dataObj, &length);
+ nsvgImage = ParseSVGWithOptions(interp, data, length, formatObj,
+ &ropts);
+ Tcl_DecrRefCount(dataObj);
+ if (nsvgImage == NULL) {
+ return TCL_ERROR;
+ }
}
-
- return result;
+ return RasterizeSVG(interp, imageHandle, nsvgImage, destX, destY,
+ width, height, srcX, srcY, &ropts);
}
/*
@@ -676,95 +232,28 @@ FileReadSVG(
static int
StringMatchSVG(
- Tcl_Interp *interp, /* interpreter to report errors */
- Tcl_Obj *dataObj, /* the object containing the image data */
- Tcl_Obj *formatObj, /* the image format object, or NULL */
- Tcl_Obj *metadataInObj, /* metadata input, may be NULL */
- int *widthPtr, /* where to put the string width */
- int *heightPtr, /* where to put the string height */
- Tcl_Obj *metadataOut, /* metadata return dict, may be NULL */
- Tcl_DString *driverInternalPtr)
- /* memory to pass to StringReadGIF */
+ Tcl_Obj *dataObj,
+ Tcl_Obj *formatObj,
+ int *widthPtr, int *heightPtr,
+ Tcl_Interp *interp)
{
TkSizeT length;
+ const char *data;
+ RastOpts ropts;
NSVGimage *nsvgImage;
- serializedHeader *serializedHeaderPtr;
- char * svgBlobPtr;
- optionsStruct options;
-
- /*
- * Parse the options. Unfortunately, any error can not be returned.
- */
-
- if (TCL_OK != ParseOptions(interp, formatObj, &options) ) {
- return 0;
- }
-
- /*
- * Check for the special data to indicate that the metadata should be used.
- * On special data, get the serialized header structure and check it.
- */
-
- svgBlobPtr = StringCheckMetadata( dataObj, metadataInObj, options.dpi,
- &length);
-
- if (NULL != svgBlobPtr) {
- serializedHeaderPtr = (serializedHeader *) svgBlobPtr;
- } else {
- Tcl_DStringSetLength(driverInternalPtr,
- sizeof(optionsStruct)+sizeof(serializedHeader));
-
- options.svgBlobFollows = 1;
- memcpy( Tcl_DStringValue(driverInternalPtr), &options,
- sizeof(optionsStruct));
-
- serializedHeaderPtr = (serializedHeader *)
- (Tcl_DStringValue(driverInternalPtr) + sizeof(optionsStruct));
- }
-
- /*
- * Use the metadata svg blob if present to return width and height
- */
-
- if (NULL != svgBlobPtr) {
- /*
- * Save the options struct in the driver internal DString
- */
- options.svgBlobFollows = 0;
- Tcl_DStringSetLength(driverInternalPtr, sizeof(optionsStruct));
- memcpy(Tcl_DStringValue(driverInternalPtr), &options,
- sizeof(optionsStruct));
-
- GetScaleFromParameters(serializedHeaderPtr, &options, widthPtr,
- heightPtr);
- return 1;
- }
-
- /*
- * Check the passed data object and serialize it on success.
- */
-
- nsvgImage = ParseSVG(interp, dataObj, options.dpi);
+ CleanCache(interp);
+ data = TkGetStringFromObj(dataObj, &length);
+ nsvgImage = ParseSVGWithOptions(interp, data, length, formatObj, &ropts);
if (nsvgImage != NULL) {
- serializedHeaderPtr->width = nsvgImage->width;
- serializedHeaderPtr->height = nsvgImage->height;
- serializedHeaderPtr->dpi = options.dpi;
- GetScaleFromParameters(serializedHeaderPtr, &options, widthPtr,
- heightPtr);
+ GetScaleFromParameters(nsvgImage, &ropts, widthPtr, heightPtr);
if ((*widthPtr <= 0.0) || (*heightPtr <= 0.0)) {
nsvgDelete(nsvgImage);
return 0;
}
-
- /*
- * Serialize the NSVGImage structure
- * As the DString is resized, serializedHeaderPtr may get invalid
- */
-
- SerializeNSVGImage(driverInternalPtr, nsvgImage);
-
- nsvgDelete(nsvgImage);
+ if (!CacheSVG(interp, dataObj, formatObj, nsvgImage, &ropts)) {
+ nsvgDelete(nsvgImage);
+ }
return 1;
}
return 0;
@@ -773,68 +262,6 @@ StringMatchSVG(
/*
*----------------------------------------------------------------------
*
- * StringCheckMetadata --
- *
- * Check the passed tring for a metadata serialized structure.
- *
- * Results:
- * The svg blob pointer on success, NULL otherwise.
- *
- * Side effects:
- * The file is saved in the internal cache for further use.
- *
- *----------------------------------------------------------------------
- */
-
-static char * StringCheckMetadata(
- Tcl_Obj *dataObj, /* the object containing the image data */
- Tcl_Obj *metadataInObj, /* metadata input, may be NULL */
- float dpi, /* options dpi must match svgblob */
- TkSizeT *lengthOutPtr) /* output data length on success */
-{
- TkSizeT length;
- const char *data;
- serializedHeader *serializedHeaderPtr;
- char * svgBlobPtr;
- Tcl_Obj *itemData;
-
- /*
- * Check for the special data to indicate that the metadata should be used.
- * On special data, get the serialized header structure and check it.
- */
-
- if (NULL == metadataInObj) {
- return NULL;
- }
-
- data = TkGetStringFromObj(dataObj, &length);
- if (0 != strcmp(data, "<svg data=\"metadata\" />") ) {
- return NULL;
- }
- if (TCL_ERROR == Tcl_DictObjGet(NULL, metadataInObj,
- Tcl_NewStringObj("SVGBLOB",-1), &itemData)) {
- return NULL;
- }
- if (itemData == NULL) {
- return NULL;
- }
- svgBlobPtr = Tcl_GetByteArrayFromObj(itemData, &length);
- if (length < sizeof(serializedHeader) ) {
- return NULL;
- }
- serializedHeaderPtr = (serializedHeader *)svgBlobPtr;
- if (serializedHeaderPtr->structureVersion != STRUCTURE_VERSION
- || serializedHeaderPtr->dpi != dpi
- ) {
- return NULL;
- }
- *lengthOutPtr = length;
- return svgBlobPtr;
-}
-
-/*
- *----------------------------------------------------------------------
- *
* StringReadSVG --
*
* This function is called by the photo image type to read SVG format
@@ -852,112 +279,59 @@ static char * StringCheckMetadata(
static int
StringReadSVG(
- Tcl_Interp *interp, /* interpreter for reporting errors in */
- Tcl_Obj *dataObj, /* object containing the image */
- Tcl_Obj *formatObj, /* format object, or NULL */
- Tcl_Obj *metadataInObj, /* metadata input, may be NULL */
- Tk_PhotoHandle imageHandle, /* the image to write this data into */
- int destX, int destY, /* The rectangular region of the */
- int width, int height, /* image to copy */
- int srcX, int srcY,
- Tcl_Obj *metadataOutObj, /* metadata return dict, may be NULL */
- Tcl_DString *driverInternalPtr)
- /* memory passed from StringReadSVG */
+ Tcl_Interp *interp,
+ Tcl_Obj *dataObj,
+ Tcl_Obj *formatObj,
+ Tk_PhotoHandle imageHandle,
+ int destX, int destY,
+ int width, int height,
+ int srcX, int srcY)
{
- int result;
TkSizeT length;
- char * svgBlobPtr;
- optionsStruct * optionsPtr;
- Tcl_Obj *itemData;
-
- optionsPtr = (optionsStruct *) Tcl_DStringValue(driverInternalPtr);
- if (optionsPtr->svgBlobFollows) {
- svgBlobPtr = Tcl_DStringValue(driverInternalPtr)+ sizeof(optionsStruct);
- } else {
- if (NULL == metadataInObj
- || TCL_ERROR == Tcl_DictObjGet(NULL, metadataInObj,
- Tcl_NewStringObj("SVGBLOB",-1), &itemData)
- || itemData == NULL) {
- Tcl_SetObjResult(interp, Tcl_NewStringObj(
- "internal error: -metadata missing", -1));
- Tcl_SetErrorCode(interp, "TK", "IMAGE", "SVG", "BAD_SCALE",
- NULL);
- return TCL_ERROR;
- }
-
- svgBlobPtr = Tcl_GetByteArrayFromObj(itemData, &length);
- }
-
- result = RasterizeSVG(interp, imageHandle,
- svgBlobPtr, optionsPtr, destX, destY, width, height, srcX, srcY);
- if (result != TCL_OK) {
- return result;
- }
+ const char *data;
+ RastOpts ropts;
+ NSVGimage *nsvgImage = GetCachedSVG(interp, dataObj, formatObj, &ropts);
- if (!optionsPtr->svgBlobFollows) {
- return TCL_OK;
+ if (nsvgImage == NULL) {
+ data = TkGetStringFromObj(dataObj, &length);
+ nsvgImage = ParseSVGWithOptions(interp, data, length, formatObj,
+ &ropts);
}
-
- return SaveSVGBLOBToMetadata(interp, metadataOutObj, driverInternalPtr);
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * SaveSVGBLOBToMetadata --
- *
- * Copy the driver internal DString into the metadata key SVGBLOB.
- *
- * Results:
- * A TCL result value.
- *
- * Side effects:
- * Change the output metadata.
- *
- *----------------------------------------------------------------------
- */
-
-static int SaveSVGBLOBToMetadata(
- Tcl_Interp *interp, /* interpreter for reporting errors in */
- Tcl_Obj *metadataOutObj, /* metadata return dict, may be NULL */
- Tcl_DString *driverInternalPtr)
- /* memory passed from xxxReadSVG */
-{
- if (metadataOutObj == NULL) {
- return TCL_OK;
+ if (nsvgImage == NULL) {
+ return TCL_ERROR;
}
- return Tcl_DictObjPut(interp, metadataOutObj,
- Tcl_NewStringObj("SVGBLOB",-1),
- Tcl_NewByteArrayObj(
- Tcl_DStringValue(driverInternalPtr) + sizeof(optionsStruct),
- Tcl_DStringLength(driverInternalPtr) - sizeof(optionsStruct)));
+ return RasterizeSVG(interp, imageHandle, nsvgImage, destX, destY,
+ width, height, srcX, srcY, &ropts);
}
/*
*----------------------------------------------------------------------
*
- * ParseOptions --
+ * ParseSVGWithOptions --
*
- * Parse the options given in the -format parameter.
+ * This function is called to parse the given input string as SVG.
*
* Results:
- * A normal tcl result
+ * Return a newly create NSVGimage on success, and NULL otherwise.
*
* Side effects:
*
*----------------------------------------------------------------------
*/
-static int
-ParseOptions(
+static NSVGimage *
+ParseSVGWithOptions(
Tcl_Interp *interp,
+ const char *input,
+ TkSizeT length,
Tcl_Obj *formatObj,
- optionsStruct * optionsPtr)
+ RastOpts *ropts)
{
Tcl_Obj **objv = NULL;
int objc = 0;
- double dpi;
+ double dpi = 96.0;
char *inputCopy = NULL;
+ NSVGimage *nsvgImage;
int parameterScaleSeen = 0;
static const char *const fmtOptions[] = {
"-dpi", "-scale", "-scaletoheight", "-scaletowidth", NULL
@@ -967,16 +341,29 @@ ParseOptions(
};
/*
+ * The parser destroys the original input string,
+ * therefore first duplicate.
+ */
+
+ inputCopy = (char *)attemptckalloc(length+1);
+ if (inputCopy == NULL) {
+ Tcl_SetObjResult(interp, Tcl_NewStringObj("cannot alloc data buffer", -1));
+ Tcl_SetErrorCode(interp, "TK", "IMAGE", "SVG", "OUT_OF_MEMORY", NULL);
+ goto error;
+ }
+ memcpy(inputCopy, input, length);
+ inputCopy[length] = '\0';
+
+ /*
* Process elements of format specification as a list.
*/
- optionsPtr->dpi = 96.0;
- optionsPtr->scale = 1.0;
- optionsPtr->scaleToHeight = 0;
- optionsPtr->scaleToWidth = 0;
+ ropts->scale = 1.0;
+ ropts->scaleToHeight = 0;
+ ropts->scaleToWidth = 0;
if ((formatObj != NULL) &&
Tcl_ListObjGetElements(interp, formatObj, &objc, &objv) != TCL_OK) {
- return TCL_ERROR;;
+ goto error;
}
for (; objc > 0 ; objc--, objv++) {
int optIndex;
@@ -991,12 +378,14 @@ ParseOptions(
if (Tcl_GetIndexFromObjStruct(interp, objv[0], fmtOptions,
sizeof(char *), "option", 0, &optIndex) == TCL_ERROR) {
- return TCL_ERROR;;
+ goto error;
}
if (objc < 2) {
+ ckfree(inputCopy);
+ inputCopy = NULL;
Tcl_WrongNumArgs(interp, 1, objv, "value");
- return TCL_ERROR;;
+ goto error;
}
objc--;
@@ -1014,7 +403,7 @@ ParseOptions(
"only one of -scale, -scaletoheight, -scaletowidth may be given", -1));
Tcl_SetErrorCode(interp, "TK", "IMAGE", "SVG", "BAD_SCALE",
NULL);
- return TCL_ERROR;;
+ goto error;
}
parameterScaleSeen = 1;
break;
@@ -1028,174 +417,72 @@ ParseOptions(
switch ((enum fmtOptions) optIndex) {
case OPT_DPI:
if (Tcl_GetDoubleFromObj(interp, objv[0], &dpi) == TCL_ERROR) {
- return TCL_ERROR;;
+ goto error;
}
if (dpi < 0.0) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"-dpi value must be positive", -1));
Tcl_SetErrorCode(interp, "TK", "IMAGE", "SVG", "BAD_DPI",
NULL);
- return TCL_ERROR;;
+ goto error;
}
- optionsPtr->dpi = (float)dpi;
break;
case OPT_SCALE:
- if (Tcl_GetDoubleFromObj(interp, objv[0],
- &(optionsPtr->scale)) ==
+ if (Tcl_GetDoubleFromObj(interp, objv[0], &ropts->scale) ==
TCL_ERROR) {
- return TCL_ERROR;;
+ goto error;
}
- if (optionsPtr->scale <= 0.0) {
+ if (ropts->scale <= 0.0) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"-scale value must be positive", -1));
Tcl_SetErrorCode(interp, "TK", "IMAGE", "SVG", "BAD_SCALE",
NULL);
- return TCL_ERROR;;
+ goto error;
}
break;
case OPT_SCALE_TO_HEIGHT:
- if (Tcl_GetIntFromObj(interp, objv[0],
- &(optionsPtr->scaleToHeight)) == TCL_ERROR) {
- return TCL_ERROR;;
+ if (Tcl_GetIntFromObj(interp, objv[0], &ropts->scaleToHeight) ==
+ TCL_ERROR) {
+ goto error;
}
- if (optionsPtr->scaleToHeight <= 0) {
+ if (ropts->scaleToHeight <= 0) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"-scaletoheight value must be positive", -1));
Tcl_SetErrorCode(interp, "TK", "IMAGE", "SVG", "BAD_SCALE",
NULL);
- return TCL_ERROR;;
+ goto error;
}
break;
case OPT_SCALE_TO_WIDTH:
- if (Tcl_GetIntFromObj(interp, objv[0],
- &(optionsPtr->scaleToWidth)) == TCL_ERROR) {
- return TCL_ERROR;;
+ if (Tcl_GetIntFromObj(interp, objv[0], &ropts->scaleToWidth) ==
+ TCL_ERROR) {
+ goto error;
}
- if (optionsPtr->scaleToWidth <= 0) {
+ if (ropts->scaleToWidth <= 0) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"-scaletowidth value must be positive", -1));
Tcl_SetErrorCode(interp, "TK", "IMAGE", "SVG", "BAD_SCALE",
NULL);
- return TCL_ERROR;;
+ goto error;
}
break;
}
}
-
- return TCL_OK;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * ParseSVG --
- *
- * This function is called to parse the given input string as SVG.
- *
- * Results:
- * Return a newly create NSVGimage on success, and NULL otherwise.
- *
- * Side effects:
- *
- *----------------------------------------------------------------------
- */
-
-static NSVGimage *
-ParseSVG(
- Tcl_Interp *interp,
- Tcl_Obj *dataObj,
- float dpi)
-{
- const char *input;
- char *inputCopy = NULL;
- NSVGimage *nsvgImage;
- TkSizeT length;
-
- /*
- * The parser destroys the original input string,
- * therefore first duplicate.
- */
-
- input = TkGetStringFromObj(dataObj, &length);
- inputCopy = (char *)attemptckalloc(length+1);
- if (inputCopy == NULL) {
- Tcl_SetObjResult(interp, Tcl_NewStringObj("cannot alloc data buffer", -1));
- Tcl_SetErrorCode(interp, "TK", "IMAGE", "SVG", "OUT_OF_MEMORY", NULL);
- return NULL;
- }
- memcpy(inputCopy, input, length);
- inputCopy[length] = '\0';
-
- nsvgImage = nsvgParse(inputCopy, "px", dpi);
+ nsvgImage = nsvgParse(inputCopy, "px", (float) dpi);
if (nsvgImage == NULL) {
Tcl_SetObjResult(interp, Tcl_NewStringObj("cannot parse SVG image", -1));
Tcl_SetErrorCode(interp, "TK", "IMAGE", "SVG", "PARSE_ERROR", NULL);
- ckfree(inputCopy);
- return NULL;
+ goto error;
}
ckfree(inputCopy);
return nsvgImage;
-}
-/*
- *----------------------------------------------------------------------
- *
- * GetScaleFromParameters --
- *
- * Get the scale value from the already parsed parameters -scale,
- * -scaletoheight and -scaletowidth.
- *
- * The image width and height is also returned.
- *
- * Results:
- * The evaluated or configured scale value, or 0.0 on failure
- *
- * Side effects:
- * heightPtr and widthPtr are set to height and width of the image.
- *
- *----------------------------------------------------------------------
- */
-
-static double
-GetScaleFromParameters(
- serializedHeader *serializedHeaderPtr,
- optionsStruct * optionsPtr,
- int *widthPtr,
- int *heightPtr)
-{
- double scale;
- int width, height;
-
- if ((serializedHeaderPtr->width == 0.0) || (serializedHeaderPtr->height == 0.0)) {
- width = height = 0;
- scale = 1.0;
- } else if (optionsPtr->scaleToHeight > 0) {
- /*
- * Fixed height
- */
- height = optionsPtr->scaleToHeight;
- scale = height / serializedHeaderPtr->height;
- width = (int) ceil(serializedHeaderPtr->width * scale);
- } else if (optionsPtr->scaleToWidth > 0) {
- /*
- * Fixed width
- */
- width = optionsPtr->scaleToWidth;
- scale = width / serializedHeaderPtr->width;
- height = (int) ceil(serializedHeaderPtr->height * scale);
- } else {
- /*
- * Scale factor
- */
- scale = optionsPtr->scale;
- width = (int) ceil(serializedHeaderPtr->width * scale);
- height = (int) ceil(serializedHeaderPtr->height * scale);
+error:
+ if (inputCopy != NULL) {
+ ckfree(inputCopy);
}
-
- *heightPtr = height;
- *widthPtr = width;
- return scale;
+ return NULL;
}
/*
@@ -1221,11 +508,11 @@ static int
RasterizeSVG(
Tcl_Interp *interp,
Tk_PhotoHandle imageHandle,
- char *svgBlobPtr,
- optionsStruct * optionsPtr,
+ NSVGimage *nsvgImage,
int destX, int destY,
int width, int height,
- int srcX, int srcY)
+ int srcX, int srcY,
+ RastOpts *ropts)
{
int w, h, c;
NSVGrasterizer *rast;
@@ -1234,16 +521,15 @@ RasterizeSVG(
double scale;
(void)srcX;
(void)srcY;
-
- scale = GetScaleFromParameters((serializedHeader *) svgBlobPtr, optionsPtr,
- &w, &h);
+
+ scale = GetScaleFromParameters(nsvgImage, ropts, &w, &h);
rast = nsvgCreateRasterizer();
if (rast == NULL) {
Tcl_SetObjResult(interp, Tcl_NewStringObj("cannot initialize rasterizer", -1));
Tcl_SetErrorCode(interp, "TK", "IMAGE", "SVG", "RASTERIZER_ERROR",
NULL);
- return TCL_ERROR;
+ goto cleanAST;
}
imgData = (unsigned char *)attemptckalloc(w * h *4);
if (imgData == NULL) {
@@ -1251,8 +537,7 @@ RasterizeSVG(
Tcl_SetErrorCode(interp, "TK", "IMAGE", "SVG", "OUT_OF_MEMORY", NULL);
goto cleanRAST;
}
-
- nsvgRasterizeSerialized(rast, svgBlobPtr, 0, 0,
+ nsvgRasterize(rast, nsvgImage, 0, 0,
(float) scale, imgData, w, h, w * 4);
/* transfer the data to a photo block */
svgblock.pixelPtr = imgData;
@@ -1273,6 +558,7 @@ RasterizeSVG(
}
ckfree(imgData);
nsvgDeleteRasterizer(rast);
+ nsvgDelete(nsvgImage);
return TCL_OK;
cleanimg:
@@ -1281,369 +567,244 @@ cleanimg:
cleanRAST:
nsvgDeleteRasterizer(rast);
+cleanAST:
+ nsvgDelete(nsvgImage);
return TCL_ERROR;
}
/*
*----------------------------------------------------------------------
*
- * Rasterize Serialized --
+ * GetScaleFromParameters --
*
- * Fiunctions of svgnrast.h which requires modification due to the
- * serialized data structure.
+ * Get the scale value from the already parsed parameters -scale,
+ * -scaletoheight and -scaletowidth.
*
- * Results:
+ * The image width and height is also returned.
*
+ * Results:
+ * The evaluated or configured scale value, or 0.0 on failure
*
* Side effects:
+ * heightPtr and widthPtr are set to height and width of the image.
*
*----------------------------------------------------------------------
*/
-static void nsvg__flattenShapeSerialized(NSVGrasterizer* r, int pathIndex,
- NSVGpathSerialized *pathSerializedPtr, float *ptsSerializedPtr,
- float scale)
+static double
+GetScaleFromParameters(
+ NSVGimage *nsvgImage,
+ RastOpts *ropts,
+ int *widthPtr,
+ int *heightPtr)
{
- int i, j;
- NSVGpathSerialized* path;
+ double scale;
+ int width, height;
- for (; pathIndex != -1; pathIndex = pathSerializedPtr[pathIndex].next) {
- path = &(pathSerializedPtr[pathIndex]);
- r->npoints = 0;
- // Flatten path
- nsvg__addPathPoint(r,
- ptsSerializedPtr[path->pts]*scale,
- ptsSerializedPtr[path->pts+1]*scale, 0);
- for (i = 0; i < path->npts-1; i += 3) {
- float* p = &ptsSerializedPtr[path->pts+i*2];
- nsvg__flattenCubicBez(r, p[0]*scale,p[1]*scale, p[2]*scale,p[3]*scale, p[4]*scale,p[5]*scale, p[6]*scale,p[7]*scale, 0, 0);
- }
- // Close path
- nsvg__addPathPoint(r, ptsSerializedPtr[path->pts]*scale,
- ptsSerializedPtr[path->pts+1]*scale, 0);
- // Build edges
- for (i = 0, j = r->npoints-1; i < r->npoints; j = i++)
- nsvg__addEdge(r, r->points[j].x, r->points[j].y, r->points[i].x, r->points[i].y);
+ if ((nsvgImage->width == 0.0) || (nsvgImage->height == 0.0)) {
+ width = height = 0;
+ scale = 1.0;
+ } else if (ropts->scaleToHeight > 0) {
+ /*
+ * Fixed height
+ */
+ height = ropts->scaleToHeight;
+ scale = height / nsvgImage->height;
+ width = (int) ceil(nsvgImage->width * scale);
+ } else if (ropts->scaleToWidth > 0) {
+ /*
+ * Fixed width
+ */
+ width = ropts->scaleToWidth;
+ scale = width / nsvgImage->width;
+ height = (int) ceil(nsvgImage->height * scale);
+ } else {
+ /*
+ * Scale factor
+ */
+ scale = ropts->scale;
+ width = (int) ceil(nsvgImage->width * scale);
+ height = (int) ceil(nsvgImage->height * scale);
}
-}
-
-static void nsvg__initPaintSerialized(NSVGcachedPaint* cache,
- NSVGpaintSerialized* paint, float opacity,
- NSVGgradientSerialized *gradientSerializedPtr,
- NSVGgradientStop *gradientStopPtr)
-{
- int i, j;
- NSVGgradientSerialized* grad;
- cache->type = paint->type;
-
- if (paint->type == NSVG_PAINT_COLOR) {
- cache->colors[0] = nsvg__applyOpacity(paint->color, opacity);
- return;
- }
+ *heightPtr = height;
+ *widthPtr = width;
+ return scale;
+}
- grad = &(gradientSerializedPtr[paint->gradient]);
+/*
+ *----------------------------------------------------------------------
+ *
+ * GetCachePtr --
+ *
+ * This function is called to get the per interpreter used
+ * svg image cache.
+ *
+ * Results:
+ * Return a pointer to the used cache.
+ *
+ * Side effects:
+ * Initialize the cache on the first call.
+ *
+ *----------------------------------------------------------------------
+ */
- cache->spread = grad->spread;
- memcpy(cache->xform, grad->xform, sizeof(float)*6);
+static NSVGcache *
+GetCachePtr(
+ Tcl_Interp *interp
+) {
+ NSVGcache *cachePtr = (NSVGcache *)Tcl_GetAssocData(interp, "tksvgnano", NULL);
+ if (cachePtr == NULL) {
+ cachePtr = (NSVGcache *)ckalloc(sizeof(NSVGcache));
+ cachePtr->dataOrChan = NULL;
+ Tcl_DStringInit(&cachePtr->formatString);
+ cachePtr->nsvgImage = NULL;
+ Tcl_SetAssocData(interp, "tksvgnano", FreeCache, cachePtr);
+ }
+ return cachePtr;
+}
- if (grad->nstops == 0) {
- for (i = 0; i < 256; i++)
- cache->colors[i] = 0;
- } if (grad->nstops == 1) {
- for (i = 0; i < 256; i++)
- cache->colors[i] = nsvg__applyOpacity(
- gradientStopPtr[grad->stops+i].color, opacity);
- } else {
- unsigned int ca, cb = 0;
- float ua, ub, du, u;
- int ia, ib, count;
+/*
+ *----------------------------------------------------------------------
+ *
+ * CacheSVG --
+ *
+ * Add the given svg image informations to the cache for further usage.
+ *
+ * Results:
+ * Return 1 on success, and 0 otherwise.
+ *
+ * Side effects:
+ *
+ *----------------------------------------------------------------------
+ */
- ca = nsvg__applyOpacity(gradientStopPtr[grad->stops].color, opacity);
- ua = nsvg__clampf(gradientStopPtr[grad->stops].offset, 0, 1);
- ub = nsvg__clampf(gradientStopPtr[grad->stops+grad->nstops-1].offset,
- ua, 1);
- ia = (int)(ua * 255.0f);
- ib = (int)(ub * 255.0f);
- for (i = 0; i < ia; i++) {
- cache->colors[i] = ca;
- }
+static int
+CacheSVG(
+ Tcl_Interp *interp,
+ ClientData dataOrChan,
+ Tcl_Obj *formatObj,
+ NSVGimage *nsvgImage,
+ RastOpts *ropts)
+{
+ TkSizeT length;
+ const char *data;
+ NSVGcache *cachePtr = GetCachePtr(interp);
- for (i = 0; i < grad->nstops-1; i++) {
- ca = nsvg__applyOpacity(gradientStopPtr[grad->stops+i].color,
- opacity);
- cb = nsvg__applyOpacity(gradientStopPtr[grad->stops+i+1].color,
- opacity);
- ua = nsvg__clampf(gradientStopPtr[grad->stops+i].offset, 0, 1);
- ub = nsvg__clampf(gradientStopPtr[grad->stops+i+1].offset, 0, 1);
- ia = (int)(ua * 255.0f);
- ib = (int)(ub * 255.0f);
- count = ib - ia;
- if (count <= 0) continue;
- u = 0;
- du = 1.0f / (float)count;
- for (j = 0; j < count; j++) {
- cache->colors[ia+j] = nsvg__lerpRGBA(ca,cb,u);
- u += du;
- }
+ if (cachePtr != NULL) {
+ cachePtr->dataOrChan = dataOrChan;
+ if (formatObj != NULL) {
+ data = TkGetStringFromObj(formatObj, &length);
+ Tcl_DStringAppend(&cachePtr->formatString, data, length);
}
-
- for (i = ib; i < 256; i++)
- cache->colors[i] = cb;
+ cachePtr->nsvgImage = nsvgImage;
+ cachePtr->ropts = *ropts;
+ return 1;
}
-
+ return 0;
}
-static void nsvg__flattenShapeStrokeSerialized(NSVGrasterizer* r,
- NSVGshapeSerialized* shape, NSVGpathSerialized *pathSerializedPtr,
- float *ptsSerializedPtr, float scale)
-{
- int i, j, closed, pathIndex;
- NSVGpathSerialized* path;
- NSVGpoint* p0, *p1;
- float miterLimit = shape->miterLimit;
- int lineJoin = shape->strokeLineJoin;
- int lineCap = shape->strokeLineCap;
- float lineWidth = shape->strokeWidth * scale;
-
- for (pathIndex = shape->paths; pathIndex != -1;
- pathIndex = pathSerializedPtr[pathIndex].next) {
- path = &(pathSerializedPtr[pathIndex]);
- // Flatten path
- r->npoints = 0;
- nsvg__addPathPoint(r, ptsSerializedPtr[path->pts]*scale,
- ptsSerializedPtr[path->pts+1]*scale, NSVG_PT_CORNER);
- for (i = 0; i < path->npts-1; i += 3) {
- float* p = &ptsSerializedPtr[path->pts+i*2];
- nsvg__flattenCubicBez(r, p[0]*scale,p[1]*scale, p[2]*scale,
- p[3]*scale, p[4]*scale,p[5]*scale, p[6]*scale,p[7]*scale, 0,
- NSVG_PT_CORNER);
- }
- if (r->npoints < 2)
- continue;
-
- closed = path->closed;
-
- // If the first and last points are the same, remove the last, mark as closed path.
- p0 = &r->points[r->npoints-1];
- p1 = &r->points[0];
- if (nsvg__ptEquals(p0->x,p0->y, p1->x,p1->y, r->distTol)) {
- r->npoints--;
- p0 = &r->points[r->npoints-1];
- closed = 1;
- }
-
- if (shape->strokeDashCount > 0) {
- int idash = 0, dashState = 1;
- float totalDist = 0, dashLen, allDashLen, dashOffset;
- NSVGpoint cur;
-
- if (closed)
- nsvg__appendPathPoint(r, r->points[0]);
-
- // Duplicate points -> points2.
- nsvg__duplicatePoints(r);
- r->npoints = 0;
- cur = r->points2[0];
- nsvg__appendPathPoint(r, cur);
-
- // Figure out dash offset.
- allDashLen = 0;
- for (j = 0; j < shape->strokeDashCount; j++)
- allDashLen += shape->strokeDashArray[j];
- if (shape->strokeDashCount & 1)
- allDashLen *= 2.0f;
- // Find location inside pattern
- dashOffset = fmodf(shape->strokeDashOffset, allDashLen);
- if (dashOffset < 0.0f)
- dashOffset += allDashLen;
-
- while (dashOffset > shape->strokeDashArray[idash]) {
- dashOffset -= shape->strokeDashArray[idash];
- idash = (idash + 1) % shape->strokeDashCount;
- }
- dashLen = (shape->strokeDashArray[idash] - dashOffset) * scale;
-
- for (j = 1; j < r->npoints2; ) {
- float dx = r->points2[j].x - cur.x;
- float dy = r->points2[j].y - cur.y;
- float dist = sqrtf(dx*dx + dy*dy);
-
- if ((totalDist + dist) > dashLen) {
- // Calculate intermediate point
- float d = (dashLen - totalDist) / dist;
- float x = cur.x + dx * d;
- float y = cur.y + dy * d;
- nsvg__addPathPoint(r, x, y, NSVG_PT_CORNER);
+/*
+ *----------------------------------------------------------------------
+ *
+ * GetCachedSVG --
+ *
+ * Try to get the NSVGimage from the internal cache.
+ *
+ * Results:
+ * Return the found NSVGimage on success, and NULL otherwise.
+ *
+ * Side effects:
+ * Calls the CleanCache() function.
+ *
+ *----------------------------------------------------------------------
+ */
- // Stroke
- if (r->npoints > 1 && dashState) {
- nsvg__prepareStroke(r, miterLimit, lineJoin);
- nsvg__expandStroke(r, r->points, r->npoints, 0,
- lineJoin, lineCap, lineWidth);
- }
- // Advance dash pattern
- dashState = !dashState;
- idash = (idash+1) % shape->strokeDashCount;
- dashLen = shape->strokeDashArray[idash] * scale;
- // Restart
- cur.x = x;
- cur.y = y;
- cur.flags = NSVG_PT_CORNER;
- totalDist = 0.0f;
- r->npoints = 0;
- nsvg__appendPathPoint(r, cur);
- } else {
- totalDist += dist;
- cur = r->points2[j];
- nsvg__appendPathPoint(r, cur);
- j++;
- }
+static NSVGimage *
+GetCachedSVG(
+ Tcl_Interp *interp,
+ ClientData dataOrChan,
+ Tcl_Obj *formatObj,
+ RastOpts *ropts)
+{
+ TkSizeT length;
+ const char *data;
+ NSVGcache *cachePtr = GetCachePtr(interp);
+ NSVGimage *nsvgImage = NULL;
+
+ if ((cachePtr != NULL) && (cachePtr->nsvgImage != NULL) &&
+ (cachePtr->dataOrChan == dataOrChan)) {
+ if (formatObj != NULL) {
+ data = TkGetStringFromObj(formatObj, &length);
+ if (strcmp(data, Tcl_DStringValue(&cachePtr->formatString)) == 0) {
+ nsvgImage = cachePtr->nsvgImage;
+ *ropts = cachePtr->ropts;
+ cachePtr->nsvgImage = NULL;
}
- // Stroke any leftover path
- if (r->npoints > 1 && dashState)
- nsvg__expandStroke(r, r->points, r->npoints, 0, lineJoin,
- lineCap, lineWidth);
- } else {
- nsvg__prepareStroke(r, miterLimit, lineJoin);
- nsvg__expandStroke(r, r->points, r->npoints, closed, lineJoin,
- lineCap, lineWidth);
+ } else if (Tcl_DStringLength(&cachePtr->formatString) == 0) {
+ nsvgImage = cachePtr->nsvgImage;
+ *ropts = cachePtr->ropts;
+ cachePtr->nsvgImage = NULL;
}
}
+ CleanCache(interp);
+ return nsvgImage;
}
-
/*
*----------------------------------------------------------------------
*
- * RasterizeSVGSerialized --
+ * CleanCache --
*
- * This function is called to rasterize the given nsvgImage and
- * fill the imageHandle with data.
+ * Reset the cache and delete the saved image in it.
*
* Results:
- * A standard TCL completion code. If TCL_ERROR is returned then an error
- * message is left in the interp's result.
- *
*
* Side effects:
- * On error the given nsvgImage will be deleted.
*
*----------------------------------------------------------------------
*/
-static void nsvgRasterizeSerialized(NSVGrasterizer* r,
- char *svgBlobPtr, float tx, float ty, float scale,
- unsigned char* dst, int w, int h, int stride)
+static void
+CleanCache(Tcl_Interp *interp)
{
- NSVGshapeSerialized *shape = NULL;
- NSVGedge *e = NULL;
- NSVGcachedPaint cache;
- int i, shapeIndex;
- serializedHeader * serializedHeaderPtr;
- NSVGshapeSerialized *shapeSerializedPtr;
- NSVGpathSerialized *pathSerializedPtr;
- float *ptsSerializedPtr;
- NSVGgradientSerialized *gradientSerializedPtr;
- NSVGgradientStop *gradientStopPtr;
-
- /*
- * Prepare the array pointers of the data array placed after serializedHeader
- */
- serializedHeaderPtr = (serializedHeader *) svgBlobPtr;
- svgBlobPtr += sizeof (serializedHeader);
- shapeSerializedPtr = (NSVGshapeSerialized *) svgBlobPtr;
- svgBlobPtr += serializedHeaderPtr->shapeCount * sizeof(NSVGshapeSerialized);
- pathSerializedPtr = (NSVGpathSerialized *) svgBlobPtr;
- svgBlobPtr += serializedHeaderPtr->pathCount * sizeof(NSVGpathSerialized);
- ptsSerializedPtr = (float *) svgBlobPtr;
- svgBlobPtr += serializedHeaderPtr->ptsCount * sizeof(float);
- gradientSerializedPtr = (NSVGgradientSerialized *) svgBlobPtr;
- svgBlobPtr += serializedHeaderPtr->gradientCount *
- sizeof(NSVGgradientSerialized);
- gradientStopPtr = (NSVGgradientStop *) svgBlobPtr;
-
- r->bitmap = dst;
- r->width = w;
- r->height = h;
- r->stride = stride;
-
- if (w > r->cscanline) {
- r->cscanline = w;
- r->scanline = (unsigned char*)NANOSVG_realloc(r->scanline, w);
- if (r->scanline == NULL) return;
- }
-
- for (i = 0; i < h; i++)
- memset(&dst[i*stride], 0, w*4);
-
- for (shapeIndex = 0 ; shapeIndex < serializedHeaderPtr->shapeCount;
- shapeIndex++) {
- shape = &(shapeSerializedPtr[shapeIndex]);
- if (!(shape->flags & NSVG_FLAGS_VISIBLE))
- continue;
-
- if (shape->fill.type != NSVG_PAINT_NONE) {
- nsvg__resetPool(r);
- r->freelist = NULL;
- r->nedges = 0;
-
- nsvg__flattenShapeSerialized(r, shape->paths, pathSerializedPtr, ptsSerializedPtr,
- scale);
-
- // Scale and translate edges
- for (i = 0; i < r->nedges; i++) {
- e = &r->edges[i];
- e->x0 = tx + e->x0;
- e->y0 = (ty + e->y0) * NSVG__SUBSAMPLES;
- e->x1 = tx + e->x1;
- e->y1 = (ty + e->y1) * NSVG__SUBSAMPLES;
- }
-
- // Rasterize edges
- qsort(r->edges, r->nedges, sizeof(NSVGedge), nsvg__cmpEdge);
-
- // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
- nsvg__initPaintSerialized(&cache, &shape->fill, shape->opacity,
- gradientSerializedPtr, gradientStopPtr);
-
- nsvg__rasterizeSortedEdges(r, tx,ty,scale, &cache, shape->fillRule);
+ NSVGcache *cachePtr = GetCachePtr(interp);
+
+ if (cachePtr != NULL) {
+ cachePtr->dataOrChan = NULL;
+ Tcl_DStringSetLength(&cachePtr->formatString, 0);
+ if (cachePtr->nsvgImage != NULL) {
+ nsvgDelete(cachePtr->nsvgImage);
+ cachePtr->nsvgImage = NULL;
}
- if (shape->stroke.type != NSVG_PAINT_NONE && (shape->strokeWidth * scale) > 0.01f) {
- nsvg__resetPool(r);
- r->freelist = NULL;
- r->nedges = 0;
-
- nsvg__flattenShapeStrokeSerialized(r, shape, pathSerializedPtr,
- ptsSerializedPtr, scale);
-
- // dumpEdges(r, "edge.svg");
-
- // Scale and translate edges
- for (i = 0; i < r->nedges; i++) {
- e = &r->edges[i];
- e->x0 = tx + e->x0;
- e->y0 = (ty + e->y0) * NSVG__SUBSAMPLES;
- e->x1 = tx + e->x1;
- e->y1 = (ty + e->y1) * NSVG__SUBSAMPLES;
- }
+ }
+}
- // Rasterize edges
- qsort(r->edges, r->nedges, sizeof(NSVGedge), nsvg__cmpEdge);
+/*
+ *----------------------------------------------------------------------
+ *
+ * FreeCache --
+ *
+ * This function is called to clean up the internal cache data.
+ *
+ * Results:
+ *
+ * Side effects:
+ * Existing image data in the cache and the cache will be deleted.
+ *
+ *----------------------------------------------------------------------
+ */
- // now, traverse the scanlines and find the intersections on each scanline, use non-zero rule
- nsvg__initPaintSerialized(&cache, &shape->stroke, shape->opacity,
- gradientSerializedPtr, gradientStopPtr);
+static void
+FreeCache(ClientData clientData, Tcl_Interp *interp)
+{
+ NSVGcache *cachePtr = (NSVGcache *)clientData;
+ (void)interp;
- nsvg__rasterizeSortedEdges(r, tx,ty,scale, &cache, NSVG_FILLRULE_NONZERO);
- }
+ Tcl_DStringFree(&cachePtr->formatString);
+ if (cachePtr->nsvgImage != NULL) {
+ nsvgDelete(cachePtr->nsvgImage);
}
-
- nsvg__unpremultiplyAlpha(dst, w, h, stride);
-
- r->bitmap = NULL;
- r->width = 0;
- r->height = 0;
- r->stride = 0;
+ ckfree(cachePtr);
}
diff --git a/generic/tkInt.h b/generic/tkInt.h
index ae25937..c3fe72f 100644
--- a/generic/tkInt.h
+++ b/generic/tkInt.h
@@ -1061,7 +1061,7 @@ MODULE_SCOPE void (*tkHandleEventProc) (XEvent* eventPtr);
MODULE_SCOPE Tk_PhotoImageFormat tkImgFmtDefault;
MODULE_SCOPE Tk_PhotoImageFormatVersion3 tkImgFmtPNG;
MODULE_SCOPE Tk_PhotoImageFormat tkImgFmtPPM;
-MODULE_SCOPE Tk_PhotoImageFormatVersion3 tkImgFmtSVGnano;
+MODULE_SCOPE Tk_PhotoImageFormat tkImgFmtSVGnano;
MODULE_SCOPE TkMainInfo *tkMainWindowList;
MODULE_SCOPE Tk_ImageType tkPhotoImageType;
MODULE_SCOPE Tcl_HashTable tkPredefBitmapTable;
diff --git a/generic/tkWindow.c b/generic/tkWindow.c
index 2adb0fa..aaa4a06 100644
--- a/generic/tkWindow.c
+++ b/generic/tkWindow.c
@@ -340,7 +340,7 @@ CreateTopLevelWindow(
Tk_CreatePhotoImageFormatVersion3(&tkImgFmtGIF);
Tk_CreatePhotoImageFormatVersion3(&tkImgFmtPNG);
Tk_CreatePhotoImageFormat(&tkImgFmtPPM);
- Tk_CreatePhotoImageFormatVersion3(&tkImgFmtSVGnano);
+ Tk_CreatePhotoImageFormat(&tkImgFmtSVGnano);
}
if ((parent != NULL) && (screenName != NULL) && (screenName[0] == '\0')) {
diff --git a/tests/imgPhoto.test b/tests/imgPhoto.test
index 5f71b9a..f0cd730 100644
--- a/tests/imgPhoto.test
+++ b/tests/imgPhoto.test
@@ -2249,170 +2249,7 @@ test imgPhoto-23.6 {Two GIF comment blocks (-file)} -setup {
file delete $path
} -result {comment ABCD}
-test imgPhoto-23.7 {XMP comment block before image (-data)} -setup {
- set data $::gifstart
- # Append an XMP comment extension block (including a Unicode codepoint 2022
- set xmpdata "<rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"\
- xmlns:xmp=\"http://ns.adobe.com/xap/1.0/\">\
- <rdf:Description rdf:about=\"1\u2022\">\
- <xmp:Rating>3</xmp:Rating></rdf:Description></rdf:RDF>"
- append data "\x21\xff\x0B" "XMP DataXMP" [encoding convertto utf-8 $xmpdata]
- # Special trailer of 1 ff fe ... 02 01 00 00
- append data "\x01"
- for {set i 0xff} {$i != -1} {incr i -1} {
- append data [binary format c $i]
- }
- append data "\x00"
-
- append data $::gifdata
- # Trailer
- append data $::gifend
-} -body {
- image create photo gif1 -data $data
- set d [dict get [gif1 cget -metadata] XMP]
- expr {$d eq $xmpdata}
-} -cleanup {
- catch {image delete gif1}
-} -result {1}
-
-test imgPhoto-23.8 {XMP comment block before image (-file)} -setup {
- set data $::gifstart
- # Append an XMP comment extension block (including a Unicode codepoint 2022
- set xmpdata "<rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"\
- xmlns:xmp=\"http://ns.adobe.com/xap/1.0/\">\
- <rdf:Description rdf:about=\"1\u2022\">\
- <xmp:Rating>3</xmp:Rating></rdf:Description></rdf:RDF>"
- append data "\x21\xff\x0B" "XMP DataXMP" [encoding convertto utf-8 $xmpdata]
- # Special trailer of 1 ff fe ... 02 01 00 00
- append data "\x01"
- for {set i 0xff} {$i != -1} {incr i -1} {
- append data [binary format c $i]
- }
- append data "\x00"
-
- append data $::gifdata
- # Trailer
- append data $::gifend
- set path [file join [configure -tmpdir] test.gif]
- set h [open $path "WRONLY BINARY CREAT"]
- puts $h $data
- close $h
-} -body {
- image create photo gif1 -file $path
- set d [dict get [gif1 cget -metadata] XMP]
- expr {$d eq $xmpdata}
-} -cleanup {
- catch {image delete gif1}
- file delete $path
-} -result {1}
-
-test imgPhoto-23.9 {XMP comment block after image (-data)} -setup {
- set data $::gifstart
- append data $::gifdata
-
- # Append an XMP comment extension block (including a Unicode codepoint 2022
- set xmpdata "<rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"\
- xmlns:xmp=\"http://ns.adobe.com/xap/1.0/\">\
- <rdf:Description rdf:about=\"1\u2022\">\
- <xmp:Rating>3</xmp:Rating></rdf:Description></rdf:RDF>"
- append data "\x21\xff\x0B" "XMP DataXMP" [encoding convertto utf-8 $xmpdata]
- # Special trailer of 1 ff fe ... 02 01 00 00
- append data "\x01"
- for {set i 0xff} {$i != -1} {incr i -1} {
- append data [binary format c $i]
- }
- append data "\x00"
-
- # Trailer
- append data $::gifend
-} -body {
- image create photo gif1 -data $data
- set d [dict get [gif1 cget -metadata] XMP]
- expr {$d eq $xmpdata}
-} -cleanup {
- catch {image delete gif1}
-} -result {1}
-
-test imgPhoto-23.10 {XMP comment block after image (-file)} -setup {
- set data $::gifstart
- append data $::gifdata
-
- # Append an XMP comment extension block (including a Unicode codepoint 2022
- set xmpdata "<rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"\
- xmlns:xmp=\"http://ns.adobe.com/xap/1.0/\">\
- <rdf:Description rdf:about=\"1\u2022\">\
- <xmp:Rating>3</xmp:Rating></rdf:Description></rdf:RDF>"
- append data "\x21\xff\x0B" "XMP DataXMP" [encoding convertto utf-8 $xmpdata]
- # Special trailer of 1 ff fe ... 02 01 00 00
- append data "\x01"
- for {set i 0xff} {$i != -1} {incr i -1} {
- append data [binary format c $i]
- }
- append data "\x00"
-
- # Trailer
- append data $::gifend
-
- set path [file join [configure -tmpdir] test.gif]
- set h [open $path "WRONLY BINARY CREAT"]
- puts $h $data
- close $h
-} -body {
- image create photo gif1 -file $path
- set d [dict get [gif1 cget -metadata] XMP]
- expr {$d eq $xmpdata}
-} -cleanup {
- catch {image delete gif1}
- file delete $path
-} -result {1}
-
-test imgPhoto-23.11 {empty XMP comment block after image (-data)} -setup {
- set data $::gifstart
- append data $::gifdata
-
- append data "\x21\xff\x0B" "XMP DataXMP"
- # Special trailer of 1 ff fe ... 02 01 00 00
- append data "\x01"
- for {set i 0xff} {$i != -1} {incr i -1} {
- append data [binary format c $i]
- }
- append data "\x00"
- # Trailer
- append data $::gifend
-} -body {
- image create photo gif1 -data $data
- dict get [gif1 cget -metadata] XMP
-} -cleanup {
- catch {image delete gif1}
-} -result {}
-
-test imgPhoto-23.12 {empty XMP comment block after image (-file)} -setup {
- set data $::gifstart
- append data $::gifdata
-
- append data "\x21\xff\x0B" "XMP DataXMP"
- # Special trailer of 1 ff fe ... 02 01 00 00
- append data "\x01"
- for {set i 0xff} {$i != -1} {incr i -1} {
- append data [binary format c $i]
- }
- append data "\x00"
- # Trailer
- append data $::gifend
-
- set path [file join [configure -tmpdir] test.gif]
- set h [open $path "WRONLY BINARY CREAT"]
- puts $h $data
- close $h
-} -body {
- image create photo gif1 -file $path
- dict get [gif1 cget -metadata] XMP
-} -cleanup {
- catch {image delete gif1}
- file delete $path
-} -result {}
-
-test imgPhoto-23.13 {create: test if shared metadata object is not preserved\
+test imgPhoto-23.7 {create: test if shared metadata object is not preserved\
(-data)}\
-setup {
set data $::gifstart
@@ -2429,7 +2266,7 @@ test imgPhoto-23.13 {create: test if shared metadata object is not preserved\
catch {image delete gif1}
} -result {{A 1 comment ABCD} {A 1} {A 1}}
-test imgPhoto-23.14 {create: test if shared metadata object is not preserved\
+test imgPhoto-23.8 {create: test if shared metadata object is not preserved\
(-file)}\
-setup {
set data $::gifstart
@@ -2452,7 +2289,7 @@ test imgPhoto-23.14 {create: test if shared metadata object is not preserved\
file delete $path
} -result {{A 1 comment ABCD} {A 1} {A 1}}
-test imgPhoto-23.15 {configure: test if shared metadata object is not\
+test imgPhoto-23.9 {configure: test if shared metadata object is not\
preserved (empty image, -data)}\
-setup {
set data $::gifstart
@@ -2470,7 +2307,7 @@ test imgPhoto-23.15 {configure: test if shared metadata object is not\
catch {image delete gif1}
} -result {{A 1 comment ABCD} {A 1} {A 1}}
-test imgPhoto-23.16 {configure: test if shared metadata object is not preserved\
+test imgPhoto-23.10 {configure: test if shared metadata object is not preserved\
(empty image, -file)}\
-setup {
set data $::gifstart
@@ -2494,7 +2331,7 @@ test imgPhoto-23.16 {configure: test if shared metadata object is not preserved\
file delete $path
} -result {{A 1 comment ABCD} {A 1} {A 1}}
-test imgPhoto-23.17 {configure: test if shared metadata object is not preserved\
+test imgPhoto-23.11 {configure: test if shared metadata object is not preserved\
(metadata replace, -data}\
-setup {
set data $::gifstart
@@ -2512,7 +2349,7 @@ test imgPhoto-23.17 {configure: test if shared metadata object is not preserved\
catch {image delete gif1}
} -result {{A 1 comment ABCD} {A 1} {A 1}}
-test imgPhoto-23.18 {configure: test if shared metadata object is not preserved\
+test imgPhoto-23.12 {configure: test if shared metadata object is not preserved\
(metadata replace, -file}\
-setup {
set data $::gifstart
@@ -2536,7 +2373,7 @@ test imgPhoto-23.18 {configure: test if shared metadata object is not preserved\
file delete $path
} -result {{A 1 comment ABCD} {A 1} {A 1}}
-test imgPhoto-23.19 {configure: test if shared metadata object is not preserved\
+test imgPhoto-23.13 {configure: test if shared metadata object is not preserved\
(-data)}\
-setup {
set data $::gifstart$::gifdata$::gifend
@@ -2555,7 +2392,7 @@ test imgPhoto-23.19 {configure: test if shared metadata object is not preserved\
catch {image delete gif1}
} -result {{A 1 comment ABCD} {A 1} {A 1}}
-test imgPhoto-23.20 {configure: test if shared metadata object is not preserved\
+test imgPhoto-23.14 {configure: test if shared metadata object is not preserved\
(-file)}\
-setup {
set data $::gifstart
@@ -2579,7 +2416,7 @@ test imgPhoto-23.20 {configure: test if shared metadata object is not preserved\
file delete $path
} -result {{A 1 comment ABCD} {A 1} {A 1}}
-test imgPhoto-23.21 {output data with comment (from -metadata argument)}\
+test imgPhoto-23.15 {output data with comment (from -metadata argument)}\
-setup {
set data $::gifstart$::gifdata$::gifend
} -body {
@@ -2604,7 +2441,7 @@ test imgPhoto-23.22 {output file with comment (from -metadata argument)}\
file delete $path
} -result {ABCD}
-test imgPhoto-23.23 {output data with comment (from -metadata property)}\
+test imgPhoto-23.16 {output data with comment (from -metadata property)}\
-setup {
set data $::gifstart$::gifdata$::gifend
} -body {
@@ -2615,7 +2452,7 @@ test imgPhoto-23.23 {output data with comment (from -metadata property)}\
catch {image delete gif1}
} -match glob -result {*ABCD*}
-test imgPhoto-23.24 {output file with comment (from -metadata property)}\
+test imgPhoto-23.17 {output file with comment (from -metadata property)}\
-setup {
set data $::gifstart$::gifdata$::gifend
set path [file join [configure -tmpdir] test.gif]
@@ -2631,44 +2468,7 @@ test imgPhoto-23.24 {output file with comment (from -metadata property)}\
file delete $path
} -result {ABCD}
-test imgPhoto-23.25 {output data with XMP (-data)} -setup {
- set data $::gifstart$::gifdata$::gifend
- set XMPData\
- "<rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"\
- xmlns:xmp=\"http://ns.adobe.com/xap/1.0/\">\
- <rdf:Description rdf:about=\"1\u2022\">\
- <xmp:Rating>3</xmp:Rating></rdf:Description></rdf:RDF>"
-} -body {
- image create photo gif1 -data $data
- set gifData [gif1 data -format gif -metadata [dict create\
- XMP $XMPData]]
- image delete gif1
- image create photo gif1 -data $gifData
- expr {[dict get [gif1 cget -metadata] XMP] eq $XMPData}
-} -cleanup {
- catch {image delete gif1}
-} -result {1}
-
-test imgPhoto-23.24 {output data with XMP (-file)} -setup {
- set data $::gifstart$::gifdata$::gifend
- set XMPData\
- "<rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\"\
- xmlns:xmp=\"http://ns.adobe.com/xap/1.0/\">\
- <rdf:Description rdf:about=\"1\u2022\">\
- <xmp:Rating>3</xmp:Rating></rdf:Description></rdf:RDF>"
- set path [file join [configure -tmpdir] test.gif]
-} -body {
- image create photo gif1 -data $data
- set gifData [gif1 write $path -format gif -metadata [dict create\
- XMP $XMPData]]
- image delete gif1
- image create photo gif1 -file $path
- expr {[dict get [gif1 cget -metadata] XMP] eq $XMPData}
-} -cleanup {
- catch {image delete gif1}
-} -result {1}
-
-test imgPhoto-23.25 {configure: empty metadata parameter overwrites image metadata} -setup {
+test imgPhoto-23.18 {configure: empty metadata parameter overwrites image metadata} -setup {
image create photo gif1 -data $::gifstart$::gifdata$::gifend\
-metadata {foo bar}
set data $::gifstart
@@ -2683,7 +2483,7 @@ test imgPhoto-23.25 {configure: empty metadata parameter overwrites image metada
catch {image delete gif1}
} -result {comment ABCD}
-test imgPhoto-23.26 {write: empty metadata parameter overwrites image metadata} -setup {
+test imgPhoto-23.19 {write: empty metadata parameter overwrites image metadata} -setup {
image create photo gif1 -data $::gifstart$::gifdata$::gifend\
-metadata {comment bar}
set path [file join [configure -tmpdir] test.gif]
@@ -2697,7 +2497,7 @@ test imgPhoto-23.26 {write: empty metadata parameter overwrites image metadata}
file delete $path
} -result {0}
-test imgPhoto-23.27 {data: empty metadata parameter overwrites image metadata} -setup {
+test imgPhoto-23.20 {data: empty metadata parameter overwrites image metadata} -setup {
image create photo gif1 -data $::gifstart$::gifdata$::gifend\
-metadata {comment bar}
} -body {
diff --git a/tests/imgSVGnano.test b/tests/imgSVGnano.test
index f34316b..ff7046a 100644
--- a/tests/imgSVGnano.test
+++ b/tests/imgSVGnano.test
@@ -23,36 +23,10 @@ namespace eval svgnano {
<polyline fill="red" stroke="purple" points="80,10 90,20 85,40"/>
<polygon fill ="yellow" points="80,80 70,85 90,90"/>
</svg>}
-
set data(bad) {<svg xmlns="http://www.w3.org/2000/svg" width="0" height="0:w
">
</svg>}
- set data(gradient) {<svg
- xmlns="http://www.w3.org/2000/svg"
- height="10"
- width="10">
- <defs
- id="defs7">
- <linearGradient
- gradientTransform="rotate(90)"
- id="myGradient">
- <stop
- id="stop2"
- stop-color="gold"
- offset="5%" />
- <stop
- id="stop4"
- stop-color="red"
- offset="95%" />
- </linearGradient>
- </defs>
- <rect
- id=""
- style="fill:url(#myGradient)"
- x="0" y="0" width="10" height="10" rx="0" ry="0" />
-</svg>}
-
tcltest::makeFile $data(plus) plus.svg
set data(plusFilePath) [file join [tcltest::configure -tmpdir] plus.svg]
@@ -233,96 +207,6 @@ test imgSVGnano-4.2 {error on file not accessible on reread due to configure} -s
tcltest::removeFile tmpplus.svg
} -returnCodes error -match glob -result {couldn't open "*/tmpplus.svg": no such file or directory}
-# rendering tests
-
-test imgSVGnano-5.0 {data gradient rendering} -setup {
- catch {rename foo ""}
- catch {rename gif ""}
- image create photo gif\
- -data "R0lGODlhCgAKALMAANnZ2f/XAP/LAP+yAP+zAP+bAP+DAP9rAP9TAP9UAP88AP8kAP8MAP///////////yH5BAEAAAAALAAAAAAKAAoAAAQhMMhJhb14DMI7L2AoGmRpHmiqImyLJLAiz/Ri3zij73wEADs="\
- -format gif
-} -body {
- image create photo foo -data $data(gradient)
- set res ""
- for {set y 0} {$y < [image height foo]} {incr y} {
- for {set x 0} {$x < [image width foo]} {incr x} {
- lassign [foo get $x $y] r1 g1 b1
- lassign [gif get $x $y] r2 g2 b2
- if {$r1 != $r2 || $g1 != $g2 || $b1 != $b2} {
- append res "pixel $x,$y unequal: $r1 $g1 $b1 != $r2 $g2 $b2\n"
- }
- }
- }
- set res
-} -cleanup {
- rename foo ""
- rename gif ""
-} -result {}
-
-test imgSVGnano-5.1 {file gradient rendering} -setup {
- catch {rename foo ""}
- tcltest::makeFile $data(gradient) tmpgradient.svg
- catch {rename gif ""}
- image create photo gif\
- -data "R0lGODlhCgAKALMAANnZ2f/XAP/LAP+yAP+zAP+bAP+DAP9rAP9TAP9UAP88AP8kAP8MAP///////////yH5BAEAAAAALAAAAAAKAAoAAAQhMMhJhb14DMI7L2AoGmRpHmiqImyLJLAiz/Ri3zij73wEADs="\
- -format gif
-} -body {
- image create photo foo -file [file join [tcltest::configure -tmpdir] tmpgradient.svg]
- set res ""
- for {set y 0} {$y < [image height foo]} {incr y} {
- for {set x 0} {$x < [image width foo]} {incr x} {
- lassign [foo get $x $y] r1 g1 b1
- lassign [gif get $x $y] r2 g2 b2
- if {$r1 != $r2 || $g1 != $g2 || $b1 != $b2} {
- append res "pixel $x,$y unequal: $r1 $g1 $b1 != $r2 $g2 $b2\n"
- }
- }
- }
- set res
-} -cleanup {
- rename foo ""
- tcltest::removeFile tmpgradient.svg
- rename gif ""
-} -result {}
-
-# metadata tests
-
-test imgSVGnano-6.0 {svgblob metadata creation} -setup {
- catch {rename foo ""}
- tcltest::makeFile $data(plus) tmpplus.svg
-} -body {
- image create photo foo -file [file join [tcltest::configure -tmpdir] tmpplus.svg]
- dict keys [foo cget -metadata]
-} -cleanup {
- rename foo ""
- tcltest::removeFile tmpplus.svg
-} -result {SVGBLOB}
-
-test imgSVGnano-6.1 {scale with svgblob metadata (data)} -setup {
- catch {rename foo ""}
-} -body {
- image create photo foo -data $data(plus)
- foo configure -data "<svg data=\"metadata\" />" -format "svg"
- foo configure -format "svg -scale 2"
- lappend res [image width foo] [image height foo]
-} -cleanup {
- rename foo ""
- tcltest::removeFile tmpplus.svg
-} -result {200 200}
-
-test imgSVGnano-6.2 {scale with svgblob metadata} -setup {
- catch {rename foo ""}
- tcltest::makeFile $data(plus) tmpplus.svg
-} -body {
- image create photo foo -file [file join [tcltest::configure -tmpdir] tmpplus.svg]
- foo configure -file "" -data "<svg data=\"metadata\" />"
- foo configure -format "svg -scale 2"
- list [image width foo] [image height foo]
-} -cleanup {
- rename foo ""
- tcltest::removeFile tmpplus.svg
-} -result {200 200}
-
};# end of namespace svgnano
namespace delete svgnano