iconvg: a compact, binary format for simple vector graphics

1,202 views
Skip to first unread message

Nigel Tao

unread,
Oct 24, 2016, 2:52:48 AM10/24/16
to golang-nuts
I was looking for a compact, binary format for simple vector graphics.
I didn't find one that did all I wanted.

SVG is the de facto standard for vector graphics, in the open source
world. Unfortunately, https://www.w3.org/TR/SVG/single-page.html
prints as 400 pages, not including the XML, CSS or XSLT
specifications. The S in SVG doesn't stand for simple.

The Haiku Vector Icon Format is pretty close. Unfortunately, I didn't
find a written specification, only a single C implementation, tightly
coupled, as far as I could tell, to the Haiku operating system. Also,
https://www.haiku-os.org/articles/2009-09-14_why_haiku_vector_icons_are_so_small
says that "you wouldn't really want to use HVIF to store generic
vector graphics".

OpenType fonts contain vector graphics (glyphs), and people use it for
icon and emoji fonts. Unfortunately, there doesn't appear to be a
clear standard for colored or partially transparent glyphs.
https://en.wikipedia.org/wiki/OpenType#Color lists three competing
approaches, built on PNG, SVG or neither.

So, as an experiment, I invented a new format: IconVG. The format
itself is documented at
https://godoc.org/golang.org/x/exp/shiny/iconvg and there are some
examples at https://go.googlesource.com/exp/+/master/shiny/iconvg/testdata

The Material Design icon set (https://design.google.com/icons/)
consists of 961 vector icons. As SVG files, this totals 312,887 bytes.
As 24*24 pixel PNGs, 190,840 bytes. As 48*48 pixel PNGs, 318,219
bytes. As IconVGs, 122,012 bytes.

Like all of the golang.org/x/exp/shiny code, this is experimental, but
I think that IconVG is at an interesting enough point now to share.

The vector rasterizer at golang.org/x/image/vector is also a nice Go
package, in my biased opinion, based on the algorithm described at
https://medium.com/@raphlinus/inside-the-fastest-font-renderer-in-the-world-75ae5270c445#.ja3y3m6z2,
but that's probably a different topic for a different time.

Comments welcome.

Pietro Gagliardi

unread,
Oct 24, 2016, 11:13:43 AM10/24/16
to Nigel Tao, golang-nuts
I wonder if there's a way to simulate elliptical gradients with only circular gradients and affine transformations, so package ui can also render these files directly using the system native vector graphics APIs.

Does this also require the cairo/Quartz feature of having a circular gradient have an inner circle and an outer circle (instead of a point and an outer circle)? If so, I wonder how to simulate that on other platforms as well...


Or in other words, I wonder how I can reconcile the differences between
https://msdn.microsoft.com/en-us/library/windows/desktop/dd368149(v=vs.85).aspx
and
https://www.cairographics.org/manual/cairo-cairo-pattern-t.html#cairo-pattern-create-radial / https://developer.apple.com/reference/coregraphics/1455923-cgcontextdrawradialgradient?language=objc
so that I could possibly implement this with package ui as well.


Preemptive apologies for dropping off the shiny project early on; I was caught up in other stuff at the time ^^;
> --
> You received this message because you are subscribed to the Google Groups "golang-nuts" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.
>

Daniel Theophanes

unread,
Oct 25, 2016, 1:31:33 AM10/25/16
to golang-nuts
My understanding is that the original rust font render code could replace something like FreeType. Do you envision using iconvg and vector as a replacement for the go freetype package, where font glyphs would be loaded in as iconvg byte streams in a cache and then simply read from there in the render loop, resulting in little to no additional allocations or re-parsing of the original font glyph?

Nigel Tao

unread,
Oct 25, 2016, 3:37:48 AM10/25/16
to Pietro Gagliardi, golang-nuts
On Tue, Oct 25, 2016 at 2:13 AM, Pietro Gagliardi <and...@lostsig.net> wrote:
> I wonder if there's a way to simulate elliptical gradients with only circular gradients and affine transformations, so package ui can also render these files directly using the system native vector graphics APIs.

I'd expect that you can, but I haven't done it myself.


> Does this also require the cairo/Quartz feature of having a circular gradient have an inner circle and an outer circle (instead of a point and an outer circle)? If so, I wonder how to simulate that on other platforms as well...

It does not. IconVG follows SVG here, not cairo / Quartz.

Nigel Tao

unread,
Oct 25, 2016, 3:44:53 AM10/25/16
to Daniel Theophanes, golang-nuts
On Tue, Oct 25, 2016 at 4:31 PM, Daniel Theophanes <kard...@gmail.com> wrote:
> My understanding is that the original rust font render code could replace
> something like FreeType. Do you envision using iconvg and vector as a
> replacement for the go freetype package, where font glyphs would be loaded
> in as iconvg byte streams in a cache and then simply read from there in the
> render loop, resulting in little to no additional allocations or re-parsing
> of the original font glyph?

A TTF parser under golang.org/x/image, using x/image/vector directly
without going through an iconvg middleman, is on my list of things to
do, but one thing at a time...

roger peppe

unread,
Oct 25, 2016, 6:30:45 AM10/25/16
to Nigel Tao, golang-nuts
This looks really cool, thanks!

Would there be some advantage in making the Rasterizer
types in shiny/iconvg and image/vector somewhat more
uniform in the types they use? For example, vector.Rasterizer
seems to use f32.Vec2 pairs everywhere, but iconvg.Rasterizer
uses individual x, y arguments.

How feasible would it be (if at all) to translate from iconvg format
to svg format?

cheers,
rog.

Sean Russell

unread,
Oct 25, 2016, 9:45:02 AM10/25/16
to golang-nuts
Hi,


On Monday, October 24, 2016 at 2:52:48 AM UTC-4, Nigel Tao wrote:
The Material Design icon set (https://design.google.com/icons/)
consists of 961 vector icons. As SVG files, this totals 312,887 bytes.
As 24*24 pixel PNGs, 190,840 bytes. As 48*48 pixel PNGs, 318,219
bytes. As IconVGs, 122,012 bytes.
 
How did you calculate the SVG sizes?  When I download the the icons from the material design github, the collection of the *_48px.svg icons weighs in at 3.8MB.  The single, uncompressed SVG containing all icons -- MaterialIcons-Regular.svg -- is 276k, and as svgz is 72k.

So, one question and one suggestion: the question is what were you measuring for the SVG size, and the comment is that you might want to address the svgz aspect.  As in, "yes, svgz is smaller, but more expensive to decode," with benchmarks, or whatever other technical merits you're aware of.

Your graphics-fu is much stronger than mine, and I'm interested to see where you take this.

--- SER

--- SER

Nigel Tao

unread,
Oct 26, 2016, 1:23:36 AM10/26/16
to roger peppe, golang-nuts
On Tue, Oct 25, 2016 at 9:30 PM, roger peppe <rogp...@gmail.com> wrote:
> Would there be some advantage in making the Rasterizer
> types in shiny/iconvg and image/vector somewhat more
> uniform in the types they use? For example, vector.Rasterizer
> seems to use f32.Vec2 pairs everywhere, but iconvg.Rasterizer
> uses individual x, y arguments.

Yeah, it might be nicer for image/vector to take (bx, by float32)
instead of (b f32.Vec2). Let me think about it.


> How feasible would it be (if at all) to translate from iconvg format
> to svg format?

From IconVG to SVG should be trivial, other than features SVG doesn't
have (I think) such as Level-Of-Detail culling.

Nigel Tao

unread,
Oct 26, 2016, 1:38:14 AM10/26/16
to Sean Russell, golang-nuts
On Wed, Oct 26, 2016 at 12:45 AM, Sean Russell <seaner...@gmail.com> wrote:
> How did you calculate the SVG sizes? When I download the the icons from the
> material design github, the collection of the *_48px.svg icons weighs in at
> 3.8MB.

You may be double counting the design/ and production/ versions of the
same icons, although that shouldn't explain a 10x difference. There
may be other factors. How did you make your calculation?


> So, one question and one suggestion: the question is what were you measuring
> for the SVG size, and the comment is that you might want to address the svgz
> aspect. As in, "yes, svgz is smaller, but more expensive to decode," with
> benchmarks, or whatever other technical merits you're aware of.

The SVG size was measured by this program:
https://go.googlesource.com/exp/+/master/shiny/materialdesign/icons/gen.go
which generated this file (look at the final lines):
https://go.googlesource.com/exp/+/master/shiny/materialdesign/icons/data.go

SVGZ is indeed smaller, and more expensive to decode, but I don't have
numbers at hand.

Even so, there's still the point that a spec-compliant SVG renderer is
a _lot_ of code, and XML brings its own complexities.

roger peppe

unread,
Oct 26, 2016, 4:20:58 AM10/26/16
to Nigel Tao, Sean Russell, golang-nuts
This cannot be understated. A well known tool generates SVGs that the
Go XML parser cannot parse because it uses XML directives to create XML
entities that contain XML elements when they're expanded. This meant
we couldn't process them at all (we wanted to adjust the view
box parameter).

Nigel Tao

unread,
Oct 26, 2016, 6:51:09 PM10/26/16
to roger peppe, Sean Russell, golang-nuts
On Wed, Oct 26, 2016 at 7:20 PM, roger peppe <rogp...@gmail.com> wrote:
> This cannot be understated. A well known tool generates SVGs that the
> Go XML parser cannot parse because it uses XML directives to create XML
> entities that contain XML elements when they're expanded. This meant
> we couldn't process them at all (we wanted to adjust the view
> box parameter).

Ooh, that's interesting. Can you share some more details?

roger peppe

unread,
Oct 27, 2016, 11:43:04 AM10/27/16
to Nigel Tao, Sean Russell, golang-nuts

Pietro Gagliardi

unread,
Oct 27, 2016, 11:51:43 AM10/27/16
to roger peppe, Nigel Tao, Sean Russell, golang-nuts
What part of the document are you referring to?

roger peppe

unread,
Oct 27, 2016, 12:36:13 PM10/27/16
to Pietro Gagliardi, Nigel Tao, golang-nuts, Sean Russell

The <! declarations at the start need to be parsed to discover the namespace URIs without which you can't know which elements and attributes are part of the SVG spec.


> To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscribe@googlegroups.com.

Pietro Gagliardi

unread,
Oct 27, 2016, 12:42:24 PM10/27/16
to roger peppe, Nigel Tao, golang-nuts, Sean Russell
Ah, I see; that also explains the funny "Bogus doctype." message Firefox gives me in the view-source view.

Nigel Tao

unread,
Oct 27, 2016, 7:40:20 PM10/27/16
to Sean Russell, golang-nuts
On Wed, Oct 26, 2016 at 4:38 PM, Nigel Tao <nige...@golang.org> wrote:
> SVGZ is indeed smaller, and more expensive to decode, but I don't have
> numbers at hand.

Oh, I do have a size number. It's only one data point, but look for
"gzip" at https://godoc.org/golang.org/x/exp/shiny/iconvg

Nigel Tao

unread,
Nov 6, 2016, 1:23:14 AM11/6/16
to roger peppe, golang-nuts
On Tue, Oct 25, 2016 at 9:30 PM, roger peppe <rogp...@gmail.com> wrote:
> Would there be some advantage in making the Rasterizer
> types in shiny/iconvg and image/vector somewhat more
> uniform in the types they use? For example, vector.Rasterizer
> seems to use f32.Vec2 pairs everywhere, but iconvg.Rasterizer
> uses individual x, y arguments.

I've gone with individual x, y arguments.

https://go-review.googlesource.com/32772
https://go-review.googlesource.com/32773

rxbo...@gmail.com

unread,
Jan 17, 2018, 1:04:18 PM1/17/18
to golang-nuts
Hi Nigel,

I'm looking for a compact vg format and I found your iconvg format.
This seems to be exactly what I'm looking for. 
I'm wondering if you know any c/cpp implementation of your renderer (into image buffer). This is to be used in a small embedded system.

Great job.
Regards
Eric

Nigel Tao

unread,
Jan 17, 2018, 5:12:53 PM1/17/18
to rxbo...@gmail.com, golang-nuts
On Thu, Jan 18, 2018 at 1:53 AM, <rxbo...@gmail.com> wrote:
> I'm wondering if you know any c/cpp implementation of your renderer

I don't know of a C/C++ implementation, sorry. If you find (or write)
one, let me know!

Eric Boucher

unread,
Jan 19, 2018, 8:02:04 AM1/19/18
to golang-nuts
Ok, thanks for your answer.
As I need something really simple and lightweight, I'll probably end up writing my own format :-)

Regards
Reply all
Reply to author
Forward
0 new messages