summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--generic/tkImgSVGnano.c66
-rw-r--r--tests/imgSVGnano.test65
2 files changed, 100 insertions, 31 deletions
diff --git a/generic/tkImgSVGnano.c b/generic/tkImgSVGnano.c
index 26236da..73044c0 100644
--- a/generic/tkImgSVGnano.c
+++ b/generic/tkImgSVGnano.c
@@ -36,21 +36,6 @@ typedef struct {
} RastOpts;
/*
- * The format record for the SVG nano file format:
- */
-
-Tk_PhotoImageFormat tkImgFmtSVGnano = {
- "svgnano", /* name */
- FileMatchSVG, /* fileMatchProc */
- StringMatchSVG, /* stringMatchProc */
- FileReadSVG, /* fileReadProc */
- StringReadSVG, /* stringReadProc */
- NULL, /* fileWriteProc */
- NULL, /* stringWriteProc */
- NULL
-};
-
-/*
* Per interp cache of last NSVGimage which was matched to
* be immediately rasterized after the match. This helps to
* eliminate double parsing of the SVG file/string.
@@ -93,6 +78,21 @@ static void CleanCache(Tcl_Interp *interp);
static void FreeCache(ClientData clientData, Tcl_Interp *interp);
/*
+ * The format record for the SVG nano file format:
+ */
+
+Tk_PhotoImageFormat tkImgFmtSVGnano = {
+ "svgnano", /* name */
+ FileMatchSVG, /* fileMatchProc */
+ StringMatchSVG, /* stringMatchProc */
+ FileReadSVG, /* fileReadProc */
+ StringReadSVG, /* stringReadProc */
+ NULL, /* fileWriteProc */
+ NULL, /* stringWriteProc */
+ NULL
+};
+
+/*
*----------------------------------------------------------------------
*
* FileMatchSVG --
@@ -134,8 +134,8 @@ FileMatchSVG(
nsvgImage = ParseSVGWithOptions(interp, data, length, formatObj, &ropts);
Tcl_DecrRefCount(dataObj);
if (nsvgImage != NULL) {
- *widthPtr = ceil(nsvgImage->width * ropts.scale);
- *heightPtr = ceil(nsvgImage->height * ropts.scale);
+ *widthPtr = (int) ceil(nsvgImage->width * ropts.scale);
+ *heightPtr = (int) ceil(nsvgImage->height * ropts.scale);
if ((*widthPtr <= 0) || (*heightPtr <= 0)) {
nsvgDelete(nsvgImage);
return 0;
@@ -189,7 +189,7 @@ FileReadSVG(
if (Tcl_ReadChars(chan, dataObj, -1, 0) == -1) {
/* in case of an error reading the file */
Tcl_DecrRefCount(dataObj);
- Tcl_SetResult(interp, "read error", TCL_STATIC);
+ Tcl_SetObjResult(interp, Tcl_NewStringObj("read error", -1));
Tcl_SetErrorCode(interp, "TK", "IMAGE", "SVG", "READ_ERROR", NULL);
return TCL_ERROR;
}
@@ -239,8 +239,12 @@ StringMatchSVG(
data = Tcl_GetStringFromObj(dataObj, &length);
nsvgImage = ParseSVGWithOptions(interp, data, length, formatObj, &ropts);
if (nsvgImage != NULL) {
- *widthPtr = ceil(nsvgImage->width * ropts.scale);
- *heightPtr = ceil(nsvgImage->height * ropts.scale);
+ *widthPtr = (int) ceil(nsvgImage->width * ropts.scale);
+ *heightPtr = (int) ceil(nsvgImage->height * ropts.scale);
+ if ((*widthPtr <= 0) || (*heightPtr <= 0)) {
+ nsvgDelete(nsvgImage);
+ return 0;
+ }
if (!CacheSVG(interp, dataObj, formatObj, nsvgImage, &ropts)) {
nsvgDelete(nsvgImage);
}
@@ -337,7 +341,7 @@ ParseSVGWithOptions(
inputCopy = attemptckalloc(length+1);
if (inputCopy == NULL) {
- Tcl_SetResult(interp, "cannot alloc data buffer", TCL_STATIC);
+ Tcl_SetObjResult(interp, Tcl_NewStringObj("cannot alloc data buffer", -1));
Tcl_SetErrorCode(interp, "TK", "IMAGE", "SVG", "OUT_OF_MEMORY", NULL);
goto error;
}
@@ -359,10 +363,10 @@ ParseSVGWithOptions(
int optIndex;
/*
- * Ignore the "svg" part of the format specification.
+ * Ignore the "svgnano" part of the format specification.
*/
- if (!strcasecmp(Tcl_GetString(objv[0]), "svg")) {
+ if (!strcasecmp(Tcl_GetString(objv[0]), "svgnano")) {
continue;
}
@@ -426,9 +430,9 @@ ParseSVGWithOptions(
}
}
- nsvgImage = nsvgParse(inputCopy, unit, dpi);
+ nsvgImage = nsvgParse(inputCopy, unit, (float) dpi);
if (nsvgImage == NULL) {
- Tcl_SetResult(interp, "cannot parse SVG image", TCL_STATIC);
+ Tcl_SetObjResult(interp, Tcl_NewStringObj("cannot parse SVG image", -1));
Tcl_SetErrorCode(interp, "TK", "IMAGE", "SVG", "PARSE_ERROR", NULL);
goto error;
}
@@ -476,23 +480,23 @@ RasterizeSVG(
unsigned char *imgData;
Tk_PhotoImageBlock svgblock;
- w = ceil(nsvgImage->width * ropts->scale);
- h = ceil(nsvgImage->height * ropts->scale);
+ w = (int) ceil(nsvgImage->width * ropts->scale);
+ h = (int) ceil(nsvgImage->height * ropts->scale);
rast = nsvgCreateRasterizer();
if (rast == NULL) {
- Tcl_SetResult(interp, "cannot initialize rasterizer", TCL_STATIC);
+ Tcl_SetObjResult(interp, Tcl_NewStringObj("cannot initialize rasterizer", -1));
Tcl_SetErrorCode(interp, "TK", "IMAGE", "SVG", "RASTERIZER_ERROR",
NULL);
goto cleanAST;
}
imgData = attemptckalloc(w * h *4);
if (imgData == NULL) {
- Tcl_SetResult(interp, "cannot alloc image buffer", TCL_STATIC);
+ Tcl_SetObjResult(interp, Tcl_NewStringObj("cannot alloc image buffer", -1));
Tcl_SetErrorCode(interp, "TK", "IMAGE", "SVG", "OUT_OF_MEMORY", NULL);
goto cleanRAST;
}
- nsvgRasterize(rast, nsvgImage, ropts->x, ropts->y,
- ropts->scale, imgData, w, h, w * 4);
+ nsvgRasterize(rast, nsvgImage, (float) ropts->x, (float) ropts->y,
+ (float) ropts->scale, imgData, w, h, w * 4);
/* transfer the data to a photo block */
svgblock.pixelPtr = imgData;
svgblock.width = w;
diff --git a/tests/imgSVGnano.test b/tests/imgSVGnano.test
new file mode 100644
index 0000000..499a36f
--- /dev/null
+++ b/tests/imgSVGnano.test
@@ -0,0 +1,65 @@
+# This file is a Tcl script to test out the code in tkImgSVGnano.c, which reads
+# and write SVG-format image files for photo widgets. The files is organized
+# in the standard fashion for Tcl tests.
+#
+# Copyright (c) 2018 Rene Zaumseil
+# All rights reserved.
+
+package require tcltest 2.2
+namespace import ::tcltest::*
+eval tcltest::configure $argv
+tcltest::loadTestedCommands
+imageInit
+
+namespace eval svgnano {
+ variable data
+ set data(plus) {<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100">
+<path fill="none" stroke="#000000" d="M0 0 h16 v16 h-16 z"/>
+<path fill="none" stroke="#000000" d="M8 4 v 8 M4 8 h 8"/>
+<circle fill="yellow" stroke="red" cx="10" cy="80" r="10" />
+<ellipse fill="none" stroke="blue" stroke-width="3" cx="60" cy="60" rx="10" ry="20" />
+<line x1="10" y1="90" x2="50" y2="99"/>
+<rect fill="none" stroke="green" x="20" y="20" width="60" height="50" rx="3" ry="3"/>
+<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>}
+
+test imgSVGnano-1.1 {reading simple image} -setup {
+ catch {rename foo ""}
+} -body {
+ image create photo foo -data $data(plus)
+ list [image width foo] [image height foo]
+} -cleanup {
+ rename foo ""
+} -result {100 100}
+
+test imgSVGnano-1.2 {simple image with options} -setup {
+ catch {rename foo ""}
+} -body {
+ image create photo foo -data $data(plus) -format {svgnano -dpi 100 -scale 3}
+ list [image width foo] [image height foo]
+} -cleanup {
+ rename foo ""
+} -result {300 300}
+
+test imgSVGnano-2.1 {reading a bad image} -body {
+ image create photo foo -format svgnano -data $data(bad)
+} -returnCodes error -result {couldn't recognize image data}
+test imgSVGnano-2.2 {using bad option} -body {
+ image create photo -data $data(plus) -format {svgnano -scale 0}
+} -returnCodes error -result {couldn't recognize image data}
+
+};# end of namespace svgnano
+
+namespace delete svgnano
+imageFinish
+cleanupTests
+return
+
+# Local Variables:
+# mode: tcl
+# fill-column: 78
+# End: