commit | 9e70acc10e1278cad60c1a7bef64bc90965bc494 | [log] [tgz] |
---|---|---|

author | Nigel Tao <nigeltao@golang.org> | Sun May 30 16:29:44 2021 +1000 |

committer | Nigel Tao <nigeltao@golang.org> | Wed Jun 02 13:01:15 2021 +0000 |

tree | 5ac94cec6a76edf78c65a8ff70e357a570cf6ce5 | |

parent | b47a03e3048a16e5877dea02cf86e143e549fc46 [diff] |

shiny/iconvg: link to the canonical spec Change-Id: Ib006cf872d79acf785fa5bffde9b8e32bcf5439b Reviewed-on: https://go-review.googlesource.com/c/exp/+/323550 Reviewed-by: Rob Pike <r@golang.org> Trust: Nigel Tao <nigeltao@golang.org>

diff --git a/shiny/iconvg/doc.go b/shiny/iconvg/doc.go index a16871a..559b040 100644 --- a/shiny/iconvg/doc.go +++ b/shiny/iconvg/doc.go

@@ -8,656 +8,14 @@ WARNING: THIS FORMAT IS EXPERIMENTAL AND SUBJECT TO INCOMPATIBLE CHANGES. -It is similar in concept to SVG (Scalable Vector Graphics) but much simpler. -Compared to "SVG Tiny", it does not have features for text, multimedia, -interactivity, linking, scripting, animation, XSLT, DOM, combination with -raster graphics such as JPEG formatted textures, etc. +A longer overview is at +https://github.com/google/iconvg -It is a format for efficient presentation, not an authoring format. For -example, it does not provide grouping individual paths into higher level -objects. Instead, the anticipated workflow is that artists use other tools and -authoring formats like Inkscape and SVG, or commercial equivalents, and export -IconVG versions of their assets, the same way that they would produce PNG -versions of their vector art. It is not a goal to be able to recover the -original SVG from a derived IconVG. +The file format is specified at +https://github.com/google/iconvg/blob/main/spec/iconvg-spec.md -It is not a pixel-exact format. Different implementations may produce slightly -different renderings, due to implementation-specific rounding errors in the -mathematical computations when rasterizing vector paths to pixels. Artifacts -may appear when scaling up to extreme sizes, say 1 million by 1 million pixels. -Nonetheless, at typical scales, e.g. up to 4096 × 4096, such differences are -not expected to be perceptible to the naked eye. - -The encoder aims to emit byte-identical output for the same input, independent -of the platform (and specifically its floating-point hardware). - - -Structure - -An IconVG graphic consists of a magic identifier, one or more metadata bytes -then a sequence of variable length instructions for a virtual machine. - -Those instructions encode a sequence of filled paths, similar to SVG path data -(https://www.w3.org/TR/SVG/paths.html#PathData). Rendering involves switching -between two modes: a styling mode where color registers are set, and a drawing -mode where a path's geometry is defined. The virtual machine starts in the -styling mode. - -In both modes, rendering proceeds by reading a one byte opcode followed by a -variable number of data bytes for that opcode. The mapping from byte values to -opcodes depends on whether the renderer is in the styling or drawing mode. A -0x07 byte value means setting the color selector register in the styling mode, -and means adding multiple lineto segments in the drawing mode. - - -Level of Detail - -The machine state includes 2 level of detail registers, denoted LOD0 and LOD1, -both float32 values, initialized to +0 and +infinity. Drawing mode opcodes have -no effect (other than leaving drawing mode) unless the height H in pixels of -the rasterization satisfies LOD0 <= H and H < LOD1. - -This allows the format to provide a simpler version for small rasterizations -(e.g. below 32 pixels) and a more complex version for large rasterizations -(e.g. 32 and above pixels). - - -Registers - -The machine state includes 64 color registers (denoted CREG[0], CREG[1], ..., -CREG[63]) and 64 number registers (denoted NREG[0], NREG[1], ..., NREG[63]). -Register indexing is done modulo 64, so CREG[70] is the same as CREG[6], and -CREG[-1] is the same as CREG[63]. - -Each CREG and NREG register is 32 bits wide. The CREG registers are initialized -to the custom palette (see below); the NREG registers are initialized to 0. The -machine state also includes two selector registers, denoted CSEL and NSEL. They -are effectively 6 bit integers, as they index CREG and NREG, and are also -initialized to 0. - -Color registers are four uint8 values: red, green, blue and alpha. - -Number registers are float32 values. - - -Colors and Gradients - -IconVG graphics work in 32 bit alpha-premultiplied color, with 8 bits for red, -green, blue and alpha. Alpha-premultiplication means that c00000c0 represents a -75%-opaque, fully saturated red. - -It also means that some RGBA combinations (where e.g. the red value is greater -than the alpha value) are nonsensical. The virtual machine re-purposes some of -those values to represent gradients instead of flat colors. Any color register -whose alpha value is zero but whose blue value is at least 128 is a gradient. -Its remaining bits are reinterpreted such that: - -The low 6 bits of the red value is the number of color/offset stops, NSTOPS. - -The high 2 bits of the red value are reserved. - -The low 6 bits of the green value is the color register base, CBASE. - -The high 2 bits of the green value is how to spread the gradient past its -nominal bounds (from offset being 0.0 to offset being 1.0). The high two bits -being 0, 1, 2 or 3 mean none, pad, reflect and repeat respectively. None means -that offsets outside of the [0.0, 1.0] range map to transparent black. Pad -means that offsets below 0.0 and above 1.0 map to the colors that 0.0 and 1.0 -would map to. Reflect means that the offset mapping is reflected start-to-end, -end-to-start, start-to-end, etc. Repeat means that the offset mapping is -repeated start-to-end, start-to-end, start-to-end, etc. - -The low 6 bits of the blue value is the number register base, NBASE. - -The remaining bit (the 0x40 bit) of the blue value denotes the gradient shape: -0 means a linear gradient and 1 means a radial gradient. - -The gradient has NSTOPS color/offset stops. The first stop has color -CREG[CBASE+0] and offset NREG[NBASE+0], the second stop has color CREG[CBASE+1] -and offset NREG[NBASE+1], and so on. - -The gradient also uses the six numbers from NREG[NBASE-6] to NREG[NBASE-1], -which form an affine transformation matrix [a, b, c; d, e, f] such that -a=NREG[NBASE-6], b=NREG[NBASE-5], c=NREG[NBASE-4], etc. This matrix maps from -graphic coordinate space (defined by the metadata's viewBox) to gradient -coordinate space. Gradient coordinate space is where a linear gradient ranges -from x=0 to x=1, and a radial gradient has center (0, 0) and radius 1. - -The graphic coordinate (px, py) maps to the gradient coordinate (dx, dy) by: - - dx = a*px + b*py + c - dy = d*px + e*py + f - -The appendix below gives explicit formulae for the [a, b, c; d, e, f] affine -transformation matrix for common gradient geometry, such as a linear gradient -defined by two points. - -At the time a gradient is used to fill a path, it is invalid for any of the -stop colors to be out of alpha-premultiplied range (where red, green or blue is -greater than alpha), including referencing another gradient. It is also invalid -for any stop offset to be less than or equal to a previous offset, or outside -the range [0, 1]. - - -Colors - -Color register values are always 32 bits, or 4 bytes. Colors in the instruction -byte stream can be encoded more compactly, and are encoded in either 1, 2, 3 or -4 bytes, depending on context. For example, some opcodes are followed by a 1 -byte color, others by a 2 byte color. There are two forms of 3 byte colors: -direct and indirect. - -For a 1 byte encoding, byte values in the range [0, 125) encode the RGBA color -where the red, green and blue values come from the base-5 encoding of that byte -value such that 0, 1, 2, 3 and 4 map to 0x00, 0x40, 0x80, 0xc0, 0xff. The alpha -value is 0xff. For example, the color 40ffc0ff can be encoded as 0x30, as -decimal 48 equals 1*25 + 4*5 + 3. A byte value of 125, 126 or 127 mean the -colors c0c0c0c0, 80808080 and 00000000 respectively. Byte values in the range -[128, 192) mean a color from the custom palette (indexed by that byte value -minus 128). Byte values in the range [192, 256) mean the value of a CREG color -register (with CREG indexed by that byte value minus 192). - -For a 2 byte encoding, the red, green, blue and alpha values are all 4 bit -values. For example, the color 338800ff can be encoded as 0x38 0x0f. - -For a 3 byte direct encoding, the red, green and blue values are all 8 bit -values. The alpha value is implicitly 255. For example, the color 306607ff can -be encoded as 0x30 0x66 0x07. - -For a 4 byte encoding, the red, green, blue and alpha values are all 8 bit -values. For example, the color 30660780 is simply 0x30 0x66 0x07 0x80. - -For a 3 byte indirect encoding, the first byte is an integer value in the range -[0, 255] (denoted T) and the second and third bytes are each a 1 byte encoded -color (denoted C0 and C1). The resultant color's red channel value is given by: - RESULTANT.RED = (((255-T) * C0.RED) + (T * C1.RED) + 128) / 255 -rounded down to an integer value (the mathematical floor function), and -likewise for the green, blue and alpha channels. For example, if the custom -palette's third entry is a fully opaque orange, then 0x40 0x7f 0x82 encodes a -25% percent opaque orange: a blend of 75% times fully transparent (1 byte color -0x7f) and 25% times a fully opaque orange (1 byte color 0x82). - -It is valid for some encodings to yield a color value where the red, green or -blue value is greater than the alpha value, as this may be a gradient. If it -isn't a valid gradient, it is equivalent to transparent black and drawing with -that color is a no-op. - - -Palettes - -Rendering an IconVG graphic can be varied by a 64 color palette. For example, -an emoji graphic may be rendered with palette color 0 for skin and palette -color 1 for hair. Decorative variations, such as different clothing, can be -implemented by palette colors possibly set to completely transparent to switch -paths off. - -Rendering software should allow users to pass an optional 64 color palette. If -one isn't provided, the suggested palette (either given in the metadata or the -default consisting entirely of opaque black) should be used. Whichever palette -ends up being used is designated the custom palette. - -Some user-given colors may be nonsensical as alpha-premultiplied colors, where -e.g. the red value is greater than the alpha value. Such colors are replaced by -opaque black and not re-interpreted as gradients. - -Assigning names such as "skin", "hair" or "bow_tie" to the integer indexes of -that 64 color palette is out of scope of the IconVG format per se. - - -Numbers - -Like colors, numbers are encoded in the instruction stream in either 1, 2 or 4 -bytes. Unlike colors, the encoding length is not determined by context. -Instead, the low two bits of the first byte indicate the encoding length. - -If the least significant bit (the 0x01 bit) of the first byte is 0, the number -is encoded in 1 byte. Otherwise, it is encoded in 2 or 4 bytes depending on the -second least significant bit (the 0x02 bit) of the first byte being 0 or 1. - - -Natural Numbers - -For a 1 byte encoding, the remaining 7 bits form an integer value in the range -[0, 1<<7). For example, 0x28 encodes the value 0x14 or, in decimal, 20. - -For a 2 byte encoding, the remaining 14 bits, interpreted as little endian, -form an integer in the range [0, 1<<14). For example, 0x59 0x83 encodes the -value 0x20d6 or, in decimal, 8406. - -For a 4 byte encoding, the remaining 30 bits, interpreted as little endian, -form an integer in the range [0, 1<<30). For example, 0x07 0x00 0x80 0x3f -encodes the value 0xfe00001 or, in decimal, 266338305. - - -Real Numbers - -The encoding of a real number resembles the encoding of a natural number. For 1 -and 2 byte encodings, the decoded real number equals the decoded natural -number. For example, 0x28 encodes the real number 20.0, just as it encodes the -natural number 20. - -For a 4 byte encoding, the decoded natural number, in the range [0, 1<<30), is -shifted left by 2, to make a uint32 value that is a multiple of 4. The decoded -real number is the floating point number corresponding to the IEEE 754 binary -representation of that uint32 (i.e. a reinterpretation as a float32). For -example, 0x07 0x00 0x80 0x3f encodes the value 1.000000476837158203125. - -It is valid for the 4 byte encoding to represent infinities and NaNs, but if -not loaded into LOD0 or LOD1, the subsequent rendering is undefined. - - -Coordinate Numbers - -The encoding of a coordinate number resembles the encoding of a real number. -For 1 and 2 byte encodings, the decoded coordinate number equals (R*scale - -bias), where R is the decoded real number as above. The scale and bias depends -on the number of bytes in the encoding. - -For a 1 byte encoding, the scale is 1 and the bias is 64, so that a 1 byte -coordinate ranges in [-64, +64) at integer granularity. For example, the -coordinate 7 can be encoded as 0x8e. - -For a 2 byte encoding, the scale is 1/64 and the bias is 128, so that a 2 byte -coordinate ranges in [-128, +128) at 1/64 granularity. For example, the -coordinate 7.5 can be encoded as 0x81 0x87. - -For a 4 byte encoding, the decoded coordinate number simply equals R. For -example, the coordinate 7.5 can also be encoded as 0x03 0x00 0xf0 0x40. - - -Zero-to-One Numbers - -A zero-to-one number is a real number that is typically in the range [0, 1], -although it is valid for a value to be outside of that range. For example, -angles are expressed as a zero-to-one number: a fraction of a complete -revolution (360 degrees). Gradient stop offsets are another example. - -The encoding of a zero-to-one number resembles the encoding of a real number. -For 1 and 2 byte encodings, the decoded number equals R*scale, where R is the -decoded real number as above. The scale depends on the number of bytes in the -encoding. - -For a 1 byte encoding, the real number (ranging up to 128) is scaled by 1/120. -The denominator is 2*2*2 * 3 * 5, so that 15 degrees (2*π/24 radians) can be -encoded as 0x0a. - -For a 2 byte encoding, the real number (ranging up to 16384) is scaled by -1/15120. The denominator is 2*2*2*2 * 3*3*3 * 5 * 7. For example, 40 degrees -(2*π/9 radians) can be encoded as 0x41 0x1a. - -For a 4 byte encoding, the decoded zero-to-one number simply equals R. For -example, 1 degree (2*π/360 radians), or 0.002777777..., can be approximated by -the encoding 0x63 0x0b 0x36 0x3b. - - -Magic Identifier - -An IconVG graphic starts with the four bytes 0x89 0x49 0x56 0x47 ("\x89IVG"). - - -Metadata - -The encoded metadata starts with a natural number (see encoding above) of the -number of metadata chunks in the metadata, followed by that many chunks. Each -chunk starts with the length remaining in the chunk (again, encoded as a -natural number), not including the chunk length itself. After that is a MID -(Metadata Identifier) natural number, then MID-specific data. Chunks must be -presented in increasing MID order. MIDs cannot be repeated. All MIDs are -optional. - - -MID 0 - ViewBox - -Metadata Identifier 0 means that the MID-specific data contains four coordinate -values (see above for the coordinate encoding). These are the minX, minY, maxX, -maxY of the graphic's viewBox: its bounding rectangle in (scalable) vector -space. Note that these are abstract units, and not necessarily 1:1 with pixels. -If this MID is not present, the viewBox defaults to (-32, -32, +32, +32). A -viewBox is invalid if minX > maxX or if minY > maxY or if at least one of those -four values are a NaN or an infinity. - - -MID 1 - Suggested Palette - -Metadata Identifier 1 means that the MID-specific data contains a suggested -palette, e.g. to provide a default rendering of variable colors such as an -emoji's skin and hair. The suggested palette is encoded in at least one byte. -The low 6 bits of that byte form a number N. The high 2 bits denote the palette -color format: those high 2 bits being 0, 1, 2 or 3 mean 1, 2, 3 (direct) or 4 -byte colors (see above for the color encoding). The chunk then contains N+1 -explicit colors, in that 1, 2, 3 or 4 byte encoding. A palette has exactly 64 -colors, the 63-N implicit colors of the suggested palette are set to opaque -black. A 1 byte color that refers to the custom palette or a CREG color -register resolves to opaque black. If this MID is not present, the suggested -palette consists entirely of opaque black, as black is always fashionable. - - -Styling Opcodes - -Some opcode descriptions refer to an adjustment value, ADJ. That value is the -low three bits of the opcode, nominally in the range [0, 8), although in -practice the range is [0, 7) as no ADJ-using opcode has the low three bits set. - -Opcodes 0x00 to 0x3f sets CSEL to the low 6 bits of the opcode. - -Opcodes 0x40 to 0x7f sets NSEL to the low 6 bits of the opcode. - -Opcodes 0x80 to 0x86 sets CREG[CSEL-ADJ] to the 1 byte encoded color following -the opcode. - -Opcodes 0x88 to 0x8e sets CREG[CSEL-ADJ] to the 2 byte encoded color following -the opcode. - -Opcodes 0x90 to 0x96 sets CREG[CSEL-ADJ] to the 3 byte direct encoded color -following the opcode. - -Opcodes 0x98 to 0x9e sets CREG[CSEL-ADJ] to the 4 byte encoded color following -the opcode. - -Opcodes 0xa0 to 0xa6 sets CREG[CSEL-ADJ] to the 3 byte indirect encoded color -following the opcode. - -Opcodes 0x87, 0x8f, 0x97, 0x9f and 0xa7 sets CREG[CSEL] to the 1, 2, 3 -(direct), 4 and 3 (indirect) byte encoded color, following the opcode, and then -increments CSEL by 1. - -Opcodes 0xa8 to 0xae sets NREG[NSEL-ADJ] to the real number following the -opcode. - -Opcodes 0xb0 to 0xb6 sets NREG[NSEL-ADJ] to the coordinate number following the -opcode. - -Opcodes 0xb8 to 0xbe sets NREG[NSEL-ADJ] to the zero-to-one number following -the opcode. - -Opcode 0xaf, 0xb7 and 0xbf sets NREG[NSEL] to the real, coordinate and -zero-to-one number following the opcode, and then increments NSEL by 1. - -Opcodes 0xc0 to 0xc6 switches to the drawing mode, and is followed by two -coordinates that is the path's starting location. In effect, there is an -implicit M (absolute moveto) op. CREG[CSEL-ADJ], either a flat color or a -gradient, will fill the path once it is complete. - -Opcode 0xc7 sets the Level of Detail bounds LOD0 and LOD1 to the two real -numbers following the opcode. - -All other opcodes are reserved. - - -Drawing Opcodes - -The drawing model is based on SVG path data -(https://www.w3.org/TR/SVG/paths.html#PathData) and this description re-uses -SVG's one-letter mnemonics: M means absolute moveto, m means relative moveto, L -means absolute lineto, l means relative lineto, H means absolute horizontal -lineto, etc. Upper and lower case mean absolute and relative coordinates. The -upper case mnemonics of the SVG operations used in IconVG's drawing mode are: -M, Z, L, H, V, C, S, Q, T, A. - -IconVG differs from SVG with multiple consecutive moveto ops. SVG treats all -but the first one as lineto ops. IconVG treats them all as moveto ops. - -Almost all opcodes, i.e. those in the range [0x00, 0xdf], come in contiguous -groups of 16 or 32. For example, there are 16 Q (absolute quadratic Bézier -curveto) opcodes, from 0x60 to 0x6f. Those opcodes' meaning differ only in -their repeat count RC: how often that drawing operation is repeated. The lowest -valued opcode has a repeat count of 1, the next lowest has a repeat count of 2 -and so on. For example, the opcode 0x68 means 9 consecutive Q drawing ops. - -Opcodes 0x00 to 0x1f means RC consecutive L ops, for RC in [1, 32]. The opcode -is followed by 2*RC coordinates, RC sets of (x, y). - -Opcodes 0x20 to 0x3f are like the previous paragraph, except L (absolute) -becomes l (relative). - -Opcodes 0x40 to 0x4f means RC consecutive T ops, for RC in [1, 16]. The opcode -is followed by 2*RC coordinates, RC sets of (x, y). - -Opcodes 0x50 to 0x5f are like the previous paragraph, except T (absolute) -becomes t (relative). - -Opcodes 0x60 to 0x6f means RC consecutive Q ops, for RC in [1, 16]. The opcode -is followed by 4*RC coordinates, RC sets of (x1, y1, x, y). - -Opcodes 0x70 to 0x7f are like the previous paragraph, except Q (absolute) -becomes q (relative). - -Opcodes 0x80 to 0x8f means RC consecutive S ops, for RC in [1, 16]. The opcode -is followed by 4*RC coordinates, RC sets of (x2, y2, x, y). - -Opcodes 0x90 to 0x9f are like the previous paragraph, except S (absolute) -becomes s (relative). - -Opcodes 0xa0 to 0xaf means RC consecutive C ops, for RC in [1, 16]. The opcode -is followed by 6*RC coordinates, RC sets of (x1, y1, x2, y2, x, y). - -Opcodes 0xb0 to 0xbf are like the previous paragraph, except C (absolute) -becomes c (relative). - -Opcodes 0xc0 to 0xcf means RC consecutive A ops, for RC in [1, 16]. The opcode -is followed by 6*RC numbers, RC sets of (rx, ry, xAxisRotation, flags, x, y). -The rx, ry, x and y numbers are coordinates. The xAxisRotation number is an -angle (a zero-to-one number being a fraction of 360 degrees). The flags are -encoded as a natural number. The 0x01 bit of the decoded natural number is the -large-arc-flag and the 0x02 bit is the sweep-flag. - -Opcodes 0xd0 to 0xdf are like the previous paragraph, except A (absolute) -becomes a (relative). - -Opcode 0xe0 is reserved. (A future version of IconVG may use this opcode to -mean the same as 0xe1 without the one z op, which will matter for stroked -paths). - -Opcode 0xe1 means one z op and then end the path: fill the path with the color -chosen when we switched to the drawing mode, and switch back to the styling -mode. (The Z and z ops are equivalent). - -Opcode 0xe2 means one z op and then an implicit M op to the (x, y) coordinates -after the opcode. - -Opcode 0xe3 means one z op and then an implicit m op to the (x, y) coordinates -after the opcode. - -Opcodes 0xe4 and 0xe5 are reserved. (A future version of IconVG may use these -for M and m ops, if we allow stroked paths). - -Opcode 0xe6 means one H op to the x coordinate after the opcode. - -Opcode 0xe7 means one h op to the x coordinate after the opcode. - -Opcode 0xe8 means one V op to the y coordinate after the opcode. - -Opcode 0xe9 means one v op to the y coordinate after the opcode. - -All other opcodes are reserved. - -These opcode descriptions all assume that the Level of Detail constraint (see -above) is satisfied. If not, the opcodes and their variable length data are -consumed, but no further action is taken (other than leaving drawing mode). - - -Example - -The production version of the "action/info" icon from the Material Design icon -set is defined by the following SVG, also available at -https://github.com/google/material-design-icons/blob/3.0.2/action/svg/production/ic_info_48px.svg: - - <svg xmlns="http://www.w3.org/2000/svg" width="48" height="48" viewBox="0 0 48 48"> - <path d="M24 4C12.95 4 4 12.95 4 24s8.95 20 20 20 20-8.95 20-20S35.05 4 24 4z - m2 30h-4V22h4v12zm0-16h-4v-4h4v4z"/></svg> - -This is 202 bytes, or 174 bytes after "gzip --best". The PNG renderings at -various sizes: - - 18x18: 207 bytes - 24x24: 222 bytes - 36x36: 321 bytes - 48x48: 412 bytes - -The corresponding IconVG is 73 bytes: - - 89 49 56 47 02 0a 00 50 50 b0 b0 c0 80 58 a0 cf - cc 30 c1 58 58 cf cc 30 c1 58 80 91 37 33 0f 41 - a8 a8 a8 a8 37 33 0f c1 a8 58 80 cf cc 30 41 58 - 80 58 e3 84 bc e7 78 e8 7c e7 88 e9 98 e3 80 60 - e7 78 e9 78 e7 88 e9 88 e1 - -The annotated version is below. Note that the IconVG viewBox ranges from -24 to -+24 while the SVG viewBox ranges from 0 to 48. - - 89 49 56 47 IconVG Magic identifier - 02 Number of metadata chunks: 1 - 0a Metadata chunk length: 5 - 00 Metadata Identifier: 0 (viewBox) - 50 -24 - 50 -24 - b0 +24 - b0 +24 - c0 Start path, filled with CREG[CSEL-0]; M (absolute moveTo) - 80 +0 - 58 -20 - a0 C (absolute cubeTo), 1 reps - cf cc 30 c1 -11.049999 - 58 -20 - 58 -20 - cf cc 30 c1 -11.049999 - 58 -20 - 80 +0 - 91 s (relative smooth cubeTo), 2 reps - 37 33 0f 41 +8.950001 - a8 +20 - a8 +20 - a8 +20 - s (relative smooth cubeTo), implicit - a8 +20 - 37 33 0f c1 -8.950001 - a8 +20 - 58 -20 - 80 S (absolute smooth cubeTo), 1 reps - cf cc 30 41 +11.049999 - 58 -20 - 80 +0 - 58 -20 - e3 z (closePath); m (relative moveTo) - 84 +2 - bc +30 - e7 h (relative horizontal lineTo) - 78 -4 - e8 V (absolute vertical lineTo) - 7c -2 - e7 h (relative horizontal lineTo) - 88 +4 - e9 v (relative vertical lineTo) - 98 +12 - e3 z (closePath); m (relative moveTo) - 80 +0 - 60 -16 - e7 h (relative horizontal lineTo) - 78 -4 - e9 v (relative vertical lineTo) - 78 -4 - e7 h (relative horizontal lineTo) - 88 +4 - e9 v (relative vertical lineTo) - 88 +4 - e1 z (closePath); end path - -There are more examples in the ./testdata directory. - - -Appendix - Gradient Transformation Matrices - -This appendix derives the affine transformation matrices [a, b, c; d, e, f] for -linear, circular and elliptical gradients. - - -Linear Gradients - -For a linear gradient from (x1, y1) to (x2, y2), let dx, dy = x2-x1, y2-y1. In -gradient coordinate space, the y-coordinate is ignored, so the transformation -matrix simplifies to [a, b, c; 0, 0, 0]. It satisfies the three simultaneous -equations: - - a*(x1 ) + b*(y1 ) + c = 0 (eq L.0) - a*(x1+dy) + b*(y1-dx) + c = 0 (eq L.1) - a*(x1+dx) + b*(y1+dy) + c = 1 (eq L.2) - -Subtracting equation L.0 from equations L.1 and L.2 yields: - - a*dy - b*dx = 0 - a*dx + b*dy = 1 - -So that - - a*dy*dy - b*dx*dy = 0 - a*dx*dx + b*dx*dy = dx - -Overall: - - a = dx / (dx*dx + dy*dy) - b = dy / (dx*dx + dy*dy) - c = -a*x1 - b*y1 - d = 0 - e = 0 - f = 0 - - -Circular Gradients - -For a circular gradient with center (cx, cy) and radius vector (rx, ry), such -that (cx+rx, cy+ry) is on the circle, let - - r = math.Sqrt(rx*rx + ry*ry) - -The transformation matrix maps (cx, cy) to (0, 0), maps (cx+r, cy) to (1, 0) -and maps (cx, cy+r) to (0, 1). Solving those six simultaneous equations give: - - a = +1 / r - b = +0 / r - c = -cx / r - d = +0 / r - e = +1 / r - f = -cy / r - - -Elliptical Gradients - -For an elliptical gradient with center (cx, cy) and axis vectors (rx, ry) and -(sx, sy), such that (cx+rx, cx+ry) and (cx+sx, cx+sy) are on the ellipse, the -transformation matrix satisfies the six simultaneous equations: - - a*(cx ) + b*(cy ) + c = 0 (eq E.0) - a*(cx+rx) + b*(cy+ry) + c = 1 (eq E.1) - a*(cx+sx) + b*(cy+sy) + c = 0 (eq E.2) - d*(cx ) + e*(cy ) + f = 0 (eq E.3) - d*(cx+rx) + e*(cy+ry) + f = 0 (eq E.4) - d*(cx+sx) + e*(cy+sy) + f = 1 (eq E.5) - -Subtracting equation E.0 from equations E.1 and E.2 yields: - - a*rx + b*ry = 1 - a*sx + b*sy = 0 - -Solving these two simultaneous equations yields: - - a = +sy / (rx*sy - sx*ry) - b = -sx / (rx*sy - sx*ry) - -Re-arranging E.0 yields: - - c = -a*cx - b*cy - -Similarly for d, e and f so that, overall: - - a = +sy / (rx*sy - sx*ry) - b = -sx / (rx*sy - sx*ry) - c = -a*cx - b*cy - d = -ry / (rx*sy - sx*ry) - e = +rx / (rx*sy - sx*ry) - f = -d*cx - e*cy - -Note that if rx = r, ry = 0, sx = 0 and sy = r then this simplifies to the -circular gradient transformation matrix formula, above. +This package's encoder emits byte-identical output for the same input, +independent of the platform (and specifically its floating-point hardware). */ package iconvg