Home » openjdk-7 » java » awt » image » [javadoc | source]

    1   /*
    2    * Copyright (c) 1997, 2000, Oracle and/or its affiliates. All rights reserved.
    3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
    4    *
    5    * This code is free software; you can redistribute it and/or modify it
    6    * under the terms of the GNU General Public License version 2 only, as
    7    * published by the Free Software Foundation.  Oracle designates this
    8    * particular file as subject to the "Classpath" exception as provided
    9    * by Oracle in the LICENSE file that accompanied this code.
   10    *
   11    * This code is distributed in the hope that it will be useful, but WITHOUT
   12    * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
   13    * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
   14    * version 2 for more details (a copy is included in the LICENSE file that
   15    * accompanied this code).
   16    *
   17    * You should have received a copy of the GNU General Public License version
   18    * 2 along with this work; if not, write to the Free Software Foundation,
   19    * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
   20    *
   21    * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
   22    * or visit www.oracle.com if you need additional information or have any
   23    * questions.
   24    */
   25   
   26   package java.awt.image;
   27   
   28   import java.awt.color.ICC_Profile;
   29   import java.awt.geom.Rectangle2D;
   30   import java.awt.Rectangle;
   31   import java.awt.RenderingHints;
   32   import java.awt.geom.Point2D;
   33   import sun.awt.image.ImagingLib;
   34   
   35   /**
   36    * This class implements a convolution from the source
   37    * to the destination.
   38    * Convolution using a convolution kernel is a spatial operation that
   39    * computes the output pixel from an input pixel by multiplying the kernel
   40    * with the surround of the input pixel.
   41    * This allows the output pixel to be affected by the immediate neighborhood
   42    * in a way that can be mathematically specified with a kernel.
   43    *<p>
   44    * This class operates with BufferedImage data in which color components are
   45    * premultiplied with the alpha component.  If the Source BufferedImage has
   46    * an alpha component, and the color components are not premultiplied with
   47    * the alpha component, then the data are premultiplied before being
   48    * convolved.  If the Destination has color components which are not
   49    * premultiplied, then alpha is divided out before storing into the
   50    * Destination (if alpha is 0, the color components are set to 0).  If the
   51    * Destination has no alpha component, then the resulting alpha is discarded
   52    * after first dividing it out of the color components.
   53    * <p>
   54    * Rasters are treated as having no alpha channel.  If the above treatment
   55    * of the alpha channel in BufferedImages is not desired, it may be avoided
   56    * by getting the Raster of a source BufferedImage and using the filter method
   57    * of this class which works with Rasters.
   58    * <p>
   59    * If a RenderingHints object is specified in the constructor, the
   60    * color rendering hint and the dithering hint may be used when color
   61    * conversion is required.
   62    *<p>
   63    * Note that the Source and the Destination may not be the same object.
   64    * @see Kernel
   65    * @see java.awt.RenderingHints#KEY_COLOR_RENDERING
   66    * @see java.awt.RenderingHints#KEY_DITHERING
   67    */
   68   public class ConvolveOp implements BufferedImageOp, RasterOp {
   69       Kernel kernel;
   70       int edgeHint;
   71       RenderingHints hints;
   72       /**
   73        * Edge condition constants.
   74        */
   75   
   76       /**
   77        * Pixels at the edge of the destination image are set to zero.  This
   78        * is the default.
   79        */
   80   
   81       public static final int EDGE_ZERO_FILL = 0;
   82   
   83       /**
   84        * Pixels at the edge of the source image are copied to
   85        * the corresponding pixels in the destination without modification.
   86        */
   87       public static final int EDGE_NO_OP     = 1;
   88   
   89       /**
   90        * Constructs a ConvolveOp given a Kernel, an edge condition, and a
   91        * RenderingHints object (which may be null).
   92        * @param kernel the specified <code>Kernel</code>
   93        * @param edgeCondition the specified edge condition
   94        * @param hints the specified <code>RenderingHints</code> object
   95        * @see Kernel
   96        * @see #EDGE_NO_OP
   97        * @see #EDGE_ZERO_FILL
   98        * @see java.awt.RenderingHints
   99        */
  100       public ConvolveOp(Kernel kernel, int edgeCondition, RenderingHints hints) {
  101           this.kernel   = kernel;
  102           this.edgeHint = edgeCondition;
  103           this.hints    = hints;
  104       }
  105   
  106       /**
  107        * Constructs a ConvolveOp given a Kernel.  The edge condition
  108        * will be EDGE_ZERO_FILL.
  109        * @param kernel the specified <code>Kernel</code>
  110        * @see Kernel
  111        * @see #EDGE_ZERO_FILL
  112        */
  113       public ConvolveOp(Kernel kernel) {
  114           this.kernel   = kernel;
  115           this.edgeHint = EDGE_ZERO_FILL;
  116       }
  117   
  118       /**
  119        * Returns the edge condition.
  120        * @return the edge condition of this <code>ConvolveOp</code>.
  121        * @see #EDGE_NO_OP
  122        * @see #EDGE_ZERO_FILL
  123        */
  124       public int getEdgeCondition() {
  125           return edgeHint;
  126       }
  127   
  128       /**
  129        * Returns the Kernel.
  130        * @return the <code>Kernel</code> of this <code>ConvolveOp</code>.
  131        */
  132       public final Kernel getKernel() {
  133           return (Kernel) kernel.clone();
  134       }
  135   
  136       /**
  137        * Performs a convolution on BufferedImages.  Each component of the
  138        * source image will be convolved (including the alpha component, if
  139        * present).
  140        * If the color model in the source image is not the same as that
  141        * in the destination image, the pixels will be converted
  142        * in the destination.  If the destination image is null,
  143        * a BufferedImage will be created with the source ColorModel.
  144        * The IllegalArgumentException may be thrown if the source is the
  145        * same as the destination.
  146        * @param src the source <code>BufferedImage</code> to filter
  147        * @param dst the destination <code>BufferedImage</code> for the
  148        *        filtered <code>src</code>
  149        * @return the filtered <code>BufferedImage</code>
  150        * @throws NullPointerException if <code>src</code> is <code>null</code>
  151        * @throws IllegalArgumentException if <code>src</code> equals
  152        *         <code>dst</code>
  153        * @throws ImagingOpException if <code>src</code> cannot be filtered
  154        */
  155       public final BufferedImage filter (BufferedImage src, BufferedImage dst) {
  156           if (src == null) {
  157               throw new NullPointerException("src image is null");
  158           }
  159           if (src == dst) {
  160               throw new IllegalArgumentException("src image cannot be the "+
  161                                                  "same as the dst image");
  162           }
  163   
  164           boolean needToConvert = false;
  165           ColorModel srcCM = src.getColorModel();
  166           ColorModel dstCM;
  167           BufferedImage origDst = dst;
  168   
  169           // Can't convolve an IndexColorModel.  Need to expand it
  170           if (srcCM instanceof IndexColorModel) {
  171               IndexColorModel icm = (IndexColorModel) srcCM;
  172               src = icm.convertToIntDiscrete(src.getRaster(), false);
  173               srcCM = src.getColorModel();
  174           }
  175   
  176           if (dst == null) {
  177               dst = createCompatibleDestImage(src, null);
  178               dstCM = srcCM;
  179               origDst = dst;
  180           }
  181           else {
  182               dstCM = dst.getColorModel();
  183               if (srcCM.getColorSpace().getType() !=
  184                   dstCM.getColorSpace().getType())
  185               {
  186                   needToConvert = true;
  187                   dst = createCompatibleDestImage(src, null);
  188                   dstCM = dst.getColorModel();
  189               }
  190               else if (dstCM instanceof IndexColorModel) {
  191                   dst = createCompatibleDestImage(src, null);
  192                   dstCM = dst.getColorModel();
  193               }
  194           }
  195   
  196           if (ImagingLib.filter(this, src, dst) == null) {
  197               throw new ImagingOpException ("Unable to convolve src image");
  198           }
  199   
  200           if (needToConvert) {
  201               ColorConvertOp ccop = new ColorConvertOp(hints);
  202               ccop.filter(dst, origDst);
  203           }
  204           else if (origDst != dst) {
  205               java.awt.Graphics2D g = origDst.createGraphics();
  206               try {
  207                   g.drawImage(dst, 0, 0, null);
  208               } finally {
  209                   g.dispose();
  210               }
  211           }
  212   
  213           return origDst;
  214       }
  215   
  216       /**
  217        * Performs a convolution on Rasters.  Each band of the source Raster
  218        * will be convolved.
  219        * The source and destination must have the same number of bands.
  220        * If the destination Raster is null, a new Raster will be created.
  221        * The IllegalArgumentException may be thrown if the source is
  222        * the same as the destination.
  223        * @param src the source <code>Raster</code> to filter
  224        * @param dst the destination <code>WritableRaster</code> for the
  225        *        filtered <code>src</code>
  226        * @return the filtered <code>WritableRaster</code>
  227        * @throws NullPointerException if <code>src</code> is <code>null</code>
  228        * @throws ImagingOpException if <code>src</code> and <code>dst</code>
  229        *         do not have the same number of bands
  230        * @throws ImagingOpException if <code>src</code> cannot be filtered
  231        * @throws IllegalArgumentException if <code>src</code> equals
  232        *         <code>dst</code>
  233        */
  234       public final WritableRaster filter (Raster src, WritableRaster dst) {
  235           if (dst == null) {
  236               dst = createCompatibleDestRaster(src);
  237           }
  238           else if (src == dst) {
  239               throw new IllegalArgumentException("src image cannot be the "+
  240                                                  "same as the dst image");
  241           }
  242           else if (src.getNumBands() != dst.getNumBands()) {
  243               throw new ImagingOpException("Different number of bands in src "+
  244                                            " and dst Rasters");
  245           }
  246   
  247           if (ImagingLib.filter(this, src, dst) == null) {
  248               throw new ImagingOpException ("Unable to convolve src image");
  249           }
  250   
  251           return dst;
  252       }
  253   
  254       /**
  255        * Creates a zeroed destination image with the correct size and number
  256        * of bands.  If destCM is null, an appropriate ColorModel will be used.
  257        * @param src       Source image for the filter operation.
  258        * @param destCM    ColorModel of the destination.  Can be null.
  259        * @return a destination <code>BufferedImage</code> with the correct
  260        *         size and number of bands.
  261        */
  262       public BufferedImage createCompatibleDestImage(BufferedImage src,
  263                                                      ColorModel destCM) {
  264           BufferedImage image;
  265   
  266           int w = src.getWidth();
  267           int h = src.getHeight();
  268   
  269           WritableRaster wr = null;
  270   
  271           if (destCM == null) {
  272               destCM = src.getColorModel();
  273               // Not much support for ICM
  274               if (destCM instanceof IndexColorModel) {
  275                   destCM = ColorModel.getRGBdefault();
  276               } else {
  277                   /* Create destination image as similar to the source
  278                    *  as it possible...
  279                    */
  280                   wr = src.getData().createCompatibleWritableRaster(w, h);
  281               }
  282           }
  283   
  284           if (wr == null) {
  285               /* This is the case when destination color model
  286                * was explicitly specified (and it may be not compatible
  287                * with source raster structure) or source is indexed image.
  288                * We should use destination color model to create compatible
  289                * destination raster here.
  290                */
  291               wr = destCM.createCompatibleWritableRaster(w, h);
  292           }
  293   
  294           image = new BufferedImage (destCM, wr,
  295                                      destCM.isAlphaPremultiplied(), null);
  296   
  297           return image;
  298       }
  299   
  300       /**
  301        * Creates a zeroed destination Raster with the correct size and number
  302        * of bands, given this source.
  303        */
  304       public WritableRaster createCompatibleDestRaster(Raster src) {
  305           return src.createCompatibleWritableRaster();
  306       }
  307   
  308       /**
  309        * Returns the bounding box of the filtered destination image.  Since
  310        * this is not a geometric operation, the bounding box does not
  311        * change.
  312        */
  313       public final Rectangle2D getBounds2D(BufferedImage src) {
  314           return getBounds2D(src.getRaster());
  315       }
  316   
  317       /**
  318        * Returns the bounding box of the filtered destination Raster.  Since
  319        * this is not a geometric operation, the bounding box does not
  320        * change.
  321        */
  322       public final Rectangle2D getBounds2D(Raster src) {
  323           return src.getBounds();
  324       }
  325   
  326       /**
  327        * Returns the location of the destination point given a
  328        * point in the source.  If dstPt is non-null, it will
  329        * be used to hold the return value.  Since this is not a geometric
  330        * operation, the srcPt will equal the dstPt.
  331        */
  332       public final Point2D getPoint2D(Point2D srcPt, Point2D dstPt) {
  333           if (dstPt == null) {
  334               dstPt = new Point2D.Float();
  335           }
  336           dstPt.setLocation(srcPt.getX(), srcPt.getY());
  337   
  338           return dstPt;
  339       }
  340   
  341       /**
  342        * Returns the rendering hints for this op.
  343        */
  344       public final RenderingHints getRenderingHints() {
  345           return hints;
  346       }
  347   }

Home » openjdk-7 » java » awt » image » [javadoc | source]