google / iconvg

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

Specify color space (sRGB?) #37

Open eliasnaur opened 2 years ago

eliasnaur commented 2 years ago

I didn't see a mention of either "color space" nor "srgb" in https://github.com/google/iconvg/blob/main/spec/iconvg-spec.md, and neither did I find references in the original IVG spec. I believe the (implicit) color space should be specified, and because colors are limited to 32 bit, I suggest the common sRGB color space. As a corollary, conformant rasterizers must blend and compute gradients in linear RGB space.

nigeltao commented 2 years ago

We could add a metadata chunk to hold ICC profiles and, lacking one, sRGB seems the obvious default.

As for blend and compute (with or without gamma correction before and after linear interpolation), I suspect that the implementations (the Cairo, Skia and golang.org/x/image/vector vector graphics libraries) will lead and the spec will follow.

See also https://github.com/golang/go/issues/11420

eliasnaur commented 2 years ago

We could add a metadata chunk to hold ICC profiles and, lacking one, sRGB seems the obvious default.

FWIW, I don't care as much for the ability to change color profile as I do for specifying gamma-correct blending and interpolation. I suspect supporting just sRGB correctly would be fine.

As for blend and compute (with or without gamma correction before and after linear interpolation), I suspect that the implementations (the Cairo, Skia and golang.org/x/image/vector vector graphics libraries) will lead and the spec will follow.

See also golang/go#11420

I'm pretty sure sure golang.org/x/image/vector doesn't blend in linear colorspace. Does that mean the iconvg spec will specify gamma-incorrect blending/interpolation? As per the linked #11420, it would be unfortunate to have a new format not specify gamma-correct blending and interpolation.

nigeltao commented 2 years ago

We could add a metadata chunk to hold ICC profiles and, lacking one, sRGB seems the obvious default.

Another option: we could make "no ICC profile in the IconVG metadata" to mean linearRGB.

I'm pretty sure sure golang.org/x/image/vector doesn't blend in linear colorspace.

Yeah, golang.org/x/image/vector doesn't do gamma correction. I had a quick look and I think Cairo also doesn't do this. As for Skia, I skimmed https://skia.org/docs/user/color/ and https://skia.org/docs/user/api/skpaint_overview/ but I'm still not sure.

it would be unfortunate to have a new format not specify gamma-correct blending and interpolation.

Gamma-correction can hurt performance (decode times), though. At least on the CPU. Trade-offs...

We also already have one Cairo gradient workaround, for alpha premultiplication. It possibly wouldn't hurt to have a second workaround, for gamma. That'd just address interpolation, though, and not blending (I don't think CAIRO_OPERATOR_OVER is gamma-aware). It'd also be unfortunate if the new format is unable to be rasterized with Cairo.

FWIW, https://www.w3.org/TR/SVG11/painting.html#ColorInterpolationProperty and https://www.w3.org/TR/SVG2/painting.html#ColorInterpolation is what the SVG 1.1 and SVG 2 specs says about color interpolation. IIUC "auto" means that the author doesn't really care what the user-agent does.

If authors really do care, another workaroundy idea is to declare that IconVG works solely in linearRGB and "export to IconVG" tools should approximate sRGB (or whatever color profile) how they see fit (e.g. adding explicit gradient stops), just like how "export to IconVG" already has to flatten stroked paths to simple paths.

nigeltao commented 2 years ago

As a corollary, conformant rasterizers must blend and compute gradients in linear RGB space.

I'm pretty sure sure golang.org/x/image/vector doesn't blend in linear colorspace

The terminology can be confusing. Personally, I would say that golang.org/x/image/vector does blend in linear color space because it assumes that inputs and outputs are already linear. Although by context, it looks like you use "blend in linear color space" to mean converting between linear and something else (sRGB) before and after calculating a weighted average.

How about using the terms "naive interpolation" and "sophisticated interpolation"? When interpolating e.g. the R (red) value between two colors C0 and C1 with weights W0 and W1:

Naive means:
Dst.R = W0*C0.R + W1*C1.R

Sophisticated means:
Dst.R = H(W0*G(C0.R) + W1*G(C1.R))

for some gamma correction function G and its inverse H.

eliasnaur commented 2 years ago

Right, since package image (ala #11420) assumes linear colors, package vector can be said to interpolate correctly.

However, using the terms "naive" and "sophisticated" interpolation seems misleading to me, unless IconVG specify linear colors even for 8-bit color channels, a decision (almost) no other image format has taken. As the example from #11420 shows, incorrect blending is not just a quality issue; rather, it can result in dramatically different colors. In other words, if IconVG don't specify blending algorithm or specify "naive blending", "sophisticated" ("correct") rasterizers will be forced to use incorrect blending to match results from incorrect rasterizers.

I worry that IconVG will have the same issues as fonts authored using editors and rasterizers with incorrect blending, a problem described in https://freetype.org/freetype2/docs/hinting/text-rendering-general.html.

pjanx commented 2 years ago

Cairo completely disregards gamma or any other details of colour spaces.

The underlying library for software pixops, pixman, does have an 8-bit sRGB mode, though it's quite slow and not exposed.

The sanest way of using Cairo is probably to use the new CAIRO_FORMAT_RGBA128F and give it linear data, then convert that to sRGB on the output by external means, if necessary.

eliasnaur commented 2 years ago

FWIW, Skia supports color spaces and defaults to sRGB.

eliasnaur commented 2 years ago

An article that argues sRGB is better thought of as a (lossy) encoding rather than a color space: https://webcolorisstillbroken.com/.