[OpenRaster] proposal: new layer modes, ref updates, extra properties for layer groups, impact on apps

Andrew Chadwick a.t.chadwick at gmail.com
Tue Feb 18 07:20:42 PST 2014

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

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

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

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

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::

    ├ "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::

    ├ "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

More information about the xdg mailing list