/*
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package org.apache.batik.ext.awt.image.renderable;
import java.awt.Composite;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.geom.AffineTransform;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.awt.image.RenderedImage;
import java.awt.image.renderable.RenderContext;
import org.apache.batik.ext.awt.image.GraphicsUtil;
import org.apache.batik.ext.awt.image.PadMode;
import org.apache.batik.ext.awt.image.SVGComposite;
import org.apache.batik.ext.awt.image.rendered.CachableRed;
import org.apache.batik.ext.awt.image.rendered.PadRed;
Concrete implementation of the PadRable interface.
This pads the image to a specified rectangle in user coord system.
Author: Thomas DeWeese Version: $Id: PadRable8Bit.java 1733416 2016-03-03 07:07:13Z gadams $
/**
* Concrete implementation of the PadRable interface.
* This pads the image to a specified rectangle in user coord system.
*
* @author <a href="mailto:Thomas.DeWeeese@Kodak.com">Thomas DeWeese</a>
* @version $Id: PadRable8Bit.java 1733416 2016-03-03 07:07:13Z gadams $
*/
public class PadRable8Bit extends AbstractRable
implements PadRable, PaintRable {
PadMode padMode;
Rectangle2D padRect;
public PadRable8Bit(Filter src,
Rectangle2D padRect,
PadMode padMode) {
super.init(src, null);
this.padRect = padRect;
this.padMode = padMode;
}
Returns the source to be affine.
/**
* Returns the source to be affine.
*/
public Filter getSource() {
return (Filter)srcs.get(0);
}
Sets the source to be affine.
Params: - src – image to affine.
/**
* Sets the source to be affine.
* @param src image to affine.
*/
public void setSource(Filter src) {
super.init(src, null);
}
public Rectangle2D getBounds2D() {
return (Rectangle2D)padRect.clone();
}
Set the current rectangle for padding.
Params: - rect – the new rectangle to use for pad.
/**
* Set the current rectangle for padding.
* @param rect the new rectangle to use for pad.
*/
public void setPadRect(Rectangle2D rect) {
touch();
this.padRect = rect;
}
Get the current rectangle for padding
Returns: Rectangle currently in use for pad.
/**
* Get the current rectangle for padding
* @return Rectangle currently in use for pad.
*/
public Rectangle2D getPadRect() {
return (Rectangle2D)padRect.clone();
}
Set the current extension mode for pad
Params: - padMode – the new pad mode
/**
* Set the current extension mode for pad
* @param padMode the new pad mode
*/
public void setPadMode(PadMode padMode) {
touch();
this.padMode = padMode;
}
Get the current extension mode for pad
Returns: Mode currently in use for pad
/**
* Get the current extension mode for pad
* @return Mode currently in use for pad
*/
public PadMode getPadMode() {
return padMode;
}
Should perform the equivilent action as
createRendering followed by drawing the RenderedImage to
Graphics2D, or return false.
Params: - g2d – The Graphics2D to draw to.
Returns: true if the paint call succeeded, false if
for some reason the paint failed (in which
case a createRendering should be used).
/**
* Should perform the equivilent action as
* createRendering followed by drawing the RenderedImage to
* Graphics2D, or return false.
*
* @param g2d The Graphics2D to draw to.
* @return true if the paint call succeeded, false if
* for some reason the paint failed (in which
* case a createRendering should be used).
*/
public boolean paintRable(Graphics2D g2d) {
// This optimization only apply if we are using
// SrcOver. Otherwise things break...
Composite c = g2d.getComposite();
if (!SVGComposite.OVER.equals(c))
return false;
if (getPadMode() != PadMode.ZERO_PAD)
return false;
Rectangle2D padBounds = getPadRect();
Shape clip = g2d.getClip();
g2d.clip(padBounds);
GraphicsUtil.drawImage(g2d, getSource());
g2d.setClip(clip);
return true;
}
public RenderedImage createRendering(RenderContext rc) {
RenderingHints rh = rc.getRenderingHints();
if (rh == null) rh = new RenderingHints(null);
Filter src = getSource();
Shape aoi = rc.getAreaOfInterest();
if(aoi == null){
aoi = getBounds2D();
}
AffineTransform usr2dev = rc.getTransform();
// We only depend on our source for stuff that is inside
// our bounds and his bounds (remember our bounds may be
// tighter than his in one or both directions).
Rectangle2D srect = src.getBounds2D();
Rectangle2D rect = getBounds2D();
Rectangle2D arect = aoi.getBounds2D();
// System.out.println("Rects Src:" + srect +
// "My: " + rect +
// "AOI: " + arect);
if ( ! arect.intersects(rect) )
return null;
Rectangle2D.intersect(arect, rect, arect);
RenderedImage ri = null;
if ( arect.intersects(srect) ) {
srect = (Rectangle2D)srect.clone();
Rectangle2D.intersect(srect, arect, srect);
RenderContext srcRC = new RenderContext(usr2dev, srect, rh);
ri = src.createRendering(srcRC);
// System.out.println("Pad filt: " + src + " R: " +
// src.getBounds2D());
}
// No source image so create a 1,1 transparent one...
if (ri == null)
ri = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB);
// org.apache.batik.test.gvt.ImageDisplay.showImage("Paded: ", ri);
// System.out.println("RI: " + ri + " R: " + srect);
CachableRed cr = GraphicsUtil.wrap(ri);
arect = usr2dev.createTransformedShape(arect).getBounds2D();
// System.out.println("Pad rect : " + arect);
// Use arect (my bounds intersect area of interest)
cr = new PadRed(cr, arect.getBounds(), padMode, rh);
return cr;
}
public Shape getDependencyRegion(int srcIndex, Rectangle2D outputRgn) {
if (srcIndex != 0)
throw new IndexOutOfBoundsException("Affine only has one input");
// We only depend on our source for stuff that is inside
// our bounds and his bounds (remember our bounds may be
// tighter than his in one or both directions).
Rectangle2D srect = getSource().getBounds2D();
if ( ! srect.intersects(outputRgn) )
return new Rectangle2D.Float();
Rectangle2D.intersect(srect, outputRgn, srect);
Rectangle2D bounds = getBounds2D();
if ( ! srect.intersects(bounds) )
return new Rectangle2D.Float();
Rectangle2D.intersect(srect, bounds, srect);
return srect;
}
public Shape getDirtyRegion(int srcIndex, Rectangle2D inputRgn) {
if (srcIndex != 0)
throw new IndexOutOfBoundsException("Affine only has one input");
inputRgn = (Rectangle2D)inputRgn.clone();
Rectangle2D bounds = getBounds2D();
// Changes in the input region don't propogate outside our
// bounds.
if ( ! inputRgn.intersects(bounds) )
return new Rectangle2D.Float();
Rectangle2D.intersect(inputRgn, bounds, inputRgn);
return inputRgn;
}
}