KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > batik > ext > awt > image > renderable > MorphologyRable8Bit


1 /*
2
3    Copyright 2001,2003 The Apache Software Foundation
4
5    Licensed under the Apache License, Version 2.0 (the "License");
6    you may not use this file except in compliance with the License.
7    You may obtain a copy of the License at
8
9        http://www.apache.org/licenses/LICENSE-2.0
10
11    Unless required by applicable law or agreed to in writing, software
12    distributed under the License is distributed on an "AS IS" BASIS,
13    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14    See the License for the specific language governing permissions and
15    limitations under the License.
16
17  */

18 package org.apache.batik.ext.awt.image.renderable;
19
20 import java.awt.Point JavaDoc;
21 import java.awt.RenderingHints JavaDoc;
22 import java.awt.Shape JavaDoc;
23 import java.awt.geom.AffineTransform JavaDoc;
24 import java.awt.geom.Rectangle2D JavaDoc;
25 import java.awt.image.BufferedImage JavaDoc;
26 import java.awt.image.ColorModel JavaDoc;
27 import java.awt.image.Raster JavaDoc;
28 import java.awt.image.RenderedImage JavaDoc;
29 import java.awt.image.WritableRaster JavaDoc;
30 import java.awt.image.renderable.RenderContext JavaDoc;
31
32 import org.apache.batik.ext.awt.image.PadMode;
33 import org.apache.batik.ext.awt.image.rendered.AffineRed;
34 import org.apache.batik.ext.awt.image.rendered.BufferedImageCachableRed;
35 import org.apache.batik.ext.awt.image.rendered.CachableRed;
36 import org.apache.batik.ext.awt.image.rendered.MorphologyOp;
37 import org.apache.batik.ext.awt.image.rendered.PadRed;
38 import org.apache.batik.ext.awt.image.rendered.RenderedImageCachableRed;
39
40 /**
41  * Implements a Morphology operation, where the kernel size is
42  * defined by radius along the x and y axis.
43  *
44  * @author <a HREF="mailto:vincent.hardy@eng.sun.com">Vincent Hardy</a>
45  * @version $Id: MorphologyRable8Bit.java,v 1.6 2004/08/18 07:13:59 vhardy Exp $
46  */

47 public class MorphologyRable8Bit
48     extends AbstractRable
49     implements MorphologyRable {
50     /**
51      * Morphology radius
52      */

53     private double radiusX, radiusY;
54
55     /**
56      * Controls whether this filter does dilation
57      * (as opposed to erosion)
58      */

59     private boolean doDilation;
60
61     public MorphologyRable8Bit(Filter src,
62                                    double radiusX,
63                                    double radiusY,
64                                    boolean doDilation){
65         super(src, null);
66         setRadiusX(radiusX);
67         setRadiusY(radiusY);
68         setDoDilation(doDilation);
69     }
70
71     /**
72      * Returns the source to be offset.
73      */

74     public Filter getSource(){
75         return (Filter)getSources().get(0);
76     }
77
78     /**
79      * Sets the source to be offset.
80      * @param src image to offset.
81      */

82     public void setSource(Filter src){
83         init(src, null);
84     }
85
86     /**
87      * Pass-through: returns the source's bounds
88      */

89     public Rectangle2D JavaDoc getBounds2D(){
90         return getSource().getBounds2D();
91     }
92
93     /**
94      * The radius along the x axis, in user space.
95      * @param radiusX should be greater than zero.
96      */

97     public void setRadiusX(double radiusX){
98         if(radiusX <= 0){
99             throw new IllegalArgumentException JavaDoc();
100         }
101
102         touch();
103         this.radiusX = radiusX;
104     }
105
106     /**
107      * The radius along the y axis, in user space.
108      * @param radiusY should be greater than zero.
109      */

110     public void setRadiusY(double radiusY){
111         if(radiusY <= 0){
112             throw new IllegalArgumentException JavaDoc();
113         }
114
115         touch();
116         this.radiusY = radiusY;
117     }
118
119     /**
120      * The switch that determines if the operation
121      * is to "dilate" or "erode".
122      * @param doDilation do "dilation" when true and "erosion" when false
123      */

124     public void setDoDilation(boolean doDilation){
125         touch();
126         this.doDilation = doDilation;
127     }
128
129     /**
130      * Returns whether the operation is "dilation" or not("erosion")
131      */

132     public boolean getDoDilation(){
133         return doDilation;
134     }
135
136     /**
137      * Returns the radius along the x-axis, in user space.
138      */

139     public double getRadiusX(){
140         return radiusX;
141     }
142
143     /**
144      * Returns the radius along the y-axis, in user space.
145      */

146     public double getRadiusY(){
147         return radiusY;
148     }
149
150     public RenderedImage JavaDoc createRendering(RenderContext JavaDoc rc) {
151         // Just copy over the rendering hints.
152
RenderingHints JavaDoc rh = rc.getRenderingHints();
153         if (rh == null) rh = new RenderingHints JavaDoc(null);
154
155         // update the current affine transform
156
AffineTransform JavaDoc at = rc.getTransform();
157
158         // This splits out the scale and applies it
159
// prior to the Gaussian. Then after appying the gaussian
160
// it applies the shear (rotation) and translation components.
161
double sx = at.getScaleX();
162         double sy = at.getScaleY();
163
164         double shx = at.getShearX();
165         double shy = at.getShearY();
166
167         double tx = at.getTranslateX();
168         double ty = at.getTranslateY();
169
170         // The Scale is the "hypotonose" of the matrix vectors.
171
double scaleX = Math.sqrt(sx*sx + shy*shy);
172         double scaleY = Math.sqrt(sy*sy + shx*shx);
173
174         AffineTransform JavaDoc srcAt;
175         srcAt = AffineTransform.getScaleInstance(scaleX, scaleY);
176
177         int radX = (int)Math.round(radiusX*scaleX);
178         int radY = (int)Math.round(radiusY*scaleY);
179
180         MorphologyOp op = null;
181         if(radX > 0 && radY > 0){
182             op = new MorphologyOp(radX, radY, doDilation);
183         }
184
185         // This is the affine transform between our intermediate
186
// coordinate space and the real device space.
187
AffineTransform JavaDoc resAt;
188         // The shear/rotation simply divides out the
189
// common scale factor in the matrix.
190
resAt = new AffineTransform JavaDoc(sx/scaleX, shy/scaleX,
191                                     shx/scaleY, sy/scaleY,
192                                     tx, ty);
193
194         Shape JavaDoc aoi = rc.getAreaOfInterest();
195         if(aoi == null) {
196             aoi = getBounds2D();
197         }
198  
199         Rectangle2D JavaDoc r = aoi.getBounds2D();
200         r = new Rectangle2D.Double JavaDoc(r.getX()-radX/scaleX,
201                                    r.getY()-radY/scaleY,
202                                    r.getWidth() +2*radX/scaleX,
203                                    r.getHeight()+2*radY/scaleY);
204
205         RenderedImage JavaDoc ri;
206         ri = getSource().createRendering(new RenderContext JavaDoc(srcAt, r, rh));
207         if (ri == null)
208             return null;
209
210         CachableRed cr;
211         cr = new RenderedImageCachableRed(ri);
212
213         Shape JavaDoc devShape = srcAt.createTransformedShape(aoi.getBounds2D());
214         r = devShape.getBounds2D();
215         r = new Rectangle2D.Double JavaDoc(r.getX()-radX,
216                                    r.getY()-radY,
217                                    r.getWidth() +2*radX,
218                                    r.getHeight()+2*radY);
219         cr = new PadRed(cr, r.getBounds(), PadMode.ZERO_PAD, rh);
220         
221         // System.out.println("Src: " + cr.getBounds(rc));
222

223         ColorModel JavaDoc cm = ri.getColorModel();
224
225         // OK this is a bit of a cheat. We Pull the DataBuffer out of
226
// The read-only raster that getData gives us. And use it to
227
// build a WritableRaster. This avoids a copy of the data.
228
Raster JavaDoc rr = cr.getData();
229         Point JavaDoc pt = new Point JavaDoc(0,0);
230         WritableRaster JavaDoc wr = Raster.createWritableRaster(rr.getSampleModel(),
231                                                         rr.getDataBuffer(),
232                                                         pt);
233         
234         BufferedImage JavaDoc srcBI;
235         srcBI = new BufferedImage JavaDoc(cm, wr, cm.isAlphaPremultiplied(), null);
236         
237         BufferedImage JavaDoc destBI;
238         if(op != null){
239             destBI = op.filter(srcBI, null);
240         }
241         else{
242             destBI = srcBI;
243         }
244
245         final int rrMinX = cr.getMinX();
246         final int rrMinY = cr.getMinY();
247
248         cr = new BufferedImageCachableRed(destBI, rrMinX, rrMinY);
249
250         if (!resAt.isIdentity())
251             cr = new AffineRed(cr, resAt, rh);
252         
253         // System.out.println("Res: " + cr.getBounds(rc));
254

255         return cr;
256     }
257
258     /**
259      * Returns the region of input data is is required to generate
260      * outputRgn.
261      * @param srcIndex The source to do the dependency calculation for.
262      * @param outputRgn The region of output you are interested in
263      * generating dependencies for. The is given in the user coordiate
264      * system for this node.
265      * @return The region of input required. This is in the user
266      * coordinate system for the source indicated by srcIndex.
267      */

268     public Shape JavaDoc getDependencyRegion(int srcIndex, Rectangle2D JavaDoc outputRgn){
269         // NOTE: This needs to grow the region!!!
270
// Morphology actually needs a larger area of input than
271
// it outputs.
272
return super.getDependencyRegion(srcIndex, outputRgn);
273     }
274
275     /**
276      * This calculates the region of output that is affected by a change
277      * in a region of input.
278      * @param srcIndex The input that inputRgn reflects changes in.
279      * @param inputRgn the region of input that has changed, used to
280      * calculate the returned shape. This is given in the user
281      * coordinate system of the source indicated by srcIndex.
282      * @return The region of output that would be invalid given
283      * a change to inputRgn of the source selected by srcIndex.
284      * this is in the user coordinate system of this node.
285      */

286     public Shape JavaDoc getDirtyRegion(int srcIndex, Rectangle2D JavaDoc inputRgn){
287         // NOTE: This needs to grow the region!!!
288
// Changes in the input region affect a larger area of
289
// output than the input.
290
return super.getDirtyRegion(srcIndex, inputRgn);
291     }
292
293 }
294
Popular Tags