📜 ⬆️ ⬇️

SVG-files from the inside and the output of vector images on the canvas "manually" (Part 1)


This article is written in the wake of creating a plug-in for reading SVG files for the NanoFL animation vector editor. In it you will find some features of how the SVG files are arranged from the inside and what problems arise when they are parsed and then output to HTML5 / Canvas using JavaScript.


The SVG format has in fact become the standard for the exchange of vector graphics between various programs. Therefore, it was decided to make his support in NanoFL . In the process of such development, it is important to monitor the correctness of reading and interpreting files, for which a collection of SVG images of various subjects was downloaded from the site w3.org.

Overview of what's inside an SVG file


As everyone probably knows, SVG files contain simple text data in XML format. Therefore, they, theoretically, can be opened and edited in a regular text editor. Of course, in practice it only makes sense for quick edits in small files.
')
Here is an overview of what the SVG file can contain:

  1. Header ( <svg> ).
  2. Definitions ( <defs> ) - stored here are descriptions of gradients and objects that do not need to be output directly (immediately).
  3. The group ( <g> ) is the container for the elements to be drawn, which can be referenced if necessary.
  4. A vector shape ( <path> ) is a set of rules for drawing ("go to a given point", "draw a segment from the current position to a given point"). Both straight line segments, 2nd and 3rd order Bezier curves, and circular arcs are supported.
  5. Test ( <text> ) - single-line text (in SVG there is no full support for multi-line texts).
  6. Gradient ( <linearGradient> , <radialGradient> ).
  7. <clipPath> region ( <clipPath> ) - sets the shape that can be used for clipping during output.
  8. Pattern ( <pattern> ) - sets the shape with which you can fill in closed areas.
  9. Mask ( <mask> ) - specifies an object, alpha-values ​​of which pixels can be used when displaying an arbitrary object.
  10. Filter ( <filter> ) is one of the predefined ways of post-processing a given graphic element (for example, blurring it).
  11. Raster image ( <image> ).
  12. Animation (its support was not implemented in NanoFL and therefore is not covered in this article).

Below we look at the features of some of the elements mentioned above.

Headline


Usually has the following form:

 <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="100%" height="100%" viewBox="0 0 100 100"> 

Practical features:


Groups


A group is a container tag within which there can be almost any elements. It is used as a rule or to set some parameters (for example, fill, clipping region or filter) for all internal elements at once, or to subsequently be able to refer to these elements. A group resembles a symbol in the editor's library, which we can use several times, and modifying it when used (in order to refer to a group, the <use> tag is used). Below is an example of setting a group and using links to it.


 <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="100" height="100"> <defs> <g id="man"> <circle cx="16" cy="25" r="7"/> <path d="m7,44 a9,9 0,0,1 18,0 v20h-18z"/> </g> </defs> <use x="0" y="0" xlink:href="#man" /> <use x="50" y="-18" transform="rotate(15)" fill="blue" xlink:href="#man" /> </svg> 

Vector shapes


SVG uses several tags to define vector shapes: the universal <path> and private <polygon> , <circle> and <rect> . The following points are interesting:

  1. Lines of shapes can intersect (which is unacceptable for both Flash Pro and NanoFL).
  2. SVG supports two different methods for determining which of the resulting closed areas to be considered internal (and, accordingly, paint over):
    a) fill-type="nonzero" - a beam is fill-type="nonzero" from a point inside the region and the number of its intersections with the lines going clockwise and counterclockwise is considered separately; the region is painted if the numbers do not match;
    b) fill-type="evenodd" - a ray is fill-type="evenodd" from a point inside the region and counted as the number of intersections with the lines defining the boundary; the region is filled if the number of intersections is odd.

Both of these features were taken into account when implementing in NanoFL: all lines are broken at the intersection points and the figure is reconstructed in accordance with the specified method for selecting the fill option. If you just need to bring the object to the canvas , then there is no problem at all: Context2D.fill() supports both figures with self-intersections and an indication of the fill method.


 <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="500" height="300"> <defs> <g id="g" fill="orange" stroke="black"> <polygon points="47.773,241.534 123.868,8.466 200.427,241.534 7.784,98.208 242.216,98.208" /> </g> </defs> <use x="0" y="0" xlink:href="#g" fill-rule="nonzero" /> <use x="250" y="0" xlink:href="#g" fill-rule="evenodd" /> </svg> 

Patterns


You can paint closed regions in SVG with an arbitrary vector pattern. On canvas this is impossible: Context2D supports the creation of Context2D ; however, it is proposed to use raster images rather than vector ones in their quality. A bypass maneuver here can be rasterization of a vector on a canvas in memory, followed by filling it with a specified area. However, in the general case, this will lead to a serious loss of performance (since it is impossible to rasterize the pattern in advance and use it everywhere because of the ignorance of the scale of the object to be poured). Therefore, remembering that the patterns are rarely used in real artistic vector images, it was decided to abandon their support in the NanoFL.

Conclusion


SVG supports a rich set of possibilities for displaying vector images, however, not all of them have direct mapping to canvas related methods. Therefore, somewhere there is a sense in writing smart code that will do “like on SVG”, and somewhere, it may be worth refusing to support the functionality for the sake of performance.

The author will be glad to any constructive comments.

Source: https://habr.com/ru/post/276519/


All Articles