SVG input
The SVG adapter, stitchcraft-svg, turns an SVG file into a Design
and a list of warnings. It reads what an SVG viewer draws, in millimetres, and reports what it leaves
out. The engine never sees SVG (architecture).
What becomes an element
- Shapes. Each
<path>,<rect>,<circle>,<ellipse>,<line>,<polyline>and<polygon>that paints becomes one element per paint. A fill becomes an area and a stroke becomes an outline. A<line>has no fill. - Where a shape starts. A running stitch starts where its path starts and runs the way it runs, and each basic shape starts and runs as Ink/Stitch reads it. A circle or an ellipse starts at its top and turns left on screen. SVG 2 starts it at its right and turns the other way, which only dashes or markers would show.
- Order. Elements follow document order, which is SVG’s paint order and the sewing order. A
shape’s fill is sewn before its stroke, as Ink/Stitch sews them, and the outline covers the fill’s edge.
When
paint-orderpaints the stroke first,SC-W0802says the fill is sewn first. - Groups.
<g>,<a>and<switch>pass their transform and style to their children. A<switch>draws only its first child whose conditions pass, as a viewer does. Ink/Stitch sews every child of a switch, and drops the transforms of the switch and of the elements above it (DEV-SVG-004). - Ids. An element’s id is
svg:<label>:fillorsvg:<label>:stroke. The label is the SVG element’sid, or<tag>@<n>for the n-th element of that kind. A repeated id gets~2,~3and so on (stitchcraft_core::Labels, as in the VectorCraft adapter). The adapter’s own diagnostics name the SVG element assvg:<label>. - Names. An
inkscape:labelbecomes the element’s name. - Automatic elements. Read with
--auto(Reading::auto), a shape with no attribute in Ink/Stitch’s namespace is an automatic element, whose stitches StitchCraft chooses by its width (image to embroidery,REQ-AUTO-001). The trim and stop of Ink/Stitch’s commands attached to it still apply. A shape with anyinkstitch:attribute is not automatic: it sews as its settings say once they are read (M8), and with the defaults until then. Read with--sort-colours(Reading::sort_colours), the design’s shapes with settings sew in the order StitchCraft chooses too (image to embroidery,REQ-AUTO-011).
Geometry and units
- The root’s
width,height,viewBoxandpreserveAspectRatiomap user units to millimetres. A user unit is a CSS pixel, 1/96 inch, unless they say otherwise. A root with only a width or only a height takes the other from its viewBox’s shape, as SVG 2 sizes an image, and a percentage counts as missing. Ink/Stitch takes both sides from the viewBox, in pixels, when either is missing (DEV-SVG-009). - A viewer ignores a root
width,heightorviewBoxthat is empty, and apreserveAspectRatiothat does not read. The adapter ignores them too, andSC-W0804names each. Awidth,heightorviewBoxthat does not read could put the design at any size, and the file is refused (SC-E0801). So is a size of 0 or less, and a viewBox with no area, in which a viewer draws nothing. - Transforms compose through every ancestor. The matrices use
stitchcraft_core::math, so the result is the same on every platform (determinism). - Path data is read as SVG viewers draw it, arcs included. An error in the data, or in the list of
points of a
<polyline>or<polygon>, ends the path at the error, andSC-W0804names it. inkex skips what is not a number in a list of points, and Ink/Stitch sews the rest (DEV-SVG-010). - A path has the subpaths a viewer draws. A move-to with nothing drawn after it is no subpath, and a
command that draws after a closepath starts a new subpath where the closed one started. inkex keeps
such a move-to as a subpath of one point and runs the closed subpath on, so Ink/Stitch can count other
subpaths, which tell a satin column’s rails from its rungs (
DEV-SVG-011). - An arc becomes cubic curves as inkex, which Ink/Stitch reads files with, cuts it: in equal pieces, one
more than the whole quarter turns it makes. Manual stitch puts a needle point on each piece’s end, as
Ink/Stitch’s does. inkex counts the quarter turns in floating point, and its rounding can cut an arc of
a whole number of quarter turns into one piece fewer (
DEV-SVG-002). - A
<circle>or an<ellipse>starts at its top and goes round anticlockwise on screen, as inkex draws it, so a stroke round it starts and runs as Ink/Stitch’s does. - A
<rect>with one radius rounds its corners with it, and one with a radius of 0 has square corners. An<ellipse>with one radius is a circle of that radius. That is how SVG 2 draws them. inkex rounds a rect whoserxorryis 0 with the other, and takes an ellipse’s missing radius as 0 (DEV-SVG-006). - Positions are exact to within a micrometre (
REQ-SVG-001). Any path data reads without failing the adapter, and fuzzing checks it (REQ-SVG-002). - A length may have spaces around it. One that does not read is 0, as in a viewer, and
SC-W0804names it. A percentage is of the viewport’s width, height or diagonal over √2, anemis 16 user units and anex8, as with a viewer’s default font. inkex reads them as 0 in a shape’s attributes (DEV-SVG-005).
Colour and visibility
fill,stroke,colorandcurrentColorgive the thread colour. A gradient gives its first colour and a pattern its fallback colour, each with a warning. A gradient of one colour, such as an Inkscape swatch, gives that colour without one. A gradient without stops paints nothing, as in a viewer, and so does a reference to an element the file does not have, unless a colour is written after it. Ink/Stitch sews such a fill in black (DEV-SVG-007).- Colours read as editors write them. Keywords such as
currentcolormay be in any case. An ICC colour after the sRGB one, which Inkscape’s colour-managed picker writes, is left for the sRGB colour. - Properties come from presentation attributes (
fill="red"), the rules of style sheets and thestyleattribute, in the order of CSS’s cascade, as in a viewer (REQ-SVG-006). A rule overrides a presentation attribute, and thestyleattribute overrides a rule. Of 2 rules, the more specific one applies (more ids, then more classes, then an element name), and of 2 as specific, the later one. An!importantdeclaration overrides all of these. A paint, colour, stroke width, join or miter limit that does not read gives way to the next declaration, as in CSS. When none of an element’s paints reads, the inherited paint stays, andSC-W0802names the value. inkex takes the declaration the cascade puts first whether it reads or not, and Ink/Stitch sews a fill whose colour does not read in black and leaves such a stroke out (DEV-SVG-008).display,visibility,opacity,fill-opacity,stroke-opacity,fill-ruleandpaint-orderare read as inkex reads them, from the declaration the cascade puts first. A value there that does not read is ignored, and the declarations after it are not used, where a viewer would use the next one. - Style sheets are the
<style>elements of the file, wherever they are, whose type is CSS. Illustrator and CorelDRAW write a drawing’s colours as classes there. The adapter reads a rule whose selector is an element name or*followed by classes and ids, such asrect,.cls-1,#logoorpath.st0.st1. It reads a list of such selectors, such as.a, .b, as well. OneSC-W0802names the other selectors, such asg > rectora:hover, and the at-rules, such as@mediaand@import. What they set is not used. Ink/Stitch reads styles through inkex, which applies more kinds of selector. display: nonehides an element and everything in it. A hidden or fully transparent paint is left out, as a viewer leaves it out.visibilityhides a paint, and so does anopacityof 0 on its element or above it. Afill-opacityorstroke-opacityof 0 makes its paint clear, as does a colour that istransparentor has an alpha of 0. Ink/Stitch leaves out only whatdisplayhides and a fill whosefill-opacityis written0(DEV-SVG-003). The insides of<defs>,<symbol>,<marker>,<pattern>,<clipPath>and<mask>are never drawn.
Stroke width and join
A stroke’s width and join give a satin column drawn as one path its width and its corners
(single-path satin). Other strokes are sewn along their paths,
however wide they are drawn. Both are read as Ink/Stitch reads them (REQ-SVG-004), except an automatic
element’s join, read as SVG draws it. Its cap matters only to an automatic element, whose stitches cover
the line as it is drawn (REQ-AUTO-003).
- Width. The width is
stroke-width, inherited, 1 user unit when nothing sets it. It is a length in the shape’s own user units, as in a viewer, and a percentage is of the viewport’s diagonal over √2. The transforms down to the shape scale it by the average of how far they stretch the x and y axes. That is exact when they scale both axes alike. Under an uneven scale or a skew, a viewer draws the stroke wider one way than the other, and the average is the middle way. An automatic line sewn across its width is then as wide as that average all along.SC-W0802names such a line (REQ-AUTO-005). The transforms scale a stroke withvector-effect: non-scaling-stroketoo, as Ink/Stitch scales it, though a viewer does not. - Join.
roundandbevelare read as they are named. Amiterjoin is limited bystroke-miterlimit, 4 when nothing sets it, as SVG says. Any other join, or none, is a miter limited at 5, as in Ink/Stitch. SVG 2’smiter-clipandarcscount as other joins. An automatic element’s corners follow the drawing instead (REQ-AUTO-004). There, a join that is not set is SVG’s initial miter, limited bystroke-miterlimit, and so aremiter-clipandarcs, which few viewers draw. - Cap.
stroke-linecap, inherited,buttwhen nothing sets it:butt,roundorsquare, in any case. Ink/Stitch sews no cap, and reads none. - Values that do not read. A width, join or limit that does not read is ignored, as a viewer
ignores it, and
SC-W0804names it. A cap that does not read is ignored too, without a word: it changes nothing for a shape with settings. A negative width and a limit below 1 do not read. A stroke too wide to measure, such as1e308in, is left out withSC-W0804. Its fill is still sewn.
Ink/Stitch reads a width in %, em or ex as 0, and a join written in capitals as no join at all. The
adapter reads them as a viewer draws them (DEV-SVG-001).
Ink/Stitch objects
An Ink/Stitch SVG has 3 kinds of object that Ink/Stitch reads and does not sew. The adapter sews none of
them (REQ-SVG-003).
- Commands. The
trimandstopcommands turn on the object’strim_afterandstop_after. Theignore_objectandignore_layercommands leave out an object or a layer, as theinkstitch:ignore_objectsetting does when it says yes in one of Ink/Stitch’s words, which a toggle reads too, andSC-I0805lists each object left out. Thestarting_pointandending_pointcommands, which place where Ink/Stitch starts and ends a fill or a satin column, are not applied yet (REQ-GEN-001), andSC-W0802names each one on an object a viewer shows. The command table gives what the adapter does with each of the 12 commands. - Connectors tie a command to its object.
- Helper paths have one of Ink/Stitch’s start markers. They steer the stitches of other objects.
SC-W0802 reports a connector that ties no command, a helper path, and a command that the adapter does
not apply yet. The module docs of crates/stitchcraft-svg/src/inkstitch.rs describe how the adapter
finds these objects, with the Ink/Stitch files they were read from.
Design settings
Ink/Stitch keeps 3 settings for the whole design in the file’s first <metadata> element:
collapse_len_mm, min_stitch_len_mm and min_satin_stroke_width_mm. Each is an element of
Ink/Stitch’s namespace whose text is the value in millimetres, and the first of each name counts. They
become the design’s collapse length, shortest stitch and narrowest satin stroke (REQ-SVG-005).
SC-W0802 names a value that is not a number of 0 or more, and the design keeps its default. The
defaults are in the data model. The settings’
names, with the label and help a dialog shows, are listed once in stitchcraft_engine::design::SETTINGS,
which a VectorCraft document’s settings are read with too
(integration).
Reports
SC-W0802reports a feature that is not stitched. Text, images, clones, nested<svg>elements and the style sheet rules that are not read are such features. So are clipping, masks, filters, markers and the Ink/Stitch settings that are not read yet. Clipping is planned for M8.SC-W0804reports geometry that cannot be used:- path data or a list of points with an error, stitched up to the error
- a transform that does not parse, left out with its contents
- an element that draws nothing
- a point more than 10 m from the origin
- a stroke width, join or miter limit that does not read, and a stroke too wide to measure
- an empty root
width,heightorviewBox, and a rootpreserveAspectRatiothat does not read
SC-E0801refuses a file that is not SVG, or that is larger than the adapter reads. It refuses a file whose size cannot be used too: a rootwidth,heightorviewBoxthat does not read, a size of 0 or less, or a viewBox with no area.
Text and limits
A file is UTF-8 text, or ISO-8859-1 when its XML declaration says so, which the adapter turns into UTF-8. A file in any other encoding is refused when it has a byte outside ASCII.
A file is at most 64 MiB with a million XML nodes, and its style sheets have at most a million selectors,
declarations and at-rules. Illustrator declares its namespaces as XML entities, and an entity whose value
is plain text is read. A file is refused when an entity’s value holds markup or other entities, or when
its references would expand the file past 64 MiB. Without these rules a small file could need a large
amount of memory. Only the document type declaration’s internal subset, <!DOCTYPE svg [ … ]>, declares
entities: a declaration in a comment or in character data declares nothing. A name declared twice counts
at its longer value. XML keeps the first declaration, and the limit must hold whichever the parser keeps.
Reading charges the budget for each XML node, path segment and 8 bytes of a transform, point list or
style sheet. Each element is charged for its classes, the style sheet rules tested against it and the
declarations it takes (budgets).