TIP 507: Include simple svg support with nanosvg

Login
FlightAware bounty program for improvements to Tcl and certain Tcl packages.
Author:         René Zaumseil <r.zaumseil@freenet.de>
State:          Draft
Type:           Project
Vote:           
Created:        9-May-2018
Post-History:   
Keywords:       Tk
Tcl-Version:    8.7

Abstract

Tk needs scalable images on high res 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. 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. The out of the box image formats do not scale and are to tiny on high res mobile devices. The same goes for the image formats provided by the img extension.

There is already a Tk image extension at https://github.com/auriocus/tksvg The implementation is using nanosvg. 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 easily included
  • is really lightweight
  • is tested with tksvg
  • can render images
  • has no other external dependencies

The original nanosvg project is hosted at https://github.com/memononen/nanosvg

Specification

The already existing tksvg extension will be adapted and included in Tk. A new image format will be created. The name is svgnano. The choosen name hints the usage of a not fully compatible svg parser. It leaves the image name svg open for further usage.

The svgnano image format has the following format suboptions:

svgnano -dpi dpiValue -scale scaleValue -unit unitValue -x xValue -y yValue

dpiValue is used in conversion between given coordiantes 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.

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.

xValue is used to move the created image in x-direction. The default value is 0.

yValue is used to move the created image in y-direction. The default value is 0.

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 svgnano triggers error "image string format "svgnano" is not supported"

  2. $img configure -format {svgnano -scale 2} ; $img configure -format {svgnano -x 10} ; # the second call takes -scale as the default value (1)

Supported SVG

The svgnano 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

  • http://code.activestate.com/lists/tcl-core/19871/
  • http://code.activestate.com/lists/tcl-core/19994/

Open questions

  • Are all of the above format options necessary? May be remove the xValue and yValue options.

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 {svgnano -scale 2}
    # move right and up, all other values are reset
    foo configure -format {svgnano -x 10 -y -20}
    # use other unit
    foo configure -format {svgnano -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.