KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > java > awt > image > ConvolveOp


1 /*
2  * @(#)ConvolveOp.java 1.46 03/12/19
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 package java.awt.image;
9
10 import java.awt.color.ICC_Profile JavaDoc;
11 import java.awt.geom.Rectangle2D JavaDoc;
12 import java.awt.Rectangle JavaDoc;
13 import java.awt.RenderingHints JavaDoc;
14 import java.awt.geom.Point2D JavaDoc;
15 import sun.awt.image.ImagingLib;
16
17 /**
18  * This class implements a convolution from the source
19  * to the destination.
20  * Convolution using a convolution kernel is a spatial operation that
21  * computes the output pixel from an input pixel by multiplying the kernel
22  * with the surround of the input pixel.
23  * This allows the output pixel to be affected by the immediate neighborhood
24  * in a way that can be mathematically specified with a kernel.
25  *<p>
26  * This class operates with BufferedImage data in which color components are
27  * premultiplied with the alpha component. If the Source BufferedImage has
28  * an alpha component, and the color components are not premultiplied with
29  * the alpha component, then the data are premultiplied before being
30  * convolved. If the Destination has color components which are not
31  * premultiplied, then alpha is divided out before storing into the
32  * Destination (if alpha is 0, the color components are set to 0). If the
33  * Destination has no alpha component, then the resulting alpha is discarded
34  * after first dividing it out of the color components.
35  * <p>
36  * Rasters are treated as having no alpha channel. If the above treatment
37  * of the alpha channel in BufferedImages is not desired, it may be avoided
38  * by getting the Raster of a source BufferedImage and using the filter method
39  * of this class which works with Rasters.
40  * <p>
41  * If a RenderingHints object is specified in the constructor, the
42  * color rendering hint and the dithering hint may be used when color
43  * conversion is required.
44  *<p>
45  * Note that the Source and the Destination may not be the same object.
46  * @version 10 Feb 1997
47  * @see Kernel
48  * @see java.awt.RenderingHints#KEY_COLOR_RENDERING
49  * @see java.awt.RenderingHints#KEY_DITHERING
50  */

51 public class ConvolveOp implements BufferedImageOp JavaDoc, RasterOp JavaDoc {
52     Kernel JavaDoc kernel;
53     int edgeHint;
54     RenderingHints JavaDoc hints;
55     /**
56      * Edge condition constants.
57      */

58
59     /**
60      * Pixels at the edge of the destination image are set to zero. This
61      * is the default.
62      */

63
64     public static final int EDGE_ZERO_FILL = 0;
65
66     /**
67      * Pixels at the edge of the source image are copied to
68      * the corresponding pixels in the destination without modification.
69      */

70     public static final int EDGE_NO_OP = 1;
71
72     /**
73      * Constructs a ConvolveOp given a Kernel, an edge condition, and a
74      * RenderingHints object (which may be null).
75      * @param kernel the specified <code>Kernel</code>
76      * @param edgeCondition the specified edge condition
77      * @param hints the specified <code>RenderingHints</code> object
78      * @see Kernel
79      * @see #EDGE_NO_OP
80      * @see #EDGE_ZERO_FILL
81      * @see java.awt.RenderingHints
82      */

83     public ConvolveOp(Kernel JavaDoc kernel, int edgeCondition, RenderingHints JavaDoc hints) {
84         this.kernel = kernel;
85         this.edgeHint = edgeCondition;
86         this.hints = hints;
87     }
88
89     /**
90      * Constructs a ConvolveOp given a Kernel. The edge condition
91      * will be EDGE_ZERO_FILL.
92      * @param kernel the specified <code>Kernel</code>
93      * @see Kernel
94      * @see #EDGE_ZERO_FILL
95      */

96     public ConvolveOp(Kernel JavaDoc kernel) {
97         this.kernel = kernel;
98         this.edgeHint = EDGE_ZERO_FILL;
99     }
100
101     /**
102      * Returns the edge condition.
103      * @return the edge condition of this <code>ConvolveOp</code>.
104      * @see #EDGE_NO_OP
105      * @see #EDGE_ZERO_FILL
106      */

107     public int getEdgeCondition() {
108         return edgeHint;
109     }
110
111     /**
112      * Returns the Kernel.
113      * @return the <code>Kernel</code> of this <code>ConvolveOp</code>.
114      */

115     public final Kernel JavaDoc getKernel() {
116         return (Kernel JavaDoc) kernel.clone();
117     }
118
119     /**
120      * Performs a convolution on BufferedImages. Each component of the
121      * source image will be convolved (including the alpha component, if
122      * present).
123      * If the color model in the source image is not the same as that
124      * in the destination image, the pixels will be converted
125      * in the destination. If the destination image is null,
126      * a BufferedImage will be created with the source ColorModel.
127      * The IllegalArgumentException may be thrown if the source is the
128      * same as the destination.
129      * @param src the source <code>BufferedImage</code> to filter
130      * @param dst the destination <code>BufferedImage</code> for the
131      * filtered <code>src</code>
132      * @return the filtered <code>BufferedImage</code>
133      * @throws NullPointerException if <code>src</code> is <code>null</code>
134      * @throws IllegalArgumentException if <code>src</code> equals
135      * <code>dst</code>
136      * @throws ImagingOpException if <code>src</code> cannot be filtered
137      */

138     public final BufferedImage JavaDoc filter (BufferedImage JavaDoc src, BufferedImage JavaDoc dst) {
139         if (src == null) {
140             throw new NullPointerException JavaDoc("src image is null");
141         }
142         if (src == dst) {
143             throw new IllegalArgumentException JavaDoc("src image cannot be the "+
144                                                "same as the dst image");
145         }
146
147         boolean needToConvert = false;
148         ColorModel JavaDoc srcCM = src.getColorModel();
149         ColorModel JavaDoc dstCM;
150         BufferedImage JavaDoc origDst = dst;
151
152         // Can't convolve an IndexColorModel. Need to expand it
153
if (srcCM instanceof IndexColorModel JavaDoc) {
154             IndexColorModel JavaDoc icm = (IndexColorModel JavaDoc) srcCM;
155             src = icm.convertToIntDiscrete(src.getRaster(), false);
156             srcCM = src.getColorModel();
157         }
158         
159         if (dst == null) {
160             dst = createCompatibleDestImage(src, null);
161             dstCM = srcCM;
162             origDst = dst;
163         }
164         else {
165             dstCM = dst.getColorModel();
166             if (srcCM.getColorSpace().getType() !=
167                 dstCM.getColorSpace().getType())
168             {
169                 needToConvert = true;
170                 dst = createCompatibleDestImage(src, null);
171                 dstCM = dst.getColorModel();
172             }
173             else if (dstCM instanceof IndexColorModel JavaDoc) {
174                 dst = createCompatibleDestImage(src, null);
175                 dstCM = dst.getColorModel();
176             }
177         }
178
179         if (ImagingLib.filter(this, src, dst) == null) {
180             throw new ImagingOpException JavaDoc ("Unable to convolve src image");
181         }
182
183         if (needToConvert) {
184             ColorConvertOp JavaDoc ccop = new ColorConvertOp JavaDoc(hints);
185             ccop.filter(dst, origDst);
186         }
187         else if (origDst != dst) {
188             java.awt.Graphics2D JavaDoc g = origDst.createGraphics();
189         try {
190                 g.drawImage(dst, 0, 0, null);
191         } finally {
192             g.dispose();
193         }
194         }
195
196         return origDst;
197     }
198
199     /**
200      * Performs a convolution on Rasters. Each band of the source Raster
201      * will be convolved.
202      * The source and destination must have the same number of bands.
203      * If the destination Raster is null, a new Raster will be created.
204      * The IllegalArgumentException may be thrown if the source is
205      * the same as the destination.
206      * @param src the source <code>Raster</code> to filter
207      * @param dst the destination <code>WritableRaster</code> for the
208      * filtered <code>src</code>
209      * @return the filtered <code>WritableRaster</code>
210      * @throws NullPointerException if <code>src</code> is <code>null</code>
211      * @throws ImagingOpException if <code>src</code> and <code>dst</code>
212      * do not have the same number of bands
213      * @throws ImagingOpException if <code>src</code> cannot be filtered
214      * @throws IllegalArgumentException if <code>src</code> equals
215      * <code>dst</code>
216      */

217     public final WritableRaster JavaDoc filter (Raster JavaDoc src, WritableRaster JavaDoc dst) {
218         if (dst == null) {
219             dst = createCompatibleDestRaster(src);
220         }
221         else if (src == dst) {
222             throw new IllegalArgumentException JavaDoc("src image cannot be the "+
223                                                "same as the dst image");
224         }
225         else if (src.getNumBands() != dst.getNumBands()) {
226             throw new ImagingOpException JavaDoc("Different number of bands in src "+
227                                          " and dst Rasters");
228         }
229         
230         if (ImagingLib.filter(this, src, dst) == null) {
231             throw new ImagingOpException JavaDoc ("Unable to convolve src image");
232         }
233
234         return dst;
235     }
236
237     /**
238      * Creates a zeroed destination image with the correct size and number
239      * of bands. If destCM is null, an appropriate ColorModel will be used.
240      * @param src Source image for the filter operation.
241      * @param destCM ColorModel of the destination. Can be null.
242      * @return a destination <code>BufferedImage</code> with the correct
243      * size and number of bands.
244      */

245     public BufferedImage JavaDoc createCompatibleDestImage(BufferedImage JavaDoc src,
246                                                    ColorModel JavaDoc destCM) {
247         BufferedImage JavaDoc image;
248         if (destCM == null) {
249             destCM = src.getColorModel();
250             // Not much support for ICM
251
if (destCM instanceof IndexColorModel JavaDoc) {
252                 destCM = ColorModel.getRGBdefault();
253             }
254         }
255
256         int w = src.getWidth();
257         int h = src.getHeight();
258         image = new BufferedImage JavaDoc (destCM,
259                                    destCM.createCompatibleWritableRaster(w, h),
260                                    destCM.isAlphaPremultiplied(), null);
261
262         return image;
263     }
264
265     /**
266      * Creates a zeroed destination Raster with the correct size and number
267      * of bands, given this source.
268      */

269     public WritableRaster JavaDoc createCompatibleDestRaster(Raster JavaDoc src) {
270         return src.createCompatibleWritableRaster();
271     }
272
273     /**
274      * Returns the bounding box of the filtered destination image. Since
275      * this is not a geometric operation, the bounding box does not
276      * change.
277      */

278     public final Rectangle2D JavaDoc getBounds2D(BufferedImage JavaDoc src) {
279     return getBounds2D(src.getRaster());
280     }
281
282     /**
283      * Returns the bounding box of the filtered destination Raster. Since
284      * this is not a geometric operation, the bounding box does not
285      * change.
286      */

287     public final Rectangle2D JavaDoc getBounds2D(Raster JavaDoc src) {
288     return src.getBounds();
289     }
290
291     /**
292      * Returns the location of the destination point given a
293      * point in the source. If dstPt is non-null, it will
294      * be used to hold the return value. Since this is not a geometric
295      * operation, the srcPt will equal the dstPt.
296      */

297     public final Point2D JavaDoc getPoint2D(Point2D JavaDoc srcPt, Point2D JavaDoc dstPt) {
298         if (dstPt == null) {
299             dstPt = new Point2D.Float JavaDoc();
300         }
301     dstPt.setLocation(srcPt.getX(), srcPt.getY());
302
303         return dstPt;
304     }
305
306     /**
307      * Returns the rendering hints for this op.
308      */

309     public final RenderingHints JavaDoc getRenderingHints() {
310         return hints;
311     }
312 }
313
314
315
Popular Tags