TIP 507: Include simple SVG support with nanosvg

Login
Bounty program for improvements to Tcl and certain Tcl packages.
Author:         René Zaumseil <r.zaumseil@freenet.de>
State:          Final
Type:           Project
Vote:           Done
Created:        9-May-2018
Post-History:   
Keywords:       Tk
Tcl-Version:    8.7
Tk-Branch:      tip-507
Votes-For:      DKF, JN, FV, SL, AK
Votes-Against:  none
Votes-Present:  none

Abstract

Tk needs scalable images on high resolution mobile devices. This TIP proposes to let Tk be able to read an SVG image (plus information about orientation and pixel scale) and make it into a photo image. It is therefore a (lossy and single direction) conversion operation from an SVG format to a pixel format.

Rationale

Tk is running on desktop and mobile devices. However, the out-of-the-box photo image formats do not scale and are too tiny on high resolution mobile devices. The same goes for the image formats provided by the Img extension.

The response to this challenge in general (on the web, in applications, etc.) has been to adopt the SVG format, as that is scalable and does not typically depend on being rendered at a particular resolution. Moreover, there is already a Tk image extension to do the conversion, tksvg. The implementation is using the nanosvg library. It has no other external dependencies and is only 2 header files.

nanosvg was choosen because it:

  • has a suitable license
  • is written in 2 plain C header files and can be easily included
  • is really lightweight
  • is tested with tksvg
  • can render images
  • has no other external dependencies

Specification

The already existing tksvg extension will be adapted and included in Tk. A new photo image format will be created. The photo image format name is svg. The new format will support a small list of options. Note that scope still exists in the future for full integration of SVG as its own full image type (which would allow more options for rendering) instead of having the side-trip via the photo image's pixel buffer, but this is out of scope of this TIP. A description of the features and limitations of the current implementation is in section Supported SVG. It will be also described in the photo(n) man page.

The svg image format has the following format suboptions:

svg -dpi dpiValue -scale scaleValue -unit unitValue

dpiValue is used in conversion between given coordinates and screen resolution. The value must be greater then 0.0. The default value is 96.

scaleValue is used to scale the resulting image. The value must be greater then 0.0. The default value is 1.0.

unitValue is the unit of all coordinates in the svg data. Available units are px (default, coordinates in pixel), pt (1/72 inch), pc (12 pt), mm, cm and in.

The given format options are only used at creation time of the image and are not preserved in the image. This means that:

  1. $img data -format svg triggers the error "image string format "svg" is not supported"; Tk cannot convert a photo image into an SVG.

  2. In this:

    $img configure -format {svg -scale 2}
    $img configure -format {svg -dpi 96}
    

    the second call takes -scale as the default value (1).

There is no intention to provide a reverse mechanism for saving a photo image as an SVG image.

Supported SVG

The svg format supports a wide range of SVG features, however some features (e.g. 'text') are missing and silently ignored when reading the SVG data.

Elements

  • g
  • path
  • rect
  • circle
  • ellipse
  • line
  • polyline
  • polygon
  • linearGradient
  • radialGradient
  • stop
  • defs
  • svg
  • style

Attributes

  • width, height
  • viewBox
  • preserveAspectRatio with none, xMin, xMid, xMax, yMin, yMid, yMax, slice

Gradient Attributes

  • gradientUnits with objectBoundingBox
  • gradientTransform
  • cx, cy, r
  • fx, fy
  • x1, y1, x2, y2
  • spreadMethod with pad, reflect or repeat
  • xlink:href

Poly Attributes

  • points

Line Attributes

  • x1, y1, x2, y2

Ellipse Attributes

  • cx, cy
  • rx, ry

Circle Attributes

  • cx, cy
  • r

Rectangle Attributes

  • x, y
  • width, height
  • rx, ry

Path Attributes

  • d with m, M, l, L, h, H, v, V, c, C, s, S, q, Q, t, T, a, A, z, Z

Style Attributes

  • display with none, visibility, hidden, visible
  • fill with nonzero, evenodd
  • opacity
  • fill-opacity
  • stroke
  • stroke-width
  • stroke-dasharray
  • stroke-dashoffset
  • stroke-opacity
  • stroke-linecap with butt, round, square
  • stroke-linejoin with miter, round, bevel
  • stroke-miterlimit
  • fill-rule
  • font-size
  • transform with matrix, translate, scale, rotate, skewX, skewY
  • stop-color
  • stop-opacity
  • offset
  • id
  • class

Discussion

In http://code.activestate.com/lists/tcl-core/19994/ François Vogel mentioned his concerns.

  • A.1 Alternatives are described here at the end.
  • A.2 The interface is small (-format ...). Other, better implementations could provide it also.
  • A.3 is now described in section "Supported SVG" above.
  • A.4 The following, not necessary needed option will be removed:
    • -x xValue is used to move the created image in x-direction. The default value is 0.
    • -y yValue is used to move the created image in y-direction. The default value is 0.
  • B.3 svg
  • B.4 has the fix surfaced?
  • C is about better documentation

Thread http://code.activestate.com/lists/tcl-core/19871/ is about compilers.

Thread http://code.activestate.com/lists/tcl-core/19985/ was the last discussion.

http://code.activestate.com/lists/tcl-core/20110/ and http://code.activestate.com/lists/tcl-core/20111/ talk about a better solution, not using the photo comand and instead making a p.e. svg command with full functionality (especially writing). This is imho out of scope of this tip. It should be addressed in a separate tip. If done so the new function can then be used to support the functionality in this tip.

There was some discussion on the further usage and maintenance of this image type. Here are the current state of the implementation in this area:

  • This tip will provide an readonly display of svg images with a limited set of funtionality described above.
  • The created image will have no information about the SVG data and format options.
  • The included nanosvg header files will be remain diffable to the original ones. So changes in the original project can be ported to our implementation.
  • The format options will be limited to a minimum. So the implementation can later be substituted with a full SVG compatible one.
  • If the implamenation will be replaced it will occur in a different tk version. So there is no need to create a scpecial variable describing the used SVG implementation.
  • To further reduce the interface it is possible to remove the -dpi and -unit options. There is currently no demand for this.

Implementation

A patch implementing these changes is available in the fossil repository in the tip-507 branch.

The new format is described in the photo(n) man page.

Example of use

# the image data
set data {<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>}
# create image
image create photo foo -data $data
# change size
foo configure -format {svg -scale 2}
# change dpi value
foo configure -format {svg -dpi 96}
# use other unit
foo configure -format {svg -unit mm}

Alternatives

  • Use of another library with full SVG support instead of the current proposal for partial support: could be done as a further step.

  • Direct manipulation of SVG vector graphics (as opposed to the present proposal of converting SVG to pixel format in a photo) would be desirable. However this can always be done later, for instance in the frame of the canvas widget. It is deemed an already large improvement to have Tk be able to read SVG images and convert them to pixel-based photos.

Copyright

This document has been placed in the public domain.

History