google / iconvg

IconVG is a compact, binary format for simple vector graphics: icons, logos, glyphs and emoji.
Apache License 2.0
676 stars 11 forks source link

Allow only simple, absolute segments #29

Closed RazrFalcon closed 2 years ago

RazrFalcon commented 3 years ago

SVG path specification is extremely overcomplicated and error-prone (afaik, the current iconvg C implementation is also incorrect #23). Maybe it would be easier to stick just to M, L, C, Z segments (absolute only)?

SVG supports relative commands to simplify authoring and reduce size on large coordinates. And I'm not sure it affects iconvg in any way.

nigeltao commented 3 years ago

I'm thinking of keeping Q too, but the overall sentiment is similar to these two comments :-)

nigeltao commented 3 years ago

Quoting Hixie from https://github.com/google/iconvg/issues/18#issuecomment-853172397

I would certainly support dropping opcodes and generally simplifying the format, but I would recommend making such decisions based on what the format's goals are. If file size is a higher concern than implementation and spec complexity, then these opcodes do make sense. If rendering speed is more important then there's plenty of other places to optimize, for example the 1- and 2- byte encodings for numbers do not add any value beyond file size optimization but cost implementation complexity and size and runtime performance. I would urge any changes to be made at a holistic level; making decisions in one part of the format with different priorities than in another part of the format will lead to a confused format.

I don't have "the" answer to "what are the format's goals?" yet, but I am thinking about it...

nigeltao commented 3 years ago

Now for some data, if we simplify the drawing model to M/L/Q/C/Z. This means:

First, the test/data/*.ivg files:

File size, after / before.
a / b  =    88 /   73  = 1.205  action-info.hires.ivg
a / b  =    72 /   63  = 1.143  action-info.lores.ivg
a / b  =   263 /  147  = 1.789  arcs.ivg
a / b  =     5 /    5  = 1.000  blank.ivg
a / b  =  1032 / 1017  = 1.015  cowbell.ivg
a / b  =    86 /   85  = 1.012  elliptical.ivg
a / b  =  1796 / 1599  = 1.123  favicon.ivg
a / b  =   229 /  225  = 1.018  gradient.ivg
a / b  =    70 /   68  = 1.029  lod-polygon.ivg
a / b  =   626 /  625  = 1.002  video-005.primitive.ivg

Second, on the 961 files comprising the 2016 era Material Design icons

In terms of total file size:
130403 / 122012  = 1.069

In terms of average file size, i.e. dividing by 961, about 9 bytes per file:
135.70 / 126.96  = 1.069

Again, Hixie has a point about overall goals, but my first impressions are that a size increase of +7%, or 9 bytes per file, aren't that big a cost...

RazrFalcon commented 3 years ago

Personally, I'm looking for a binary SVG. Sadly, looks like iconvg is very far from it. Lack of stroking is the most important right now. I wanted to do something like this myself, but I don't have much time lately.

PS: by the way, I have usvg project, that could easily be used to convert SVG into ivg. It even supports text-to-path conversion and markers flattening.

RazrFalcon commented 3 years ago

As for the ArcTo, there is one particular bug where you can't replace it with CurveTo - marker-mid. Marker has to be places in the center of the path, but after ArcTo-to-CurveTo conversion you will probably have 2-3 segments instead of one, which will produce an incorrect result. Yes, this is SVG specific, but maybe worth considering. Here is a test case: https://raw.githubusercontent.com/RazrFalcon/resvg-test-suite/master/svg/e-marker-035.svg

RazrFalcon commented 3 years ago

Again, Hixie has a point about overall goals, but my first impressions are that a size increase of +7%, or 9 bytes per file, aren't that big a cost...

Have you considered RLE for path segments?

Before: MCCCCC After: 1M5C

This could greatly reduce binary size for large paths, but will slightly increase parsing complexity.

nigeltao commented 3 years ago

Have you considered RLE for path segments?

We already do RLE. Look for the phrase "repeat count" in the spec.

As for the ArcTo, there is one particular bug where you can't replace it with CurveTo

Well, IconVG doesn't have markers, so converting SVG ArcTo's with markers to IconVG is the responsibility of the convert-SVG-to-IconVG tools, not the responsibility of IconVG decoders or IconVG-to-IconVG converters.

Similarly, convert-to-IconVG tools would do stroke-to-path conversion the same way that they'd do text-to-path conversion.

Here is a test case: https://raw.githubusercontent.com/RazrFalcon/resvg-test-suite/master/svg/e-marker-035.svg

Am I supposed to see three markers (start, mid, end)? My SVG renderer (chromium) only shows two (start, end). Which is kind of the point of IconVG. SVG is so complicated that different decoders can end up showing different things. IconVG is so featureless that it's less likely (but not impossible) for implementations to diverge.


Anyway. If IconVG still doesn't work for you, then OK. We'll do different things then. :-)

nigeltao commented 3 years ago

Am I supposed to see three markers (start, mid, end)? My SVG renderer (chromium) only shows two (start, end).

e-marker-035

RazrFalcon commented 3 years ago

I see. It's not like iconvg is not what I need, rather that I'm not sure about the scope of the format. As someone who is working on a SVG renderer, I'm well aware of its complexity. But some iconvg limitations are pretty strict:

  1. Yes, we can do stroking on the converter side, but a typical stroke would be huge. So it would simply blow up the file size. Example.
  2. Raster images are necessary. You can't expresses some complex images with just vector. Even Apple Emojis are PNG's. Also, raster images can be used as filters fallback. Like drop shadow and stuff.
  3. Patterns support. Complex, yes, but flattening will only lead to a larger file size.
  4. Clipping. While can be expensive, can produce better results than flattening.

PS: I don't really care about animations, effects and other stuff.

RazrFalcon commented 3 years ago

This is how an invalid result looks like:

e-marker-035

Marker-mid appears because there are two segments now and not one.

nigeltao commented 3 years ago

Marker-mid appears because there are two segments now and not one.

Oh, I see. Converting an arcTo to two cubeTo's can be a problem with SVG, because it can introduce marker-mids. But as I said, that's a problem for convert-SVG-to-IVG tools, and it's solvable by those tools. It won't be a problem for IVG and converting arcTo's in IVG FFV 0 to cubeTo's in IVG FFV 1 (issue #4), because IVG doesn't have markers.

nigeltao commented 3 years ago

Yes, we can do stroking on the converter side, but a typical stroke would be huge.

Huge? Maybe. The cowbell example on the repository front page has a black stroke, and the .ivg file size isn't 'huge' compared to the .svg file.

RazrFalcon commented 3 years ago

Huge? Maybe.

Well, way larger that with 2d library generated one.

Basically, my point is that it's easier to rely on 2d library features than reinventing them in the file format.

nigeltao commented 3 years ago

It sounds like IconVG isn't what you want. As I said, we'll do different things then. :-)

RazrFalcon commented 3 years ago

No problem :)