Skip to content

Commit

Permalink
Added support for gaussian blurs (#1859)
Browse files Browse the repository at this point in the history
  • Loading branch information
gpeal authored Aug 1, 2021
1 parent cf45385 commit c52e752
Show file tree
Hide file tree
Showing 17 changed files with 264 additions and 14 deletions.
4 changes: 4 additions & 0 deletions lottie/src/main/java/com/airbnb/lottie/LottieProperty.java
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,10 @@ public interface LottieProperty {
* When split dimensions is enabled. In Px
*/
Float TRANSFORM_POSITION_Y = 16f;
/**
* In Px
*/
Float BLUR_RADIUS = 17f;
/**
* In Px
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import static com.airbnb.lottie.utils.MiscUtils.clamp;

import android.graphics.BlurMaskFilter;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.DashPathEffect;
Expand Down Expand Up @@ -47,11 +48,14 @@ public abstract class BaseStrokeContent
private final float[] dashPatternValues;
final Paint paint = new LPaint(Paint.ANTI_ALIAS_FLAG);


private final BaseKeyframeAnimation<?, Float> widthAnimation;
private final BaseKeyframeAnimation<?, Integer> opacityAnimation;
private final List<BaseKeyframeAnimation<?, Float>> dashPatternAnimations;
@Nullable private final BaseKeyframeAnimation<?, Float> dashPatternOffsetAnimation;
@Nullable private BaseKeyframeAnimation<ColorFilter, ColorFilter> colorFilterAnimation;
@Nullable private BaseKeyframeAnimation<Float, Float> blurAnimation;
float blurMaskFilterRadius = 0f;

BaseStrokeContent(final LottieDrawable lottieDrawable, BaseLayer layer, Paint.Cap cap,
Paint.Join join, float miterLimit, AnimatableIntegerValue opacity, AnimatableFloatValue width,
Expand Down Expand Up @@ -97,6 +101,14 @@ public abstract class BaseStrokeContent
if (dashPatternOffsetAnimation != null) {
dashPatternOffsetAnimation.addUpdateListener(this);
}

if (layer.getBlurEffect() == null) {
blurAnimation = null;
} else {
blurAnimation = layer.getBlurEffect().getBlurriness().createAnimation();
blurAnimation.addUpdateListener(this);
layer.addAnimation(blurAnimation);
}
}

@Override public void onValueChanged() {
Expand Down Expand Up @@ -158,6 +170,17 @@ public abstract class BaseStrokeContent
paint.setColorFilter(colorFilterAnimation.getValue());
}

if (blurAnimation != null) {
float blurRadius = blurAnimation.getValue();
if (blurRadius == 0f) {
paint.setMaskFilter(null);
} else if (blurRadius != blurMaskFilterRadius){
BlurMaskFilter blur = layer.getBlurMaskFilter(blurRadius);
paint.setMaskFilter(blur);
}
blurMaskFilterRadius = blurRadius;
}

for (int i = 0; i < pathGroups.size(); i++) {
PathGroup pathGroup = pathGroups.get(i);

Expand Down Expand Up @@ -327,6 +350,15 @@ public <T> void addValueCallback(T property, @Nullable LottieValueCallback<T> ca
colorFilterAnimation.addUpdateListener(this);
layer.addAnimation(colorFilterAnimation);
}
} else if (property == LottieProperty.BLUR_RADIUS) {
if (blurAnimation != null) {
blurAnimation.setValueCallback((LottieValueCallback<Float>) callback);
} else {
blurAnimation =
new ValueCallbackKeyframeAnimation<>((LottieValueCallback<Float>) callback);
blurAnimation.addUpdateListener(this);
layer.addAnimation(blurAnimation);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import static com.airbnb.lottie.utils.MiscUtils.clamp;

import android.graphics.BlurMaskFilter;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.Matrix;
Expand All @@ -17,6 +18,7 @@
import com.airbnb.lottie.animation.LPaint;
import com.airbnb.lottie.animation.keyframe.BaseKeyframeAnimation;
import com.airbnb.lottie.animation.keyframe.ColorKeyframeAnimation;
import com.airbnb.lottie.animation.keyframe.FloatKeyframeAnimation;
import com.airbnb.lottie.animation.keyframe.ValueCallbackKeyframeAnimation;
import com.airbnb.lottie.model.KeyPath;
import com.airbnb.lottie.model.content.ShapeFill;
Expand All @@ -39,12 +41,22 @@ public class FillContent
private final BaseKeyframeAnimation<Integer, Integer> opacityAnimation;
@Nullable private BaseKeyframeAnimation<ColorFilter, ColorFilter> colorFilterAnimation;
private final LottieDrawable lottieDrawable;
@Nullable private BaseKeyframeAnimation<Float, Float> blurAnimation;
float blurMaskFilterRadius;

public FillContent(final LottieDrawable lottieDrawable, BaseLayer layer, ShapeFill fill) {
this.layer = layer;
name = fill.getName();
hidden = fill.isHidden();
this.lottieDrawable = lottieDrawable;
if (layer.getBlurEffect() == null) {
blurAnimation = null;
} else {
blurAnimation = layer.getBlurEffect().getBlurriness().createAnimation();
blurAnimation.addUpdateListener(this);
layer.addAnimation(blurAnimation);
}

if (fill.getColor() == null || fill.getOpacity() == null) {
colorAnimation = null;
opacityAnimation = null;
Expand Down Expand Up @@ -91,6 +103,17 @@ public FillContent(final LottieDrawable lottieDrawable, BaseLayer layer, ShapeFi
paint.setColorFilter(colorFilterAnimation.getValue());
}

if (blurAnimation != null) {
float blurRadius = blurAnimation.getValue();
if (blurRadius == 0f) {
paint.setMaskFilter(null);
} else if (blurRadius != blurMaskFilterRadius){
BlurMaskFilter blur = layer.getBlurMaskFilter(blurRadius);
paint.setMaskFilter(blur);
}
blurMaskFilterRadius = blurRadius;
}

path.reset();
for (int i = 0; i < paths.size(); i++) {
path.addPath(paths.get(i).getPath(), parentMatrix);
Expand Down Expand Up @@ -141,6 +164,15 @@ public <T> void addValueCallback(T property, @Nullable LottieValueCallback<T> ca
colorFilterAnimation.addUpdateListener(this);
layer.addAnimation(colorFilterAnimation);
}
} else if (property == LottieProperty.BLUR_RADIUS) {
if (blurAnimation != null) {
blurAnimation.setValueCallback((LottieValueCallback<Float>) callback);
} else {
blurAnimation =
new ValueCallbackKeyframeAnimation<>((LottieValueCallback<Float>) callback);
blurAnimation.addUpdateListener(this);
layer.addAnimation(blurAnimation);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import static com.airbnb.lottie.utils.MiscUtils.clamp;

import android.graphics.BlurMaskFilter;
import android.graphics.Canvas;
import android.graphics.ColorFilter;
import android.graphics.LinearGradient;
Expand All @@ -22,6 +23,7 @@
import com.airbnb.lottie.LottieProperty;
import com.airbnb.lottie.animation.LPaint;
import com.airbnb.lottie.animation.keyframe.BaseKeyframeAnimation;
import com.airbnb.lottie.animation.keyframe.FloatKeyframeAnimation;
import com.airbnb.lottie.animation.keyframe.ValueCallbackKeyframeAnimation;
import com.airbnb.lottie.model.KeyPath;
import com.airbnb.lottie.model.content.GradientColor;
Expand Down Expand Up @@ -58,6 +60,8 @@ public class GradientFillContent
@Nullable private ValueCallbackKeyframeAnimation colorCallbackAnimation;
private final LottieDrawable lottieDrawable;
private final int cacheSteps;
@Nullable private BaseKeyframeAnimation<Float, Float> blurAnimation;
float blurMaskFilterRadius = 0f;

public GradientFillContent(final LottieDrawable lottieDrawable, BaseLayer layer, GradientFill fill) {
this.layer = layer;
Expand All @@ -83,6 +87,14 @@ public GradientFillContent(final LottieDrawable lottieDrawable, BaseLayer layer,
endPointAnimation = fill.getEndPoint().createAnimation();
endPointAnimation.addUpdateListener(this);
layer.addAnimation(endPointAnimation);

if (layer.getBlurEffect() == null) {
blurAnimation = null;
} else {
blurAnimation = layer.getBlurEffect().getBlurriness().createAnimation();
blurAnimation.addUpdateListener(this);
layer.addAnimation(blurAnimation);
}
}

@Override public void onValueChanged() {
Expand Down Expand Up @@ -123,6 +135,17 @@ public GradientFillContent(final LottieDrawable lottieDrawable, BaseLayer layer,
paint.setColorFilter(colorFilterAnimation.getValue());
}

if (blurAnimation != null) {
float blurRadius = blurAnimation.getValue();
if (blurRadius == 0f) {
paint.setMaskFilter(null);
} else if (blurRadius != blurMaskFilterRadius){
BlurMaskFilter blur = new BlurMaskFilter(blurRadius, BlurMaskFilter.Blur.NORMAL);
paint.setMaskFilter(blur);
}
blurMaskFilterRadius = blurRadius;
}

int alpha = (int) ((parentAlpha / 255f * opacityAnimation.getValue() / 100f) * 255);
paint.setAlpha(clamp(alpha, 0, 255));

Expand Down Expand Up @@ -263,6 +286,15 @@ public <T> void addValueCallback(T property, @Nullable LottieValueCallback<T> ca
colorCallbackAnimation.addUpdateListener(this);
layer.addAnimation(colorCallbackAnimation);
}
} else if (property == LottieProperty.BLUR_RADIUS) {
if (blurAnimation != null) {
blurAnimation.setValueCallback((LottieValueCallback<Float>) callback);
} else {
blurAnimation =
new ValueCallbackKeyframeAnimation<>((LottieValueCallback<Float>) callback);
blurAnimation.addUpdateListener(this);
layer.addAnimation(blurAnimation);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.airbnb.lottie.model.content;

import com.airbnb.lottie.model.animatable.AnimatableFloatValue;

public class BlurEffect {

final AnimatableFloatValue blurriness;

public BlurEffect(AnimatableFloatValue blurriness) {
this.blurriness = blurriness;
}

public AnimatableFloatValue getBlurriness() {
return blurriness;
}
}
24 changes: 22 additions & 2 deletions lottie/src/main/java/com/airbnb/lottie/model/layer/BaseLayer.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.airbnb.lottie.model.layer;

import android.graphics.BlurMaskFilter;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
Expand All @@ -9,6 +10,7 @@
import android.graphics.PorterDuffXfermode;
import android.graphics.RectF;
import android.os.Build;
import android.util.Log;

import androidx.annotation.CallSuper;
import androidx.annotation.FloatRange;
Expand All @@ -26,6 +28,7 @@
import com.airbnb.lottie.animation.keyframe.TransformKeyframeAnimation;
import com.airbnb.lottie.model.KeyPath;
import com.airbnb.lottie.model.KeyPathElement;
import com.airbnb.lottie.model.content.BlurEffect;
import com.airbnb.lottie.model.content.Mask;
import com.airbnb.lottie.model.content.ShapeData;
import com.airbnb.lottie.utils.Logger;
Expand All @@ -49,10 +52,10 @@ public abstract class BaseLayer

@Nullable
static BaseLayer forModel(
Layer layerModel, LottieDrawable drawable, LottieComposition composition) {
CompositionLayer compositionLayer, Layer layerModel, LottieDrawable drawable, LottieComposition composition) {
switch (layerModel.getLayerType()) {
case SHAPE:
return new ShapeLayer(drawable, layerModel);
return new ShapeLayer(drawable, layerModel, compositionLayer);
case PRE_COMP:
return new CompositionLayer(drawable, layerModel,
composition.getPrecomps(layerModel.getRefId()), composition);
Expand Down Expand Up @@ -108,6 +111,9 @@ static BaseLayer forModel(
private boolean outlineMasksAndMattes;
@Nullable private Paint outlineMasksAndMattesPaint;

float blurMaskFilterRadius = 0f;
@Nullable BlurMaskFilter blurMaskFilter;

BaseLayer(LottieDrawable lottieDrawable, Layer layerModel) {
this.lottieDrawable = lottieDrawable;
this.layerModel = layerModel;
Expand Down Expand Up @@ -586,6 +592,20 @@ public String getName() {
return layerModel.getName();
}

@Nullable
public BlurEffect getBlurEffect() {
return layerModel.getBlurEffect();
}

public BlurMaskFilter getBlurMaskFilter(float radius) {
if (blurMaskFilterRadius == radius) {
return blurMaskFilter;
}
blurMaskFilter = new BlurMaskFilter(radius, BlurMaskFilter.Blur.NORMAL);
blurMaskFilterRadius = radius;
return blurMaskFilter;
}

@Override
public void setContents(List<Content> contentsBefore, List<Content> contentsAfter) {
// Do nothing
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ public CompositionLayer(LottieDrawable lottieDrawable, Layer layerModel, List<La
BaseLayer mattedLayer = null;
for (int i = layerModels.size() - 1; i >= 0; i--) {
Layer lm = layerModels.get(i);
BaseLayer layer = BaseLayer.forModel(lm, lottieDrawable, composition);
BaseLayer layer = BaseLayer.forModel(this, lm, lottieDrawable, composition);
if (layer == null) {
continue;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import com.airbnb.lottie.model.animatable.AnimatableTextFrame;
import com.airbnb.lottie.model.animatable.AnimatableTextProperties;
import com.airbnb.lottie.model.animatable.AnimatableTransform;
import com.airbnb.lottie.model.content.BlurEffect;
import com.airbnb.lottie.model.content.ContentModel;
import com.airbnb.lottie.model.content.Mask;
import com.airbnb.lottie.value.Keyframe;
Expand Down Expand Up @@ -57,14 +58,15 @@ public enum MatteType {
private final List<Keyframe<Float>> inOutKeyframes;
private final MatteType matteType;
private final boolean hidden;
@Nullable private final BlurEffect blurEffect;

public Layer(List<ContentModel> shapes, LottieComposition composition, String layerName, long layerId,
LayerType layerType, long parentId, @Nullable String refId, List<Mask> masks,
AnimatableTransform transform, int solidWidth, int solidHeight, int solidColor,
float timeStretch, float startFrame, int preCompWidth, int preCompHeight,
@Nullable AnimatableTextFrame text, @Nullable AnimatableTextProperties textProperties,
List<Keyframe<Float>> inOutKeyframes, MatteType matteType,
@Nullable AnimatableFloatValue timeRemapping, boolean hidden) {
@Nullable AnimatableFloatValue timeRemapping, boolean hidden, @Nullable BlurEffect blurEffect) {
this.shapes = shapes;
this.composition = composition;
this.layerName = layerName;
Expand All @@ -87,6 +89,7 @@ public Layer(List<ContentModel> shapes, LottieComposition composition, String la
this.matteType = matteType;
this.timeRemapping = timeRemapping;
this.hidden = hidden;
this.blurEffect = blurEffect;
}

LottieComposition getComposition() {
Expand Down Expand Up @@ -181,6 +184,10 @@ public boolean isHidden() {
return hidden;
}

@Nullable public BlurEffect getBlurEffect() {
return blurEffect;
}

public String toString(String prefix) {
StringBuilder sb = new StringBuilder();
sb.append(prefix).append(getName()).append("\n");
Expand Down
Loading

0 comments on commit c52e752

Please sign in to comment.