Discussion:
[OpenRaster] proposal: new layer modes, ref updates, extra properties for layer groups, impact on apps
Andrew Chadwick
2014-02-18 15:20:42 UTC
Permalink
Updates to the OpenRaster Stack Specification
=============================================

I would like to propose the following (updated) amendments to the
[OpenRaster specification][1]. Thanks to everyone who's taken the time
to review the original proposal and comment on it.

The addition of svg:dst-in and svg:dst-out to the OpenRaster would
allow MyPaint, an app I co-maintain, implement layer masking. There is
accordingly an [experimental code branch][0] with a draft
implementation of these updates.

This revised proposal can also be read at
https://gist.github.com/achadwick/7827931


New layer modes
---------------

To the Layer Stack specification, the following change:

1. Support for at least two new composite-ops: `svg:dst-in` and
`svg:dst-out`. These names come from the old [SVG Compositing 1.2
standard][2].

We could also add support for all Porter-Duff operators as defined in
this and [in Compositing-1][3], however only a limited subset are
actually of practical use to artists. These two in particular allow
entire layer groups to be masked; others which might be of use are the
src-in and src-out variants (also useful for masking), and src-atop
which can be used for texturing the layer below.

See "Reference Updates" below for updates to the normative references
for these modes.

Reference Updates
-----------------

To the Layer Stack specification, the following changes:

1. The text "Layer stacks should be composited in a manner conforming
to the W3C's [Compositing and Blending Level 1][3] specification. The
root stack is to composite as an isolated group over a background of
the application's choice."

2. The text "Non-root stacks should be rendered as isolated groups if:
a) their "isolation" property is `isolate` (and not `auto`); or b)
Their `opacity` is less that 1.0; or c) They use a `composite-op`
other than `svg:src-over`."

3. Define what "group isolation" is by pointing at the [relevant
part][4] of the Compositing-1 spec. Add brief summary text: "Isolated
groups are rendered independently, starting with a fully-transparent
'black' backdrop (rgba={0,0,0,0}). The results of this independent
composite are then rendered on top of the group's own backdrop using
its opacity and composite mode settings. Conversely, for non-isolated
groups, each component layer is rendered in turn to the group's
backdrop, just as if there were no stacked group".

4. The text "Applications *may* assume that all stacks are isolated
groups if that is all they support. If they do so, they *must* declare
when writing OpenRaster files that their layer groups are isolated
(isolation='isolate')."

5. Consolidate all the modes into a single table, and provide deep
links into the Compositing-1 specification, which provides a (much
improved) normative reference for them and the mathematics involved.

The rather unusual point 3 above is part of the [Compositing-1][3]
spec which is intended to provide backwards compatibility for SVG's
old layer model which only supported src-over (regular
alpha-compositing). See *Extra properties for layer groups* below for
details of the `isolation` property, but note that most apps which
support OpenRaster only support isolated layer groups.

Extra properties for layer groups
---------------------------------

To the Layer Stack specification, the following changes to the
definition for *non-root* `<stack/>` elements:

1. Add the [Compositing-1][3] `isolation` property as an XML
attribute, taking the values `auto` or `isolate`. The default value is
`auto`. Its meaning is as described above in *Reference Updates*.

2. Support for `opacity`, `visibility`, and `composite-op` properties,
as defined for the `<layer/>` element.

The *root* layer stack has a fixed, implicit rendering in OpenRaster.
For sub-stacks, which are commonly called "layer groups" in painting
apps, the behaviour described for inferring group isolation based on
unusual opacities or layer modes should suffice to provide backwards
compatibility with apps which formerly didn't care about group
isolation.

Impact on current applications
------------------------------

In terms of the Compositing-1 spec's terminology, current painting
apps with OpenRaster support have the following behaviours:

* **GIMP 2.8.6**: All layer groups are isolated regardless of layer
flags and opacities, and this cannot be turned off. In addition,
"effects" layers (e.g. "Colour" or "Screen") are always masked by the
"normal" layers ("Normal" or "Dissolve") below them within their
group. Thus, "effects" layers in GIMP use an implicit SRC-ATOP
Porter-Duff compositing operator (I think). "Normal" layers use the
regular SRC-OVER operator.

* **Krita 2.7.5**: All layer groups are isolated regardless of layer
flags and opacities. Effects layers (e.g. "Colour" or "Screen") are
not masked by layers below them within their group. The implicit
Porter-Duff compositing operator appears to be SRC-OVER. Of note:
Krita already has an "erase" mode which is identical to experimental
MyPaint DST-OUT modes.

* **MyPaint master** as of 2014-02-14: all layer groups are
non-isolated, regardless of layer flags or opacities. Hence, nothing
is masked, and all effects layers composite with an implicit SRC-OVER
Porter-Duff mode.

It's fairly clear that MyPaint has an unusual (non-)treatment of group
isolation. Defaulting "isolation" to "auto" should allow this app to
evolve closer to the Krita and GIMP models as time progresses.
OpenRaster is MyPaint's default format.

The venerable GIMP has a different unusual behaviour: the implicit
SRC-ATOP compositing of "effects" layers, applied after the blend
result is calculated. This can be expressed simply by creating a mask
consisting of the simple alpha composition of the underlying layers.
Consider a GIMP document with::

root
├ "layer group" (Normal)
│ ├ "layer 3" (Screen)
│ ├ "layer 2" (Normal)
│ └ "layer 1" (Normal)
└ "bg" (Normal)

This might be represented in OpenRaster as the admittedly more complex::

root
├ "layer group" (svg:normal) ← ORA substack representing a GIMP group
│ ├ "layer 3" (svg:screen) ← ORA substack representing a GIMP effect layer
│ │ ├ "artificial composite mask" (svg:dst-in)
│ │ │ ├ data/layer2.png (svg:src-over) ←note reuse of layer2.png
│ │ │ └ data/layer1.png (svg:src-over) ←note reuse of layer1.png
│ │ └ data/layer3.png (svg:src-over)
│ ├ data/layer2.png "layer 2" (svg:src-over)
│ └ data/layer1.png "layer 1" (svg:src-over)
└ data/bg.png "bg" (svg:src-over)

Or any other structure which masks "layer 3" correctly.

Krita would be unaffected by this proposed change.


[0]: https://gitorious.org/mypaint/achadwick-mypaint/commits/layer-enhancements-exp-alt
[1]: http://www.freedesktop.org/wiki/Specifications/OpenRaster/Draft/
[2]: http://dev.w3.org/SVG/modules/compositing/master/SVGCompositing.html#comp-op-property
[3]: http://www.w3.org/TR/compositing-1/
[4]: http://www.w3.org/TR/compositing-1/#isolatedgroups
--
Andrew Chadwick
Andrew Chadwick
2014-02-24 12:00:26 UTC
Permalink
Any more feedback on this? Boud mentioned on IRC that he thinks it
looks OK, and we had a bit of a to-and-fro on #gimp about it. People
are beginning to nag me on Twitter about getting it integrated with
MyPaint master now.

Since the changes in the latest proposal are pretty minimal, I'd like
to move ahead with it in the next week. Would that meet with
everyone's approval?

Quick Q: do we need to any more more than svg:dst-in and svg:dst-out?
We could add all the Porter-Duff modes, but they're not all equally
useful! Destination In/Out seem to be the most useful for masking an
isolated stack. Off the top of my head, svg:src-atop might be of some
limited use to artists too - the rest, not so much. I'm tempted to add
them all for completeness however. Any objections?
--
Andrew Chadwick
Andrew Chadwick
2014-02-26 22:02:02 UTC
Permalink
Yes, I'm okay with the proposal. Not sure, though, about adding more porter
duff modes. It could be a long time before I figure out how to support them
More than just the default OVER and the more useful variants of IN and
OUT for masking, I assume? I think Krita's "Erase" is dst-out, and
"Behind" is (I think) dst-over. Not sure if there are others in there
which are pure Duff-Porter.

For efficiency's sake, the branches I've been working on contain
shortcut flags for the modes which tell the rendering engine whether
it can skip empty source pixels (or tiles!) for a mode, or whether a
mode can ever produce an opacity value less than that of a backdrop
pixel (meaningful for MyPaint with its normally opaque background -
we've historically employed a speedup there too, but now sometimes we
cannot). Beyond that sort of semi-empirical categorizing of modes,
there should be no real surprises, particularly if you already support
an Erase mode.

The main question is really whether they might be of use to artists.
dst-out ("masking fluid/tape", "erase"?) and dst-in ("stencil holes",
"mask"?) make nice masks for their stack if they're on top, and I
strongly suggest we recommend that apps implement them both. I'm still
not sure about src-atop, xor and friends, but svg:plus/Lighter might
be quite widely implemented already.

I've no objection to the spec saying that any from Compositing-1 can
be used and specifying the attribute value to use, but also stating
that only a subset of them are likely to be common to all apps.

If this is to be *the* way of storing layer masks in OpenRaster (and I
don't see why it shouldn't be), then we should think about what the
most efficient way of storing the information in PNG would be
(256-colour indexed palettes with a tRNS map, presumably!). But later.
--
Andrew Chadwick
Loading...