Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Apply blend modes on layer level and add Multiply blend mode #2519

Merged
merged 4 commits into from
Jul 24, 2024

Conversation

geomaster
Copy link
Contributor

@geomaster geomaster commented Jul 23, 2024

This commit improves blend mode support in lottie-android in two ways:

  • Applying blend modes on layer-level, instead of fill level
  • Adding support for the Multiply blend mode

Applying blend modes on layer level

The Lottie format defines blend modes as attributes on a layer. However, lottie-android is presently applying the layer blend modes on a solid color fill only. Notably, this causes any stroked or gradient-filled shapes or image layers to blend incorrectly, such as in this file:

stroke-blending-test.json

(The file contains a filled + stroked shape that renders as a pink square on other platforms, but renders with a visible stroke on lottie-android since its blend mode is applied only on the fill.)

Instead, we move this decision to BaseLayer by analogy to transparent layer handling, which is closer to how the format specifies the property and fixes these cases.

Multiply support

BlendModeCompat is designed to resolve to either a BlendMode (added in Android Q, supporting most modern blend modes) or PorterDuff.Mode (always available, but a smaller choice of modes as it is mostly focused on alpha compositing).

We use BlendModeCompat to support Lottie layer blend modes (bm key) to ensure compatibility on all platforms. For consistency, we don't support values which don't have a PorterDuff.Mode equivalent.

Our support for Lottie blend modes did not include Multiply due to a slightly different behavior between the PorterDuff.MULTIPLY (exposed as BlendModeCompat.MODULATE) and BlendModeCompat.MULTIPLY variants. Namely, the formula used for PorterDuff.MODULATE, combined with alpha-premultiplication done by Skia, means that a layer with an alpha < 1.0 and multiply blend mode will also darken the destination:

Incorrect-Blend

(Multiply-blended layers with < 1.0 alpha on the left, Screen-blended layers with < 1.0 alpha on the right)

However, what we can do instead is clear the canvas with a solid white color instead of transparent before drawing the layer's contents as normal. When blending the resulting bitmap over an opaque background using PorterDuff.MULTIPLY (i.e. BlendModeCompat.MODULATE), the end result will be as if we had used BlendModeCompat.MULTIPLY, since all-1.0 (white) is a multiplication identity:

Correct-Blend

This PR implements the latter solution and adds a consistent support for the Multiply blend mode for all Android versions.

Test file used: blendmode-tests-multiply+screen+bg.zip

BlendModeCompat is designed to use either a BlendMode (added in Android
Q) or PorterDuff.Mode (always available).

Our support for Lottie blend modes did not include Multiply due to a
slightly different formula between the PorterDuff and BlendMode
variants.

However, we did include support for Screen, which suffers from a similar
behavior. Therefore, we are not breaking any consistency by including
Multiply too, and including it provides benefits in terms of more
complete support, as Multiply is a foundational blend mode.
Copy link
Collaborator

@gpeal gpeal left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

Copy link

Snapshot Tests
API 23: Report Diff
API 31: Report Diff

"Proper" MULTIPLY seems to have been added in Android Q, so use the
older MODULATE with a slight hack to ensure proper rendering in our
usecase.
Copy link

Snapshot Tests
API 23: Report Diff
API 31: Report Diff

@geomaster
Copy link
Contributor Author

@gpeal Thanks for the review! Addressed comment. Let me know if there's anything else you see that needs improvement!

Copy link
Collaborator

@gpeal gpeal left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the investigative work here!

Copy link

Snapshot Tests
API 23: Report Diff
API 31: Report Diff

@gpeal gpeal merged commit 328fc72 into airbnb:master Jul 24, 2024
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants