/*
* @(#)ImageInstruction.java
*
* $Date: 2014-03-13 09:15:48 +0100 (Cs, 13 márc. 2014) $
*
* Copyright (c) 2011 by Jeremy Wood.
* All rights reserved.
*
* The copyright of this software is owned by Jeremy Wood.
* You may not use, copy or modify this software, except in
* accordance with the license agreement you entered into with
* Jeremy Wood. For details see accompanying license terms.
*
* This software is probably, but not necessarily, discussed here:
* https://javagraphics.java.net/
*
* That site should also contain the most recent official version
* of this software. (See the SVN repository for more details.)
*/
package com.bric.image.transition;
import com.bric.geom.Clipper;
import com.bric.geom.RectangularTransform;
import com.bric.geom.ShapeStringUtils;
import org.jdesktop.swingx.graphics.BlendComposite;
import java.awt.AlphaComposite;
import java.awt.Composite;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.GeneralPath;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
/** This is an instruction to render an image.
*/
public class ImageInstruction extends Transition2DInstruction {
/** If this is true, then this instruction relates to Frame A. Otherwise this relates to Frame B. */
public boolean isFirstFrame = true;
/** This is the clipping to apply. This may be null, indicating that clipping is not needed. */
public Shape clipping = null;
/** This is the transform to render this graphic through. This may be null, indicating that no transform is needed. */
public AffineTransform transform = null;
/** This is the opacity of this image. By default this value is 1. */
public float opacity = 1;
public ImageInstruction(boolean isFirstFrame,float opacity,AffineTransform transform,Shape clipping) {
this(isFirstFrame,transform,clipping);
this.opacity = opacity;
}
public ImageInstruction(boolean isFirstFrame,float opacity) {
this(isFirstFrame);
this.opacity = opacity;
}
public ImageInstruction(boolean isFirstFrame,float opacity,Rectangle2D dest,Dimension frameSize,Shape clipping) {
this(isFirstFrame,opacity,RectangularTransform.create(new Rectangle2D.Double(0,0,frameSize.width,frameSize.height),dest),clipping);
}
/** Renders a completely opaque image, anchored at (0,0), at its original
* size with no clipping.
* @param isFirstFrame indicates whether to use the original image or
* the incoming image.
*/
public ImageInstruction(boolean isFirstFrame) {
this(isFirstFrame,null,null);
}
@Override
public String toString() {
String clippingString = (clipping==null) ? "null" : ShapeStringUtils.toString(clipping);
return "ImageInstruction[ isFirstFrame = "+isFirstFrame+", transform = "+transform+", clipping = "+clippingString+" opacity="+opacity+"]";
}
/** Creates a shallow clone of the argument */
public ImageInstruction(ImageInstruction i) {
this.clipping = i.clipping;
this.isFirstFrame = i.isFirstFrame;
this.transform = i.transform;
this.opacity = i.opacity;
}
public ImageInstruction(boolean isFirstFrame,AffineTransform transform,Shape clipping) {
this.isFirstFrame = isFirstFrame;
if(transform!=null)
this.transform = new AffineTransform(transform);
if(clipping!=null) {
if(clipping instanceof Rectangle) {
this.clipping = new Rectangle((Rectangle)clipping);
} else if(clipping instanceof Rectangle2D) {
Rectangle2D r = new Rectangle2D.Float();
r.setFrame((Rectangle2D)clipping);
this.clipping = r;
} else {
this.clipping = new GeneralPath(clipping);
}
}
}
public ImageInstruction(boolean isFirstFrame,Rectangle2D dest,Dimension frameSize,Shape clipping) {
this(isFirstFrame,RectangularTransform.create(new Rectangle2D.Double(0,0,frameSize.width,frameSize.height),dest),clipping);
}
@Override
public void paint(Graphics2D g, BufferedImage frameA, BufferedImage frameB) {
// Laszlo: In Pixelitor frameB is always transparent, the following
// code will work only in that case - but the original code used to work
// only with opaque images, see http://javagraphics.blogspot.hu/2008/06/crossfades-what-is-and-isnt-possible.html
BufferedImage img = isFirstFrame ? frameA : frameB;
Composite oldComposite = null;
// if(opacity!=1) {
oldComposite = g.getComposite();
// g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, opacity));
// g.setComposite(new CrossFadeToTransparentComposite(opacity));
// g.setComposite(new AddComposite(opacity));
// g.setComposite(BlendComposite.Src.derive(opacity));
if(isFirstFrame) {
g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, opacity));
} else {
// g.setComposite(AlphaComposite.getInstance(AlphaComposite.DST_OUT, opacity));
g.setComposite(BlendComposite.CrossFade.derive(opacity));
}
//}
Shape oldClipping = null;
if(clipping!=null) {
oldClipping = g.getClip();
Clipper.clip(g, clipping);
}
g.drawImage(img,transform,null);
if(clipping!=null)
g.setClip(oldClipping);
if(opacity!=1) {
g.setComposite(oldComposite);
}
}
}