TinyVG: A challenger to the throne of vector graphics
zig.news
zig.news
https://www.getlazarus.org/videos/physics/blueprint/
The rendering in my library relies upon OpenGL and the NanoVG library. My library is called Tiny Sim. All of these nano tiny and vg names seem to be colliding adding a bit of confusion in my opinion.
How does eps really compare with the other formats mentioned above?
The big problem with PS, EPS and Flash as simple graphics formats is that they're all turing complete and you can author documents that will never terminate. When importing EPS, Illustrator used to have a timeout and would fail if the render didn't complete in a couple minutes. I assume it still does, but haven't tried it in years.
Animation is issue #2 on https://github.com/google/iconvg and I have some ideas but no code yet. I'm also midway through changing the current "version 0" format into a "version 1" format, dropping things like the ArcTo op (inspired by SVG) precisely with one eye on (future) animation support. The ArcTo large-arc-flag, like any boolean-typed value, is impossible to interpolate smoothly.
Ideally though, the tiny* formats should be forward compatible (?) and interpretable as a valid non-Tiny* document. That would be quite nice for wider adoption (like JSON).
A compressed, paginated and indexed postscript file is not complex.
It's not very well known, but it's so elegant, and also efficient, especially for scanned files.
Looking at the website, it seems like the file format is OSS but the creation side of things is proprietary?
But yes, SVG is extremely bloated and under-documented. Especially SVG 2. The core resvg codebase is close to 20 KLOC, while the whole package is like 50 KLOC.
On the other hand, resvg is an exception, because it doesn't rely on any system and/or 3rd party libraries. 95% of the code in the final binary was written by one person (me). Not because it was strictly required, but because it was fun. resvg is basically an epitome of RIIR.
Just because I had to lookup this, for me, new acronym.
> A small nitpick as the resvg author: the repo located here https://github.com/RazrFalcon/resvg
Oh, i didn't see this. Thanks for some more correct and real numbers, i will correct them in the article later!
> I'm not sure why the author linked some random, outdated fork.
because it appears way higher up on the google search if you search for "svg rendering library". Sorry i didn't recognize that it's a fork!
Nice work then! I should check it out for SVG rendering and parsing.
How much work would it be to port over the C# SVG→TinyVG converter to Rust based on resvg? Considering that you already have a well done parser compared to mine...
Probably a day, as long as you know Rust. I can take a look into it if you're interested. usvg (the SVG parser of resvg) is specifically designed to convert a real world SVG with all its quirks into a machine readable, minimal SVG/XML.
One thing to note is that usvg doesn't preserve text at the moment (will be converted into paths automatically) and Quadratic curves.
PS: I also have a longer, but still unfinished rant [0] over SVG complexity if you're interested.
[0] https://github.com/RazrFalcon/resvg/blob/master/docs/renderi...
I mean, that sounds perfect in my ears as TinyVG doesn't has text/font support anyways and you need to perform the conversion at one point or another.
> Probably a day, as long as you know Rust. I can take a look into it if you're interested
That would be rad! I'll try to do that myself as well, but my last experience with Rust is over two years away, so i'd be happy to see a pro doing the work!
Your effort to create a lightweight vector file format with these features is really appreciable, even if it can never replace SVG for the more general use case. Anyway the tiger has rendering problems (I am quite obsessed with this tiger: even my rasterizer initially did not draw it correctly).
Spoiler: I'm one of the developers of AmanithSVG - http://www.amanithsvg.com
TinyVG doesn't implement node referencing. In SVG it is done by the `clone` operation, which creates SVG node that references original shape. Using this you can build smart scenes with shadows, reflections, arrayed clones and other interesting effects. It's like DRY principle for art; you can later modify the original shape and see changes reflected in other parts of the scene.
TinyVG doesn't even seem to have object groups. If I wanted to draw a gauge and control needle rotation in runtime I would have to manually re-compute path coordinates each frame. In SVG I would group all parts the gauge needle, and in each frame I would update just the rotation angle in group transform.
For a vector format to de-throne the SVG I would expect it to be smarter than SVG while discarding legacy features. I'd like to see things like infinitely large dimensions for shapes (shapes for ground and sky, or a ray of sun), specifying design constraints, interactivity and procedural animations. IMO the TinyVG takes vector graphics into wrong direction, as a boring subset of SVG.
Edit: I like that TinyVG takes form of very readable lisp-like data description language. Maybe it could be used as a starting point for a smarter vector format for authoring graphics and not just for distributing the end results.
Most uses today of SVG, that I have seen in the wild are icons, graphs and diagrams. Which this TinyVG covers beautifully. Especially for embeded (TinyVG's authors motivation for this) you often need some icons.
Sure if you need something more complex keep using SVG, or create something new. But for 80% - 90% off web and embedded its enough.
> TinyVG doesn't implement node referencing. In SVG it is done by the `clone` operation, which creates SVG node that references original shape. Using this you can build smart scenes with shadows, reflections, arrayed clones and other interesting effects. It's like DRY principle for art; you can later modify the original shape and see changes reflected in other parts of the scene.
TinyVG is final format optimized for rendering. You can design your graphic with all those futures, and then render them to TinyVG.
DRY doesn't apply since you will not be writing it by hand anyway, but use a tool.
Author clearly states that this is not an Authoring format, but display format. What you are looking for is better authoring format.
> Edit: I like that TinyVG takes form of very readable lisp-like data description language. Maybe it could be used as a starting point for a smarter vector format for authoring graphics and not just for distributing the end results.
That's not TinyVG format. That is just sample generator that comes with TinyVG suite. TinyVG is binary format, and you can't edit it with text editor
Just like bitmaps, vector graphics looks best when it is displayed at size it was designed for. Too small and details will just blur together; too large and the design looks overly simple with unnaturally sharp edges.
Looking at what people mostly use SVG's for on the web, most people don't agree with you. Like I said most SVG's I see are either static icons, diagrams or graphs.
Weather it would be better for them to be bitmaps is another discussion. Lately in embedded I often come in situation where I have CPU cycles to spare, but bump into available storage limit on micro. So this might make sense in such situation
Whole point of this format is to be 80%. that's why it has tiny in name :) If you want to do dynamic content this is not format for you.
> Otherwise the graphics is baked and I can just as well use PNG.
that's what I use now.
But I will try this TinyVG for my next projects dashboard icons, to see cpu/storage space is favorable
Of course this has some drawbacks, particularly when talking about user-uploaded SVGs on a website (they probably shouldn't be on the same domain as the website at all). But that's a much narrower use case than what SVG was supposed to be or even than what SVG is used for today.
@ikskuh since I see you here in the comments, I have one nitpick: I don't think it's fair to compare your binary format to an uncompressed SVG file since they are most often used online (and often used even offline) as gzip- or brotli-compressed resources. It would be nice to see an additional comparison between gzipped TinyVG and gzipped SVG to help even the playing field.
tl;dr: The input svg is pushed through svgo, so we have a very compact format already
obviously different font widths for rendering of SVG text in different browsers/font stacks
> That didn't go as expected. I thought that at least both files on my Linux machine look the same, but it seems like Firefox doesn't like the font-size specification, while Chrome and Edge do.
I asked the Render-A-Webpage-As-An-SVG-framework guy about this last week. He claimed over multiple years he hasn't had a single report of broken text rendering from users of his framework.
So what's the deal? Are OP and me the only devs who have ever hit up against this issue in practice?
If i create a image, i want that image to look exactly the same on all machines. This is sadly not the fact for SVG :(
The W3C SVG example files contain a lot of these files that make every SVG renderer explode. There's images that don't render anywhere except inkscape
You just have to convert the text in the image to a path before using it wherever you plan on, just be sure to save the original for editing.
https://mq32.de/public/9f3cd5eb7f310139cf8acdd61edb73080d26a...
Off topic question for you though, that looks like probably i3 or dwm, did you make any modifications to Inkscape to make it more usable in a tiling wm, I always have to turn off tiling when I launch it.
The sad truth is that many issues go unreported because people are lazy and move on when they hit a roadblock.
Also, I've seen this problem reported more than a few times so you're not alone.
> if only reported
Reporting bugs can be super time consuming, especially if your project is large and the maintainer has a high bar for bug reports (e.g. "provide a codesandbox link"). I can't spend 20 minutes reporting a bug that will be auto-closed in 6 months when I can attempt fixing it instead, especially if I'm annoyed at the tool already. This used to happen a lot with browsers and nowadays it happens with build tools and libraries.
I reckon devs will just drop SVG in favor of a PNG or re-export with text as paths instead of complaining somewhere.
SVG 1.1 extends CSS 2’s font-size value to allow a unitless number on a font-size SVG attribute <https://www.w3.org/TR/SVG11/text.html#FontSizeProperty>, but when you specify it as a CSS style it must follow the CSS declaration form, which means that non-zero lengths must include a unit—<https://www.w3.org/TR/SVG11/styling.html#StyleAttribute> even explicitly mentions font-size as its example on this point.
SVG 2 removes the unitless number extension and defers to CSS Fonts Module Level 3 entirely for font-size, so that unitless non-zero numbers aren’t permitted even in a font-size attribute.
All up, it’s a bad example that doesn’t support the thesis in the slightest, because a rookie error was made. (There’s still something in the fact that such an error could be made so easily, but it’s not that big a deal, certainly not enough to suggest that text is unreliable beyond the fact that you don’t know what fonts are available.)
Text in SVG is just as good as text in HTML, except inasmuch as nothing implements runtime (font-dependent) line wrapping, so it’s kinda more like HTML with white-space:nowrap.
The interactions between presentation attributes and style properties are a bit fiddly and sometimes unclear. Take something like <rect x="2" y="2" width="calc(100% - 4px)" height="calc(100% - 4px)"/>; it’s not quite clear to me whether this is valid in SVG 1.1, though I think it should be in SVG 2. It works in both Firefox and Chromium, though Firefox logs a claim that it’s invalid in the dev tools. <rect style="x:2px;y:2px;width:calc(100% - 4px);height:calc(100% - 4px)"/>, on the other hand, is definitely fine.
That's quite a caveat. How many current webpage designs depend on wrapping happening in exactly the same way across all browsers and device dimensions?
If you want it to look like a document with wrapping then use HTML for your text, not SVG
https://en.wikipedia.org/wiki/Haiku_Vector_Icon_Format
http://blog.leahhanson.us/post/recursecenter2016/haiku_icons...
This is actually a limitation of chrome! The images are perfectly sharp when displayed as files:
https://tinyvg.tech/img/app-icon.png
The are just up/downscaled to 3em height so the table looks uniform
The images are the output from the offline renderer, so they are included as PNGs
> magic must be { 0x72, 0x56 }
I usually use weird non-ASCII bytes in file signatures of binary formats. Many tools will then correctly identify the file as binary data.
> RGB 565
Not important, but I would remove that. In hardware, these 16-bit formats is a thing of the past. Nowdays, you only saving 2 bytes/color compared to RGBA8, for non-trivial complexity cost.
> with the color channels encoded in sRGB
I would add another field in the file header for color space. For RGBA8, sRGB is the only reasonable choice, for FP32 colors however, linear colorspace is very reasonable for some applications.
> VarUInt.. encoded as a variable-sized integer that uses 7 bit per byte for integer bits and the 7th bit to encode that there is ”more bits available”.
This means you need to parse the complete uint just to skip the field, less than ideal. MKV does it much better https://www.rfc-editor.org/rfc/rfc8794.html#name-variable-si... you only need the first byte to find out the length. Note all modern CPUs have bswap instruction or an equivalent to load integers from memory while flipping endianness to little endian.
> Arc Ellipse
Even circular arc segments are relatively hard to implement. The only reason it’s relatively hard and not insanely hard, formulae created for SVG and similar: https://www.w3.org/TR/SVG/implnote.html#ArcConversionEndpoin... Pretty sure elliptical arc segments going to be insanely hard to implement and debug. Another thing, AFAIK no authoring software supports these splines, how people are supposed to get vector art with these things?
(byte & 0x1F) >> 3
should probably be ((byte >> 3) & 0x1f)
... or something like that.(tvg 1 (32 32 1/1 u8888 reduced) ( (1 0 0) ) ( (fill_polygon (flat 0) ( (16 0) (32 32) (0 32) )) ) )
This draws you a tiny triangle. The only problem you'll get is when doing text, but for SVG: These wouldn't be portable anyways
If you take the expression above and format it in any half-decent editor, it's pretty clear. YAML is a shitshow, JSON is yuck and let's not talk about XML.
>YAML is a shitshow, JSON is yuck and let's not talk about XML.
My issue with S-expressions as a data exchange format is that they're actually just the worst aspects of all three of those combined. If you're frustrated by XML having really deep trees and only having strings and elements as datatypes, then S-expressions are just as bad, reliably they only really have strings and lists as datatypes and the trees tend to have even deeper nesting than XML. For JSON the formats are equivalent if you remove everything from JSON except lists and strings, so S-expressions are strictly a worse subset, they're just as yuck. YAML is bad because it's complex and badly specified but S-expressions are still worse of a shitshow because there is no spec. You just have to hope the format you used is compatible with your Lisp implementation. And yes this has caused me problems where using "read" on S-expressions with certain characters in them or in certain encodings completely breaks on some Lisp implementations. If you're using some other language that isn't Lisp and you're rolling your own parser then good luck having that be compatible with anything, most parsers I see just pick a random Lisp implementation and aim for compatibility with it which is still not reliable.
The only good thing I can say about S-expressions is that they're quite easy to spit out from a bash script, but for this problem domain (vector graphics) there is an even easier option: use a very simple command-based format like postscript.
While admittedly less of a problem for implementation, it is also annoying to see lists with dangling parens on their own lines, and symbols with underscores or camelCase in the names, once you are used to the normal way of formatting Lisp code.
[1] https://github.com/no-defun-allowed/wasm2ps/blob/master/Code... [2] https://github.com/WebAssembly/spec/blob/master/interpreter/...
%!PS % -John Tromp http://tromp.github.io/
/t{dup 1 sub gsave dup 0 gt{[.4 .2 -.2 .4 .4 .2]concat t currentgray
.8 mul .2 add setgray -1 1 scale t -1 2 translate t 1 -1 scale t[0 1
1 0 0 2]concat t pop}{0 moveto 1 0 lineto 0 2 lineto closepath clip
fill}ifelse grestore}def 10 10 translate 600 600 scale 5 t showpage
[1] https://en.wikipedia.org/wiki/Pinwheel_tilingNo, Blc is not a concatenative language. It uses application rather than concatenation to combine programs, and its semantics is not described in terms of stack operations (the blc seld-interpreter happens to use a stack though).
Maybe because in the formats named, the image format is the expensive/complex/insecure libraries? I know that sounds a bit snappy, but I felt the author of TinyVG made a pretty good case for what they're aiming at: a simple vector format that does not come with a (or even multiple, in at least the case of PDF) Turing complete kitchen sinks.
Look at log4j for a recent example on what unwanted complexity does. For something matching the subject matter at hand here, look at the various image parsing attacks that have gained large notoriety. Now force multiply by having PostScript, an actual programming language, in the path.
Over time, the old format may potentially be removed if it falls in disfavor, or at least only be accepted in more and more restricted contexts, but this works better in closed systems of course. I just finished excising a complex format in favor of a much simpler one, and since it was internal to the organization cutting out the old one did not cause anyone problems. For browsers, I don't know. Deprecating Java Applets and Flash seems to have worked, but those are maybe "heavier" examples than SVG.
As for comparison to existing vector formats, I don't have the necessary domain knowledge there.
So I don't really see the point in introducing any new vector graphic formats. Just define a subset of SVG that supports the features commonly in use, give it a name, and adopt one of the existing lightweight renderers, forking it if necessary.
As others have pointed out, representation size doesn't matter because it'll be compressed anyway in any applications where size is important. Plain old text is fine.
It's the "shield-account" from material design.
353 shield.svg
246 shield.svg.gz
119 shield.tvg
139 shield.tvg.gz
Looks like tvg is so well compressed that using gzip compression doesn't help and beats compressed and optimized svg still by a magnitude of two. We'll get better numbers when i find time to improve the benchmark.TinyVG was also designed to be used on constrained embedded systems with low RAM, and i have a proof of concept that it can render medium complexity files with less than 32k RAM without memory optimizations in the reference implementation. NanoVG doesn't seem to support streaming render events either, so it isn't suitable for low memory profiles as it creates a DOM that will be rendered
Two qns: 1. Did you consider a re-specification of SVG or a subset in another embedding language that's easier to parse? text/json+svg, application/bson+svg, etc. (Examples for clarity, not literally suggesting json/bson are appropriate choices)
2. SVG has broken gamma-correct blending. It was originally not specified at all so all implementations did it wrong; i think the spec fixes it in 1.2 but the only people who care are Inkscape, and they explicitly aren't implementing it because they don't want to author files that in all likelihood will never display properly in browsers. So... the ship sailed in the wrong direction. Could be worth some thought at this early stage of your project, then you'd have a feature that you actually can't achieve in SVG.
Oh that explains why all my rendering experiments looked different from SVG. I think the reference renderer already does gamma correct blending.
This is something we should add to the specification for sure.
> 1. …
Even re-encoding the SVG crap would only remove XML from the equation, but that's not my main concern with SVG.
Zig has the Zen "only one way to do things". Meanwhile SVG has tens of ways to solve the same problem.
One example: You can set the opacity via css, fill-opacity and opacity. What you cannot do: Set the opacity via color. But you can make 50% black by just specifying fill-opacity, as black is the default color. to render lines, you need to set fill to "none". ugh.
For a pen plotter, I'd like something like SVG that has color, pen-pressure, and pen-rotation.
(I have written SWF rendering and conversion code before, so I might be biased in saying that it's an example of a very well-designed vector format; too bad Adobe has been trying to kill it off.)
Just converting text to vector paths will ruin accessibility, and also hurt SEO / discoverability.
If you need the "tiny" part of TinyVG, add an aria label to the UI node that renders it. Should work well for icons, logos, etc.
And even if we rely only on XML, we get the DOM and hierarchical structures. If we forbid those, we have <svg><object /><object /><object /></svg> as a file format and people will look weird because their other SVG won't be supported in there.
Your second point is actually valid though. If the TinyVG format takes advantage of non-tree based data-structures, I can certainly understand the motivation. I have a hard time conceptualizing how a tree based format would be beneficial to a vector format, other than describing metadata about certain "areas" of the image.
All of these would be fine if XML offered you some really good advantage over alternatives, but as far as I can see, it doesn't. It just eats up CPU/memory/bandwith/keystrokes for no reason.
All of these properties contradict a embedded world where you can render vector graphics from 32k RAM on a chip that doesn't even have enough memory for a framebuffer itself.
Also implementation complexity of XML is so high that i gave up on impementing a correct parser. I don't want to have a half-assed parser that cannot parse XML, but only "XML light" and making this is a huge amount of work which i don't want to waste in my leisure time
Why? Streaming/evented (e.g., SAX) parsing for XML is as old as XML.
It’s reached meme status. I think most people conflate complex XML-based _formats_ (e.g., WSDL, XSD) with XML _the format_. The rules of XML parsing can fit on a notecard. And a basic parser that supports all the core functionality plus namespaces is really not that complicated to implement. Now, implementing schema validation, Xlink, etc. in your parser is definitely not simple. But to make a simple XML parser those are optional bits.
Yes, but SVG requires a lot of those optional bits... A parser complex enough to deal with all the nooks and corners of SVG is not simple at all.
Semi-structured data is not bad. Namespaces are not bad. Schema are not bad. In fact, I also on the other hand very much lament that XML's backlash lead us to JSON, which is entirely untyped semi-structured data where everyone has to write an (often buggy and incomplete) ad-hoc typechecker for every single document.
Those features are not the problem, the problem is that they are embedded in the SGML-borne XML, that has many weird and intricate corners that only make sense in light of its history, and that lead to complex parsing, obscure behavior, and lots of potential for vulnerabilities--in the parsers or in code that just uses a (perhaps in itself safe) parser. DTDs, Entities, and Processing Instructions are just some of the more known warts.
Do we, though?
We've already had animated GIFs, the marquee tag, Java applets, and Flash animation, and they've all died out because 99.9% of the time the animation is obnoxious and terrible. Vector animation would be just as annoying.
Java applets died out of technical reasons (and was replaced by flash)
Flash died, because it was proprietary and Adobe did not open it up. (and flash was vector animation btw.)
Otherwise it surely would still be around. And in a way it is, as you can export flash animations to the html canvas element. And some people do that (with quirks)
In other words, a simple, but powerful vector animation tool, is very much needed. The current state is a mess.
And you probably do not like vector animated advertisement, or websites that use animations for the sake of animations. Sure, no one wants that.
But how about games, or interactive graphic to for example show complex data in context to some map? Or animations for didactic purposes? Cartoons?
A animation well done is actually one, you do not notice. (but you would notice, if it was missing)
I think the iPhone refusing to support Flash had far more to do than the underlying business practices or IP.
If the Flash player would have been open in a way, chromium/webkit is, with many top players working on it - it very likely would still be around and maybe even dominating, as it was way superior in terms of features and more importantly, it was not a mess to work with, like HTML still is.
But it had a reputation for being insecure, and for being slow — because it retained the ability to put vector animation on top of videos.
When HTML 5 was adopted with video playback tags (safer, faster, open), that killed it for web video.
Flash renderers didn't have to suck. However, there wasn't enough money in it for anyone to care.
We do definitely need better vector graphics, including animations. Because then you can have the same crisp images and animations regardless of your resolution or screen size.
So if you want to use animation for everything, you could design a secondary format that allows animation of TinyVG files hint
You could probably take a hard line that once you have references, there is no need for any other extension, those are doable using references.
BTW, has someone worked on a js backfill that lets you load the file format in an image tag? I'd be happy to give it a shot with zig/wasm.
Edit: OK, I just found the polyfill.
E.g., even in Firefox I can do myRect.animate([ { x: "0px" }, { x: "100px" }], 1000); and it works correctly.
I expected to see something related to performance in the benchmark[1] but it's only focused on file size.
But the decoding speed should be blazingly fast, as there is not much memory heavy lifting to do, and only a handful of int to float conversions.
As soon as i have a competetive rendering (aka Vulkan), i will add those to the benchmark. My guess is that rendering TinyVG should also be much faster than SVG due to not having any matrix transformations or hierarchies included in the format
Edit: Nevermind, this was answered in another comment, apparently it's a limitation of Chrome
This is what i've done for a lot of test files until i had the TinyVG text form ready.
Also, we should not edit graphic files in a code editor. We have better tools for that
"a powerful, flexible, declarative domain-specific language for creating vector graphics, using the Haskell programming language."
I don't think even the first generation of iPhone (400MHz ARM) was too slow to run the average Flash games of the time, given that SWF was originally designed to work well on mid-90s PCs (200-300MHz Pentium/Pentium II).
and Steve Jobs' "Thoughts on Flash"
That's more likely.
The peak performance was enough, but the it will drain battary very quickly.
If I want to have use those features I now need two (or more) formats, which kind of defeats the point of a less complicated format, for size, complexity and security reasons.
12 Multimedia, 13 Interactivity, 14 Linking, 15 Scripting, 16 Animation, 17 Fonts
That does not sound very tiny to me.
With a hierarchical system you can do things like bones for animation.
Amazing.
Seems like doing a webpage with SVG instead of CSS would also allow more flexible web design.
Seems exactly the opposite to me.
But maybe I don't understand the intended sense of “flexible” intended.
Can TinyVG be converted to other image formats, such as PNG?
XML
Don't even know what implementing a subset without using XML would actually mean.
An XML being a strong contender for the title of worst file format ever devised by mankind, I'm not sure how 'implementing a subset' would fix that.
To define a subset of SVG doesn't imply that simplifying the XML part is going to be easy.
Could you name the feature to which you are referring specifically?
> XML part is going to be easy.
What part of parsing XML is hard? My premise is that all XML parsing is easy.