com.enterprisemath.utils.image.BlendImageAnimation Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of em-utils Show documentation
Show all versions of em-utils Show documentation
Collection of utility classes for large scale projects focusing on robust and testable code.
package com.enterprisemath.utils.image;
import java.awt.Color;
import java.awt.image.BufferedImage;
import java.awt.image.Raster;
import java.awt.image.RenderedImage;
import org.apache.commons.lang3.builder.ToStringBuilder;
import com.enterprisemath.utils.ValidationUtils;
/**
* Implementation of image animation which blends 2 animation together. Result frame
* is the mixture of the same frame from the 2 animations.
* Precondition is that both animations have same frame size, frame duration and number of frames.
*
* @author radek.hecl
*
*/
public class BlendImageAnimation implements ImageAnimation {
/**
* Builder object.
*/
public static class Builder {
/**
* Animation which is placed at the bottom.
*/
private ImageAnimation bottom;
/**
* Animation which is placed at the top.
*/
private ImageAnimation top;
/**
* Start blending factor. Must be in interval [0, 1].
* 0 means the bottom animation is fully visible, 1 means the top animation is fully visible.
*/
private Double blendStart;
/**
* End blending factor. Must be in interval [0, 1].
* 0 means the bottom animation is fully visible, 1 means the top animation is fully visible.
*/
private Double blendEnd;
/**
* Sets bottom animation.
*
* @param bottom bottom animation
* @return this instance
*/
public Builder setBottom(ImageAnimation bottom) {
this.bottom = bottom;
return this;
}
/**
* Sets top animation.
*
* @param top top animation
* @return this instance
*/
public Builder setTop(ImageAnimation top) {
this.top = top;
return this;
}
/**
* Sets start blending factor. Must be in interval [0, 1].
* 0 means the bottom animation is fully visible, 1 means the top animation is fully visible.
*
* @param blendStart start blending factor
* @return this instance
*/
public Builder setBlendStart(double blendStart) {
this.blendStart = blendStart;
return this;
}
/**
* Sets end blending factor. Must be in interval [0, 1].
* 0 means the bottom animation is fully visible, 1 means the top animation is fully visible.
*
* @param blendEnd end blending factor
* @return this instance
*/
public Builder setBlendEnd(double blendEnd) {
this.blendEnd = blendEnd;
return this;
}
/**
* Builds the result object.
*
* @return created object
*/
public BlendImageAnimation build() {
return new BlendImageAnimation(this);
}
}
/**
* Animation which is placed at the bottom.
*/
private ImageAnimation bottom;
/**
* Animation which is placed at the top.
*/
private ImageAnimation top;
/**
* Start blending factor. Must be in interval [0, 1].
* 0 means the bottom animation is fully visible, 1 means the top animation is fully visible.
*/
private Double blendStart;
/**
* End blending factor. Must be in interval [0, 1].
* 0 means the bottom animation is fully visible, 1 means the top animation is fully visible.
*/
private Double blendEnd;
/**
* Creates new instance.
*
* @param builder builder object
*/
public BlendImageAnimation(Builder builder) {
bottom = builder.bottom;
top = builder.top;
blendStart = builder.blendStart;
blendEnd = builder.blendEnd;
guardInvariants();
}
/**
* Guards this object to be consistent. Throws exception if this is not the case.
*/
private void guardInvariants() {
ValidationUtils.guardNotNull(bottom, "bottom cannot be null");
ValidationUtils.guardNotNull(top, "top cannot be null");
ValidationUtils.guardEquals(bottom.getFrameWidth(), top.getFrameWidth(), "frameWidth must be equal for both animation");
ValidationUtils.guardEquals(bottom.getFrameHeight(), top.getFrameHeight(), "getFrameHeight must be equal for both animation");
ValidationUtils.guardEquals(bottom.getFrameDuration(), top.getFrameDuration(), "getFrameDuration must be equal for both animation");
ValidationUtils.guardEquals(bottom.getNumFrames(), top.getNumFrames(), "getNumFrames must be equal for both animation");
ValidationUtils.guardGreaterOrEqualDouble(1, blendStart, "blendStart must be in interval [0, 1]");
ValidationUtils.guardGreaterOrEqualDouble(blendStart, 0, "blendStart must be in interval [0, 1]");
ValidationUtils.guardGreaterOrEqualDouble(1, blendEnd, "blendEnd must be in interval [0, 1]");
ValidationUtils.guardGreaterOrEqualDouble(blendEnd, 0, "blendEnd must be in interval [0, 1]");
}
@Override
public int getFrameWidth() {
return bottom.getFrameWidth();
}
@Override
public int getFrameHeight() {
return bottom.getFrameHeight();
}
@Override
public int getNumFrames() {
return bottom.getNumFrames();
}
@Override
public int getFrameDuration() {
return bottom.getFrameDuration();
}
@Override
public RenderedImage getFrame(int index) {
RenderedImage bimg = bottom.getFrame(index);
RenderedImage timg = top.getFrame(index);
Raster brast = bimg.getData();
Raster trast = timg.getData();
double tt = blendStart + (blendEnd - blendStart) / (bottom.getNumFrames() - 1) * index;
double tb = 1 - tt;
BufferedImage res = new BufferedImage(bottom.getFrameWidth(), bottom.getFrameHeight(), BufferedImage.TYPE_4BYTE_ABGR);
int[] bpix = new int[4];
int[] tpix = new int[4];
Color c = null;
for (int x = 0; x < bottom.getFrameWidth(); ++x) {
for (int y = 0; y < bottom.getFrameHeight(); ++y) {
brast.getPixel(x, y, bpix);
trast.getPixel(x, y, tpix);
c = new Color((int)(bpix[0] * tb + tpix[0] * tt),
(int)(bpix[1] * tb + tpix[1] * tt),
(int)(bpix[2] * tb + tpix[2] * tt),
(int)(bpix[3] * tb + tpix[3] * tt));
res.setRGB(x, y, c.getRGB());
}
}
return res;
}
@Override
public String toString() {
return ToStringBuilder.reflectionToString(this);
}
/**
* Creates new instance.
*
* @param bottom bottom animation
* @param top top animation
* @param blendStart start blending factor in interval [0, 1]
* @param blendEnd end blending factor in interval [0, 1]
* @return created object
*/
public static BlendImageAnimation create(ImageAnimation bottom, ImageAnimation top, double blendStart, double blendEnd) {
return new BlendImageAnimation.Builder().
setBottom(bottom).
setTop(top).
setBlendStart(blendStart).
setBlendEnd(blendEnd).
build();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy