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

    1   /*
    2    * Copyright (c) 1997, 2005, 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.GraphicsEnvironment;
   29   import java.awt.color.ICC_Profile;
   30   import java.awt.geom.Rectangle2D;
   31   import java.awt.Rectangle;
   32   import java.awt.geom.Point2D;
   33   import java.awt.RenderingHints;
   34   import sun.awt.image.ImagingLib;
   35   import java.util.Arrays;
   36   
   37   /**
   38    * This class performs an arbitrary linear combination of the bands
   39    * in a <CODE>Raster</CODE>, using a specified matrix.
   40    * <p>
   41    * The width of the matrix must be equal to the number of bands in the
   42    * source <CODE>Raster</CODE>, optionally plus one.  If there is one more
   43    * column in the matrix than the number of bands, there is an implied 1 at the
   44    * end of the vector of band samples representing a pixel.  The height
   45    * of the matrix must be equal to the number of bands in the destination.
   46    * <p>
   47    * For example, a 3-banded <CODE>Raster</CODE> might have the following
   48    * transformation applied to each pixel in order to invert the second band of
   49    * the <CODE>Raster</CODE>.
   50    * <pre>
   51    *   [ 1.0   0.0   0.0    0.0  ]     [ b1 ]
   52    *   [ 0.0  -1.0   0.0  255.0  ]  x  [ b2 ]
   53    *   [ 0.0   0.0   1.0    0.0  ]     [ b3 ]
   54    *                                   [ 1 ]
   55    * </pre>
   56    *
   57    * <p>
   58    * Note that the source and destination can be the same object.
   59    */
   60   public class BandCombineOp implements  RasterOp {
   61       float[][] matrix;
   62       int nrows = 0;
   63       int ncols = 0;
   64       RenderingHints hints;
   65   
   66       /**
   67        * Constructs a <CODE>BandCombineOp</CODE> with the specified matrix.
   68        * The width of the matrix must be equal to the number of bands in
   69        * the source <CODE>Raster</CODE>, optionally plus one.  If there is one
   70        * more column in the matrix than the number of bands, there is an implied
   71        * 1 at the end of the vector of band samples representing a pixel.  The
   72        * height of the matrix must be equal to the number of bands in the
   73        * destination.
   74        * <p>
   75        * The first subscript is the row index and the second
   76        * is the column index.  This operation uses none of the currently
   77        * defined rendering hints; the <CODE>RenderingHints</CODE> argument can be
   78        * null.
   79        *
   80        * @param matrix The matrix to use for the band combine operation.
   81        * @param hints The <CODE>RenderingHints</CODE> object for this operation.
   82        * Not currently used so it can be null.
   83        */
   84       public BandCombineOp (float[][] matrix, RenderingHints hints) {
   85           nrows = matrix.length;
   86           ncols = matrix[0].length;
   87           this.matrix = new float[nrows][];
   88           for (int i=0; i < nrows; i++) {
   89               /* Arrays.copyOf is forgiving of the source array being
   90                * too short, but it is also faster than other cloning
   91                * methods, so we provide our own protection for short
   92                * matrix rows.
   93                */
   94               if (ncols > matrix[i].length) {
   95                   throw new IndexOutOfBoundsException("row "+i+" too short");
   96               }
   97               this.matrix[i] = Arrays.copyOf(matrix[i], ncols);
   98           }
   99           this.hints  = hints;
  100       }
  101   
  102       /**
  103        * Returns a copy of the linear combination matrix.
  104        *
  105        * @return The matrix associated with this band combine operation.
  106        */
  107       public final float[][] getMatrix() {
  108           float[][] ret = new float[nrows][];
  109           for (int i = 0; i < nrows; i++) {
  110               ret[i] = Arrays.copyOf(matrix[i], ncols);
  111           }
  112           return ret;
  113       }
  114   
  115       /**
  116        * Transforms the <CODE>Raster</CODE> using the matrix specified in the
  117        * constructor. An <CODE>IllegalArgumentException</CODE> may be thrown if
  118        * the number of bands in the source or destination is incompatible with
  119        * the matrix.  See the class comments for more details.
  120        * <p>
  121        * If the destination is null, it will be created with a number of bands
  122        * equalling the number of rows in the matrix. No exception is thrown
  123        * if the operation causes a data overflow.
  124        *
  125        * @param src The <CODE>Raster</CODE> to be filtered.
  126        * @param dst The <CODE>Raster</CODE> in which to store the results
  127        * of the filter operation.
  128        *
  129        * @return The filtered <CODE>Raster</CODE>.
  130        *
  131        * @throws IllegalArgumentException If the number of bands in the
  132        * source or destination is incompatible with the matrix.
  133        */
  134       public WritableRaster filter(Raster src, WritableRaster dst) {
  135           int nBands = src.getNumBands();
  136           if (ncols != nBands && ncols != (nBands+1)) {
  137               throw new IllegalArgumentException("Number of columns in the "+
  138                                                  "matrix ("+ncols+
  139                                                  ") must be equal to the number"+
  140                                                  " of bands ([+1]) in src ("+
  141                                                  nBands+").");
  142           }
  143           if (dst == null) {
  144               dst = createCompatibleDestRaster(src);
  145           }
  146           else if (nrows != dst.getNumBands()) {
  147               throw new IllegalArgumentException("Number of rows in the "+
  148                                                  "matrix ("+nrows+
  149                                                  ") must be equal to the number"+
  150                                                  " of bands ([+1]) in dst ("+
  151                                                  nBands+").");
  152           }
  153   
  154           if (ImagingLib.filter(this, src, dst) != null) {
  155               return dst;
  156           }
  157   
  158           int[] pixel = null;
  159           int[] dstPixel = new int[dst.getNumBands()];
  160           float accum;
  161           int sminX = src.getMinX();
  162           int sY = src.getMinY();
  163           int dminX = dst.getMinX();
  164           int dY = dst.getMinY();
  165           int sX;
  166           int dX;
  167           if (ncols == nBands) {
  168               for (int y=0; y < src.getHeight(); y++, sY++, dY++) {
  169                   dX = dminX;
  170                   sX = sminX;
  171                   for (int x=0; x < src.getWidth(); x++, sX++, dX++) {
  172                       pixel = src.getPixel(sX, sY, pixel);
  173                       for (int r=0; r < nrows; r++) {
  174                           accum = 0.f;
  175                           for (int c=0; c < ncols; c++) {
  176                               accum += matrix[r][c]*pixel[c];
  177                           }
  178                           dstPixel[r] = (int) accum;
  179                       }
  180                       dst.setPixel(dX, dY, dstPixel);
  181                   }
  182               }
  183           }
  184           else {
  185               // Need to add constant
  186               for (int y=0; y < src.getHeight(); y++, sY++, dY++) {
  187                   dX = dminX;
  188                   sX = sminX;
  189                   for (int x=0; x < src.getWidth(); x++, sX++, dX++) {
  190                       pixel = src.getPixel(sX, sY, pixel);
  191                       for (int r=0; r < nrows; r++) {
  192                           accum = 0.f;
  193                           for (int c=0; c < nBands; c++) {
  194                               accum += matrix[r][c]*pixel[c];
  195                           }
  196                           dstPixel[r] = (int) (accum+matrix[r][nBands]);
  197                       }
  198                       dst.setPixel(dX, dY, dstPixel);
  199                   }
  200               }
  201           }
  202   
  203           return dst;
  204       }
  205   
  206       /**
  207        * Returns the bounding box of the transformed destination.  Since
  208        * this is not a geometric operation, the bounding box is the same for
  209        * the source and destination.
  210        * An <CODE>IllegalArgumentException</CODE> may be thrown if the number of
  211        * bands in the source is incompatible with the matrix.  See
  212        * the class comments for more details.
  213        *
  214        * @param src The <CODE>Raster</CODE> to be filtered.
  215        *
  216        * @return The <CODE>Rectangle2D</CODE> representing the destination
  217        * image's bounding box.
  218        *
  219        * @throws IllegalArgumentException If the number of bands in the source
  220        * is incompatible with the matrix.
  221        */
  222       public final Rectangle2D getBounds2D (Raster src) {
  223           return src.getBounds();
  224       }
  225   
  226   
  227       /**
  228        * Creates a zeroed destination <CODE>Raster</CODE> with the correct size
  229        * and number of bands.
  230        * An <CODE>IllegalArgumentException</CODE> may be thrown if the number of
  231        * bands in the source is incompatible with the matrix.  See
  232        * the class comments for more details.
  233        *
  234        * @param src The <CODE>Raster</CODE> to be filtered.
  235        *
  236        * @return The zeroed destination <CODE>Raster</CODE>.
  237        */
  238       public WritableRaster createCompatibleDestRaster (Raster src) {
  239           int nBands = src.getNumBands();
  240           if ((ncols != nBands) && (ncols != (nBands+1))) {
  241               throw new IllegalArgumentException("Number of columns in the "+
  242                                                  "matrix ("+ncols+
  243                                                  ") must be equal to the number"+
  244                                                  " of bands ([+1]) in src ("+
  245                                                  nBands+").");
  246           }
  247           if (src.getNumBands() == nrows) {
  248               return src.createCompatibleWritableRaster();
  249           }
  250           else {
  251               throw new IllegalArgumentException("Don't know how to create a "+
  252                                                  " compatible Raster with "+
  253                                                  nrows+" bands.");
  254           }
  255       }
  256   
  257       /**
  258        * Returns the location of the corresponding destination point given a
  259        * point in the source <CODE>Raster</CODE>.  If <CODE>dstPt</CODE> is
  260        * specified, it is used to hold the return value.
  261        * Since this is not a geometric operation, the point returned
  262        * is the same as the specified <CODE>srcPt</CODE>.
  263        *
  264        * @param srcPt The <code>Point2D</code> that represents the point in
  265        *              the source <code>Raster</code>
  266        * @param dstPt The <CODE>Point2D</CODE> in which to store the result.
  267        *
  268        * @return The <CODE>Point2D</CODE> in the destination image that
  269        * corresponds to the specified point in the source image.
  270        */
  271       public final Point2D getPoint2D (Point2D srcPt, Point2D dstPt) {
  272           if (dstPt == null) {
  273               dstPt = new Point2D.Float();
  274           }
  275           dstPt.setLocation(srcPt.getX(), srcPt.getY());
  276   
  277           return dstPt;
  278       }
  279   
  280       /**
  281        * Returns the rendering hints for this operation.
  282        *
  283        * @return The <CODE>RenderingHints</CODE> object associated with this
  284        * operation.  Returns null if no hints have been set.
  285        */
  286       public final RenderingHints getRenderingHints() {
  287           return hints;
  288       }
  289   }

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