TIP 545: image photo SVG options: remove -unit and add target height/width option

Login
Bounty program for improvements to Tcl and certain Tcl packages.
Author:         Harald Oehlmann <oehhar@users.sourceforge.net>
State:          Final
Type:           Project
Vote:           Done
Created:        19-May-2019
Keywords:       Tk, image
Tcl-Version:    8.7
Tk-Branch:      tip-545-svg-options
Vote-Results:	6/0/0 accepted
Votes-For:	BG, DKF, FV, KW, JN, MC
Votes-Against:	none
Votes-Present:	none

Abstract

Image photo SVG support was added to Tk by TIP 507. This TIP is about the options of SVG rendering:

  • The option "-unit" is not helpful in an environment, where the only destination unit is pixel.
  • The option "-scale float" is the essential tool to set rendering scaling. Nevertheless, to scale to a given height or width, a two-step procedure is required. This common case should be implemented by a one step procedure.
  • A valid image file scaled to a size resulting to 0 px height or width does not lead to an error but to an image of at least 1x1 pixels. The aspect-ratio may not be respected.

Rationale

This TIP includes the following proposed changes:

Remove option "-unit"

Remove the option "-unit". The given unit is used to set the unit of the intermediate set of polygons.

The final unit will be pixels anyway, undependent on any intermediate unit. Image width and height is in pixel. There is no other unit available for image width or height.

The current implementation does the following:

  • the intermediate representation is scaled in the unit given by "-unit" using the current dpi value. The result depends on the unit used in the svg, to specified unit and the dpi value (96 or specified by -dpi).
  • the size of the image is evaluated by transforming the given unit into pixel
  • the image data is rendered by assuming (not transforming: 1 inch is set to 1 pixel) that unit is pixel. If it was not pixel, a scale effect is shown by accident.

Here is an example from the core list:

set data {<svg xmlns="http://www.w3.org/2000/svg" width="100" height="100"><circle fill="yellow" stroke="red" cx="50" cy="50" r="30" /></svg>}
set im [image create photo -data $data]
pack [button .b -image $im]
$im configure -format {svg -unit px}  ; # no change (this is the default)
$im configure -format {svg -unit mm}  ; # image gets scaled to a smaller image, but image size stays the same

# Set inner scale to one:
$im configure -format {svg -unit in -dpi 1}
image width $im
-> 100
# with the same result as no format option at all (e.g. "svg -unit px -dpi 96")

# Set inner scale to 0.1, but keep same size
$im configure -format {svg -unit in -dpi 10}
image width $im
-> 100
# but image data is scale by factor 0.1

# The standard way to get an image scaled by 0.1 but with size set to 100x100 is as follows:
set im2 [image create photo -data $data -format {svg -scale 0.1} -width 100 -height 100]
pack [button .b2 -image $im2]

Add a possibility to scale to a given width or height in pixels

A common usage of svg is to render button images for a given button height or width. Buttons of applications may have all the same height or width when aranged in button lines aranged horizontally or vertically.

The current solution to render a svg to a given height "$height" is:

image create photo p -file "test.svg"
set imageHeight [image height p]
p configure [list svg -scale [expr {double($height) / $imageHeight}]

This two step procedure has a high performance impact, as the image is loaded twice. The aim is to render it only once by one parameter.

No error on to small scale

It feels odd to throw an error on a valid image but on a to small combination of size and -scale parameter resulting in a rounded size of width 0 or height 0. Alternatively, a valid image with width 1 and/or height 1 is rendered.

As an alternate solution, an error message special for this case may be given.

Specification

Remove option "-unit"

Add new option -scaletoheight

The option "-scaletoheight entier" specifies the image height in pixels to scale to. The image width is found by the aspect-ratio.

Example with an image "test.svg" with an aspect ration of width:height = 2:1. The required height is 16 pixels:

% image create photo p -file "test.svg" -format {svg -scaletoheight 16}
p
% image height p
16
% image width p
32

The entier argument must be greater to 0. The option may not be specified together with "-scale" and/or "-scaletowidth".

Add new option -scaletowidth

The option "-scaletowidth entier" specifies the image width in pixels to scale to. The image height is found by the aspect-ratio.

Example with an image "test.svg" with an aspect ration of width:height = 2:1. The required width is 16 pixels:

% image create photo p -file "test.svg" -format {svg -scaletowidth 16}
p
% image width p
16
% image height p
8

The entier argument must be greater than 0. The option may not be specified together with "-scale" and/or "-scaletoheight".

No error on to small scale

The image size is set to height 1 and/or width 1 if width and/or height is 0 after scaling and rounding. This is a very rare case, as ceil rounding is used and we must go below the resolution of double to acheve this.

Implementation

Implementation is ready in branch tip-545-svg-options.

Discussion

This TIP was discussed at Euro-TCL 2019.

It was concluded that svg support is a good feature and helpful for modern gui design. The limitations of nanosvg are seen as ok.

It was concluded that there is no use case for the -unit option.

Rene has another use-case for visual graph generation. A svg file is created on the fly using the given data. This is then rendered and displayed by a label widget. This procedure is faster than the canvas or the tkpath widget (and has much less features). This solution is a good fit to this application.

Francois Vogel commented with his vote:

The TIP says "The image size is set to height 1 and/or width 1 if width and/or height is 0 after scaling and rounding.". Where is that statement implemented?

IMO this story is a leftover in the TIP from a previous mistake made in the implementation that I corrected later (details at https://sourceforge.net/p/tcl/mailman/message/36693070/ ). If so, I would prefer the TIP to be corrected so that it accurately reflects the implementation: all this story should be deleted throughout the TIP.

Copyright

This document has been placed in the public domain.

History