Skip to content

Instantly share code, notes, and snippets.

@achadwick
Last active December 30, 2015 12:19
Show Gist options
  • Save achadwick/7827931 to your computer and use it in GitHub Desktop.
Save achadwick/7827931 to your computer and use it in GitHub Desktop.
Some proposed updates to the OpenRaster stack specification.

Updates to the OpenRaster Stack Specification

I would like to propose the following (updated) amendments to the OpenRaster specification. 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 format would allow MyPaint, an app I co-maintain, implement layer masking. There is accordingly an experimental code branch with a draft implementation of these updates.

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.

We could also add support for all Porter-Duff operators as defined in this and in Compositing-1, 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 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 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 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 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.

@manuq
Copy link

manuq commented Jan 19, 2014

Hi Andrew,

the usage of "svg:" prefix in composite-op is to be compliant with the w3c spec? Great work!

@achadwick
Copy link
Author

Hi manuq. "composite-op" is the existing attribute's name, and the svg: prefix does indeed refer to the SVG 1.2 specification's notion of compositing. I don't think the "svg:" prefix was ever part of any W3C spec, and it doesn't refer to a namespace in OpenRaster - I think it was always just there for extensibility, in case OpenRaster needed to define new kinds of blending mode. Perhaps we can do the same thing with these without too much fuss.

In my opinion, the newer spec, Compositing and Blending Level 1, is a better fit for raster graphics editors because it specifies very clearly the order of operations to take, and (crucially for masking) how sub-groups are supposed to composite. It also makes a clear distinction between "blending" (combining colours from a layer and its backdrop) and "compositing" (taking the result of the blend and stamping it down onto the backdrop). A layer in the model described above can have both a blending mode and a compositing mode. The fancy compositing modes are quite difficult to understand in the raw, but app developers can implement masking (and texturing) with them, and if everyone agrees on using the new model then layer masks could be shared.

@achadwick
Copy link
Author

@achadwick
Copy link
Author

Subsequent to the earlier comments here, I received feedback asking for compositing not to be split from blending for reasons of UI complexity and code path proliferation. A fair point. Proposal updated, and a new test branch for comparison is now up at https://gitorious.org/mypaint/achadwick-mypaint/graph/layer-enhancements-exp-alt

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment