001: /*
002:
003: Licensed to the Apache Software Foundation (ASF) under one or more
004: contributor license agreements. See the NOTICE file distributed with
005: this work for additional information regarding copyright ownership.
006: The ASF licenses this file to You under the Apache License, Version 2.0
007: (the "License"); you may not use this file except in compliance with
008: the License. You may obtain a copy of the License at
009:
010: http://www.apache.org/licenses/LICENSE-2.0
011:
012: Unless required by applicable law or agreed to in writing, software
013: distributed under the License is distributed on an "AS IS" BASIS,
014: WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015: See the License for the specific language governing permissions and
016: limitations under the License.
017:
018: */
019: package org.apache.batik.ext.awt.image.renderable;
020:
021: import java.awt.Color;
022: import java.awt.Graphics2D;
023: import java.awt.Rectangle;
024: import java.awt.RenderingHints;
025: import java.awt.Shape;
026: import java.awt.geom.AffineTransform;
027: import java.awt.geom.Rectangle2D;
028: import java.awt.image.BufferedImage;
029: import java.awt.image.RenderedImage;
030: import java.awt.image.renderable.RenderContext;
031:
032: import org.apache.batik.ext.awt.image.GraphicsUtil;
033: import org.apache.batik.ext.awt.image.PadMode;
034: import org.apache.batik.ext.awt.image.rendered.BufferedImageCachableRed;
035: import org.apache.batik.ext.awt.image.rendered.CachableRed;
036: import org.apache.batik.ext.awt.image.rendered.MultiplyAlphaRed;
037: import org.apache.batik.ext.awt.image.rendered.PadRed;
038: import org.apache.batik.ext.awt.image.rendered.RenderedImageCachableRed;
039:
040: /**
041: * ClipRable implementation
042: *
043: * @author <a href="mailto:Thomas.DeWeese@Kodak.com">Thomas DeWeese</a>
044: * @version $Id: ClipRable8Bit.java 478276 2006-11-22 18:33:37Z dvholten $
045: */
046: public class ClipRable8Bit extends AbstractRable implements ClipRable {
047:
048: protected boolean useAA;
049:
050: /**
051: * The node who's outline specifies our mask.
052: */
053: protected Shape clipPath;
054:
055: public ClipRable8Bit(Filter src, Shape clipPath) {
056: super (src, null);
057: setClipPath(clipPath);
058: setUseAntialiasedClip(false);
059: }
060:
061: public ClipRable8Bit(Filter src, Shape clipPath, boolean useAA) {
062: super (src, null);
063: setClipPath(clipPath);
064: setUseAntialiasedClip(useAA);
065: }
066:
067: /**
068: * The source to be masked by the mask node.
069: * @param src The Image to be masked.
070: */
071: public void setSource(Filter src) {
072: init(src, null);
073: }
074:
075: /**
076: * This returns the current image being masked by the mask node.
077: * @return The image to mask
078: */
079: public Filter getSource() {
080: return (Filter) getSources().get(0);
081: }
082:
083: /**
084: * Set the default behaviour of anti-aliased clipping.
085: * for this clip object.
086: */
087: public void setUseAntialiasedClip(boolean useAA) {
088: touch();
089: this .useAA = useAA;
090: }
091:
092: /**
093: * Resturns true if the default behaviour should be to use
094: * anti-aliased clipping.
095: */
096: public boolean getUseAntialiasedClip() {
097: return useAA;
098: }
099:
100: /**
101: * Set the clip path to use.
102: * The path will be filled with opaque white.
103: * @param clipPath The clip path to use
104: */
105: public void setClipPath(Shape clipPath) {
106: touch();
107: this .clipPath = clipPath;
108: }
109:
110: /**
111: * Returns the Shape that the cliprable will use to
112: * define the clip path.
113: * @return The shape that defines the clip path.
114: */
115: public Shape getClipPath() {
116: return clipPath;
117: }
118:
119: /**
120: * Pass-through: returns the source's bounds
121: */
122: public Rectangle2D getBounds2D() {
123: return getSource().getBounds2D();
124: }
125:
126: public RenderedImage createRendering(RenderContext rc) {
127:
128: AffineTransform usr2dev = rc.getTransform();
129:
130: // Just copy over the rendering hints.
131: RenderingHints rh = rc.getRenderingHints();
132: if (rh == null)
133: rh = new RenderingHints(null);
134:
135: Shape aoi = rc.getAreaOfInterest();
136: if (aoi == null)
137: aoi = getBounds2D();
138:
139: Rectangle2D rect = getBounds2D();
140: Rectangle2D clipRect = clipPath.getBounds2D();
141: Rectangle2D aoiRect = aoi.getBounds2D();
142:
143: if (!rect.intersects(clipRect))
144: return null;
145: Rectangle2D.intersect(rect, clipRect, rect);
146:
147: if (!rect.intersects(aoiRect))
148: return null;
149: Rectangle2D.intersect(rect, aoi.getBounds2D(), rect);
150:
151: Rectangle devR = usr2dev.createTransformedShape(rect)
152: .getBounds();
153:
154: if ((devR.width == 0) || (devR.height == 0))
155: return null;
156:
157: BufferedImage bi = new BufferedImage(devR.width, devR.height,
158: BufferedImage.TYPE_BYTE_GRAY);
159:
160: Shape devShape = usr2dev.createTransformedShape(getClipPath());
161: Rectangle devAOIR;
162: devAOIR = usr2dev.createTransformedShape(aoi).getBounds();
163:
164: Graphics2D g2d = GraphicsUtil.createGraphics(bi, rh);
165:
166: if (false) {
167: java.util.Set s = rh.keySet();
168: java.util.Iterator i = s.iterator();
169: while (i.hasNext()) {
170: Object o = i.next();
171: System.out.println("XXX: " + o + " -> " + rh.get(o));
172: }
173: }
174: g2d.translate(-devR.x, -devR.y);
175: g2d.setPaint(Color.white);
176: g2d.fill(devShape);
177: g2d.dispose();
178:
179: RenderedImage ri;
180: ri = getSource().createRendering(
181: new RenderContext(usr2dev, rect, rh));
182:
183: CachableRed cr, clipCr;
184: cr = RenderedImageCachableRed.wrap(ri);
185: clipCr = new BufferedImageCachableRed(bi, devR.x, devR.y);
186: CachableRed ret = new MultiplyAlphaRed(cr, clipCr);
187:
188: // Pad back out to the proper size...
189: ret = new PadRed(ret, devAOIR, PadMode.ZERO_PAD, rh);
190:
191: return ret;
192: }
193: }
|