Re: [fxtf-drafts] [compositing-2] Add support for add, subtract and divide blending modes. (#449)

I started to draft a spec change and also write WPT tests based on the existing plus-lighter tests. In the process of this, it's been made clear that while add is trivially simple, subtract and divide are harder than would first appear, at least depending on which existing implementations the math should aim to match.

Firstly, it seems that how Subtract and Divide is implemented is not universal across software. When the alpha component of colors being subtracted or divided is 1.0, all programs produce the same result, but when blending two or more colors with alphas of less than 1.0, the results diverge.

When testing with less than 1.0 alpha colors, about half of the software I tried[^1] would produce the same result, while the other half[^2] would all produce wildly different results from even each other. Of all programs tested, only DaVinci Resolve matches the trivial math I originally posted.

As an example, taking a bottom layer of pure white with an alpha of 0.5, and a top layer of pure blue with an alpha of 0.5, the former group would all produce a perfect grey[^4], while the latter group would all produce colors that would tend more towards yellow.

The definition that the former group follows for subtract is represented like this...

```
Subtract:
B(Cb, Cs, αb) = max(0, Cb + Cs * (1 - 2αb))
```

The definition that that group follows for divide is represented like this...

```
Divide:
if (Cb == 0)
    B(Cb, Cs, αb) = 0 + Cs * (1 - αb)
else
    B(Cb, Cs, αb, αs) = Cd * (1 - αs) + min(Cd / Cs, αd) * αs + Cs * (1 - αd)
```

Implementing these alternative definitions in my tests based on the plus-lighter WPT tests produce identical results as Photoshop with two colors, and are seemingly within a margin of error of each other when combining several colors (possible rounding step that Photoshop and AE do in 8bpc color mode that the test avoids?).

While I can't speak for whether the subtract definition should be considered "correct", the trivial definition for divide I originally provided definitely has problems—namely that as the alpha of the top color decreases, rather than having less of an effect on the backdrop, it would actually make the backdrop whiter as the premultiplied color component gets closer to, and eventually reaches 0. An alternative definition based on the trivial math but fixes that particular bug might look like the following:

```
Divide:
if (Cb == 0)
    B(Cb, Cs) = 0
else
    B(Cb, Cs, αb, αs) = Cd * (1 - αs) + min(Cd / Cs, αd) * αs
```

I'm inclined to believe that the Photoshop math is correct in this instance and should be what such a blend mode on the web should follow.

Whether it uses the Photoshop math or not, at least one of these definitions would need the alpha components to be included in the calculation to produce a sensible result, which does not match any of the existing blending modes. Would that therefore make them compositing operations instead? If not, would it still be considered a separable blending mode, as it still applies to the individual color components separately, even though the alpha is now included in the calculation?

Would there be any implementation concerns, given the use of alpha components in the calculation, but still needing to work with all other existing compositing operations in the context of Canvas 2D?

Is there any strong preferences that others have for which is the "correct" way of implementing these blending modes?

[^1]: Photoshop, After Effects, paint.net, Krita and ImageMagick.
[^2]: Clip Studio Paint, GNU Image Manipulation Program, FFmpeg[^3], OBS Studio (Beta), and DaVinci Resolve.
[^3]: Despite multiple attempts with the filtergraph to rectify this, when subtracting color components FFmpeg would also seemingly subtract the alpha components. This may mean that I simply was executing the filter incorrectly, and it may actually produce the result of the former group if ran correctly. Until I can find out otherwise, I am ignoring the alpha component and assuming the result for the color component to be correct.
[^4]: The reason for the perfect grey is because those programs are using the inverse of the alpha of the backdrop as a multiplier for how much of the top layers color to keep visible. If the backdrop has an alpha of 0, then those programs expect the color on top to passthrough unchanged (in this case, showing blue), but if the backdrop has an alpha of 1, then those programs expect the result to match the result of the trivial subtraction (in this case, it would show yellow). The midpoint of these two colors is grey, so the alpha of 0.5 on the backdrop results in a grey.

-- 
GitHub Notification of comment by VodBox
Please view or discuss this issue at https://github.com/w3c/fxtf-drafts/issues/449#issuecomment-1037241031 using your GitHub account


-- 
Sent via github-notify-ml as configured in https://github.com/w3c/github-notify-ml-config

Received on Saturday, 12 February 2022 14:30:23 UTC