diff options
-rw-r--r-- | generic/tkImgSVGnano.c | 66 | ||||
-rw-r--r-- | tests/imgSVGnano.test | 65 |
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: |