All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.enterprisemath.utils.image.BlendImageAnimation Maven / Gradle / Ivy

Go to download

Collection of utility classes for large scale projects focusing on robust and testable code.

There is a newer version: 4.1.1
Show newest version
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