KickJava   Java API By Example, From Geeks To Geeks.

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


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.Rectangle 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.NoninvertibleTransformException JavaDoc;
25 import java.awt.geom.Rectangle2D JavaDoc;
26 import java.awt.image.RenderedImage JavaDoc;
27 import java.awt.image.renderable.RenderContext JavaDoc;
28
29 import org.apache.batik.ext.awt.image.PadMode;
30 import org.apache.batik.ext.awt.image.rendered.AffineRed;
31 import org.apache.batik.ext.awt.image.rendered.CachableRed;
32 import org.apache.batik.ext.awt.image.rendered.GaussianBlurRed8Bit;
33 import org.apache.batik.ext.awt.image.rendered.PadRed;
34
35 /**
36  * GaussianBlurRable implementation
37  *
38  * @author <a HREF="mailto:vincent.hardy@eng.sun.com">Vincent Hardy</a>
39  * @version $Id: GaussianBlurRable8Bit.java,v 1.10 2005/03/27 08:58:33 cam Exp $
40  */

41 public class GaussianBlurRable8Bit
42     extends AbstractColorInterpolationRable
43     implements GaussianBlurRable {
44
45     /**
46      * Deviation along the x-axis
47      */

48     private double stdDeviationX;
49
50     /**
51      * Deviation along the y-axis
52      */

53     private double stdDeviationY;
54
55     public GaussianBlurRable8Bit(Filter src,
56                                  double stdevX, double stdevY) {
57         super(src, null);
58         setStdDeviationX(stdevX);
59         setStdDeviationY(stdevY);
60     }
61
62     /**
63      * The deviation along the x axis, in user space.
64      * @param stdDeviationX should be greater than zero.
65      */

66     public void setStdDeviationX(double stdDeviationX){
67         if(stdDeviationX < 0){
68             throw new IllegalArgumentException JavaDoc();
69         }
70
71         touch();
72         this.stdDeviationX = stdDeviationX;
73     }
74
75     /**
76      * The deviation along the y axis, in user space.
77      * @param stdDeviationY should be greater than zero
78      */

79     public void setStdDeviationY(double stdDeviationY){
80         if(stdDeviationY < 0){
81             throw new IllegalArgumentException JavaDoc();
82         }
83         touch();
84         this.stdDeviationY = stdDeviationY;
85     }
86
87     /**
88      * Returns the deviation along the x-axis, in user space.
89      */

90     public double getStdDeviationX(){
91         return stdDeviationX;
92     }
93
94     /**
95      * Returns the deviation along the y-axis, in user space.
96      */

97     public double getStdDeviationY(){
98         return stdDeviationY;
99     }
100
101     /**
102      * Sets the source of the blur operation
103      */

104     public void setSource(Filter src){
105         init(src, null);
106     }
107
108     /**
109      * Constant: 3*sqrt(2*PI)/4
110      */

111     static final float DSQRT2PI = (float)(Math.sqrt(2*Math.PI)*3.0/4.0);
112
113     /**
114      * Grow the source's bounds
115      */

116     public Rectangle2D JavaDoc getBounds2D(){
117         Rectangle2D JavaDoc src = getSource().getBounds2D();
118         float dX = (float)(stdDeviationX*DSQRT2PI);
119         float dY = (float)(stdDeviationY*DSQRT2PI);
120         float radX = 3*dX/2;
121         float radY = 3*dY/2;
122         return new Rectangle2D.Float JavaDoc
123             ((float)(src.getMinX() -radX),
124              (float)(src.getMinY() -radY),
125              (float)(src.getWidth() +2*radX),
126              (float)(src.getHeight()+2*radY));
127     }
128
129     /**
130      * Returns the source of the blur operation
131      */

132     public Filter getSource(){
133         return (Filter)getSources().get(0);
134     }
135
136     public final static double eps = 0.0001;
137     public static boolean eps_eq(double f1, double f2) {
138         return ((f1 >= f2-eps) && (f1 <= f2+eps));
139     }
140     public static boolean eps_abs_eq(double f1, double f2) {
141         if (f1 <0) f1 = -f1;
142         if (f2 <0) f2 = -f2;
143         return eps_eq(f1, f2);
144     }
145
146     public RenderedImage JavaDoc createRendering(RenderContext JavaDoc rc) {
147         // Just copy over the rendering hints.
148
RenderingHints JavaDoc rh = rc.getRenderingHints();
149         if (rh == null) rh = new RenderingHints JavaDoc(null);
150
151         // update the current affine transform
152
AffineTransform JavaDoc at = rc.getTransform();
153
154
155         // This splits out the scale and applies it
156
// prior to the Gaussian. Then after appying the gaussian
157
// it applies the shear (rotation) and translation components.
158
double sx = at.getScaleX();
159         double sy = at.getScaleY();
160
161         double shx = at.getShearX();
162         double shy = at.getShearY();
163
164         double tx = at.getTranslateX();
165         double ty = at.getTranslateY();
166
167         // The Scale is the "hypotonose" of the matrix vectors.
168
double scaleX = Math.sqrt(sx*sx + shy*shy);
169         double scaleY = Math.sqrt(sy*sy + shx*shx);
170
171         double sdx = stdDeviationX*scaleX;
172         double sdy = stdDeviationY*scaleY;
173
174         // This is the affine transform between our usr space and an
175
// intermediate space which is scaled similarly to our device
176
// space but is still axially aligned with our device space.
177
AffineTransform JavaDoc srcAt;
178
179         // This is the affine transform between our intermediate
180
// coordinate space and the real device space, or null (if
181
// we don't need an intermediate space).
182
AffineTransform JavaDoc resAt;
183
184         int outsetX, outsetY;
185         if ((sdx < 10) &&
186             (sdy < 10) &&
187             eps_eq (sdx, sdy) &&
188             eps_abs_eq(sx/scaleX, sy/scaleY)) {
189             // Ok we have a square Gaussian kernel which means it is
190
// circularly symetric, further our residual matrix (after
191
// removing scaling) is a rotation matrix (perhaps with
192
// mirroring), thus we can generate our source directly in
193
// device space and convolve there rather than going to an
194
// intermediate space (axially aligned with usr space) and
195
// then completing the requested rotation/shear, with an
196
// AffineRed...
197

198             srcAt = at;
199             resAt = null;
200             outsetX = 0;
201             outsetY = 0;
202         } else {
203
204             // Limit std dev to 10. Put any extra into our
205
// residual matrix. This will effectively linearly
206
// interpolate, but with such a large StdDev the
207
// function is fairly smooth anyway...
208
if (sdx > 10) {
209                 scaleX = scaleX*10/sdx;
210                 sdx = 10;
211             }
212             if (sdy > 10) {
213                 scaleY = scaleY*10/sdy;
214                 sdy = 10;
215             }
216
217             // Scale to device coords.
218
srcAt = AffineTransform.getScaleInstance(scaleX, scaleY);
219
220             // The shear/rotation simply divides out the
221
// common scale factor in the matrix.
222
resAt = new AffineTransform JavaDoc(sx/scaleX, shy/scaleX,
223                                         shx/scaleY, sy/scaleY,
224                                         tx, ty);
225             // Add a pixel all around for the affine to interpolate with.
226
outsetX = 1;
227             outsetY = 1;
228         }
229
230
231         Shape JavaDoc aoi = rc.getAreaOfInterest();
232         if(aoi == null)
233             aoi = getBounds2D();
234
235         Shape JavaDoc devShape = srcAt.createTransformedShape(aoi);
236         Rectangle JavaDoc devRect = devShape.getBounds();
237
238         outsetX += GaussianBlurRed8Bit.surroundPixels(sdx, rh);
239         outsetY += GaussianBlurRed8Bit.surroundPixels(sdy, rh);
240
241         devRect.x -= outsetX;
242         devRect.y -= outsetY;
243         devRect.width += 2*outsetX;
244         devRect.height += 2*outsetY;
245
246         Rectangle2D JavaDoc r;
247         try {
248             AffineTransform JavaDoc invSrcAt = srcAt.createInverse();
249             r = invSrcAt.createTransformedShape(devRect).getBounds2D();
250         } catch (NoninvertibleTransformException JavaDoc nte) {
251             // Grow the region in usr space.
252
r = aoi.getBounds2D();
253             r = new Rectangle2D.Double JavaDoc(r.getX()-outsetX/scaleX,
254                                        r.getY()-outsetY/scaleY,
255                                        r.getWidth() +2*outsetX/scaleX,
256                                        r.getHeight()+2*outsetY/scaleY);
257         }
258
259         RenderedImage JavaDoc ri;
260         ri = getSource().createRendering(new RenderContext JavaDoc(srcAt, r, rh));
261         if (ri == null)
262             return null;
263
264         CachableRed cr = convertSourceCS(ri);
265
266         // System.out.println("DevRect: " + devRect);
267

268         if (!devRect.equals(cr.getBounds())) {
269             // System.out.println("MisMatch Dev:" + devRect);
270
// System.out.println(" CR :" + cr.getBounds());
271
cr = new PadRed(cr, devRect, PadMode.ZERO_PAD, rh);
272         }
273
274         cr = new GaussianBlurRed8Bit(cr, sdx, sdy, rh);
275
276         if ((resAt != null) && (!resAt.isIdentity()))
277             cr = new AffineRed(cr, resAt, rh);
278
279         return cr;
280     }
281
282     /**
283      * Returns the region of input data is is required to generate
284      * outputRgn.
285      * @param srcIndex The source to do the dependency calculation for.
286      * @param outputRgn The region of output you are interested in
287      * generating dependencies for. The is given in the user coordiate
288      * system for this node.
289      * @return The region of input required. This is in the user
290      * coordinate system for the source indicated by srcIndex.
291      */

292     public Shape JavaDoc getDependencyRegion(int srcIndex, Rectangle2D JavaDoc outputRgn){
293         if(srcIndex != 0)
294             outputRgn = null;
295         else {
296             // There is only one source in GaussianBlur
297
float dX = (float)(stdDeviationX*DSQRT2PI);
298             float dY = (float)(stdDeviationY*DSQRT2PI);
299             float radX = 3*dX/2;
300             float radY = 3*dY/2;
301             outputRgn = new Rectangle2D.Float JavaDoc
302                             ((float)(outputRgn.getMinX() -radX),
303                              (float)(outputRgn.getMinY() -radY),
304                              (float)(outputRgn.getWidth() +2*radX),
305                              (float)(outputRgn.getHeight()+2*radY));
306
307             Rectangle2D JavaDoc bounds = getBounds2D();
308             if (outputRgn.intersects(bounds) == false)
309                 return new Rectangle2D.Float JavaDoc();
310             // Intersect with output region
311
outputRgn = outputRgn.createIntersection(bounds);
312         }
313
314         return outputRgn;
315     }
316
317     /**
318      * This calculates the region of output that is affected by a change
319      * in a region of input.
320      * @param srcIndex The input that inputRgn reflects changes in.
321      * @param inputRgn the region of input that has changed, used to
322      * calculate the returned shape. This is given in the user
323      * coordinate system of the source indicated by srcIndex.
324      * @return The region of output that would be invalid given
325      * a change to inputRgn of the source selected by srcIndex.
326      * this is in the user coordinate system of this node.
327      */

328     public Shape JavaDoc getDirtyRegion(int srcIndex, Rectangle2D JavaDoc inputRgn){
329         Rectangle2D JavaDoc dirtyRegion = null;
330         if(srcIndex == 0){
331             float dX = (float)(stdDeviationX*DSQRT2PI);
332             float dY = (float)(stdDeviationY*DSQRT2PI);
333             float radX = 3*dX/2;
334             float radY = 3*dY/2;
335             inputRgn = new Rectangle2D.Float JavaDoc
336                             ((float)(inputRgn.getMinX() -radX),
337                              (float)(inputRgn.getMinY() -radY),
338                              (float)(inputRgn.getWidth() +2*radX),
339                              (float)(inputRgn.getHeight()+2*radY));
340
341             Rectangle2D JavaDoc bounds = getBounds2D();
342             if (inputRgn.intersects(bounds) == false)
343                 return new Rectangle2D.Float JavaDoc();
344             // Intersect with input region
345
dirtyRegion = inputRgn.createIntersection(bounds);
346         }
347
348         return dirtyRegion;
349     }
350
351
352 }
353
Popular Tags