Apply blend modes on layer level and add Multiply blend mode#2519
Merged
gpeal merged 4 commits intoairbnb:masterfrom Jul 24, 2024
Merged
Apply blend modes on layer level and add Multiply blend mode#2519gpeal merged 4 commits intoairbnb:masterfrom
gpeal merged 4 commits intoairbnb:masterfrom
Conversation
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.
"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.
gpeal
reviewed
Jul 24, 2024
lottie/src/main/java/com/airbnb/lottie/model/layer/BaseLayer.java
Outdated
Show resolved
Hide resolved
Contributor
Author
|
@gpeal Thanks for the review! Addressed comment. Let me know if there's anything else you see that needs improvement! |
gpeal
approved these changes
Jul 24, 2024
Collaborator
gpeal
left a comment
There was a problem hiding this comment.
Thanks for the investigative work here!
gpeal
approved these changes
Jul 24, 2024
allenchen1154
pushed a commit
that referenced
this pull request
Sep 13, 2025
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](https://github.com/user-attachments/files/16346206/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:  (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:  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](https://github.com/user-attachments/files/16365843/blendmode-tests-multiply%2Bscreen%2Bbg.zip)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
This commit improves blend mode support in lottie-android in two ways:
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
BaseLayerby analogy to transparent layer handling, which is closer to how the format specifies the property and fixes these cases.Multiply support
BlendModeCompatis designed to resolve to either aBlendMode(added in Android Q, supporting most modern blend modes) orPorterDuff.Mode(always available, but a smaller choice of modes as it is mostly focused on alpha compositing).We use
BlendModeCompatto support Lottie layer blend modes (bmkey) to ensure compatibility on all platforms. For consistency, we don't support values which don't have aPorterDuff.Modeequivalent.Our support for Lottie blend modes did not include Multiply due to a slightly different behavior between the
PorterDuff.MULTIPLY(exposed asBlendModeCompat.MODULATE) andBlendModeCompat.MULTIPLYvariants. Namely, the formula used forPorterDuff.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:(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 usedBlendModeCompat.MULTIPLY, since all-1.0 (white) is a multiplication identity: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