jdk/src/java.desktop/share/classes/java/awt/image/RGBImageFilter.java
changeset 25859 3317bb8137f4
parent 23010 6dadb192ad81
child 35667 ed476aba94de
equal deleted inserted replaced
25858:836adbf7a2cd 25859:3317bb8137f4
       
     1 /*
       
     2  * Copyright (c) 1995, 2013, 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.image.ImageConsumer;
       
    29 import java.awt.image.ColorModel;
       
    30 
       
    31 /**
       
    32  * This class provides an easy way to create an ImageFilter which modifies
       
    33  * the pixels of an image in the default RGB ColorModel.  It is meant to
       
    34  * be used in conjunction with a FilteredImageSource object to produce
       
    35  * filtered versions of existing images.  It is an abstract class that
       
    36  * provides the calls needed to channel all of the pixel data through a
       
    37  * single method which converts pixels one at a time in the default RGB
       
    38  * ColorModel regardless of the ColorModel being used by the ImageProducer.
       
    39  * The only method which needs to be defined to create a useable image
       
    40  * filter is the filterRGB method.  Here is an example of a definition
       
    41  * of a filter which swaps the red and blue components of an image:
       
    42  * <pre>{@code
       
    43  *
       
    44  *      class RedBlueSwapFilter extends RGBImageFilter {
       
    45  *          public RedBlueSwapFilter() {
       
    46  *              // The filter's operation does not depend on the
       
    47  *              // pixel's location, so IndexColorModels can be
       
    48  *              // filtered directly.
       
    49  *              canFilterIndexColorModel = true;
       
    50  *          }
       
    51  *
       
    52  *          public int filterRGB(int x, int y, int rgb) {
       
    53  *              return ((rgb & 0xff00ff00)
       
    54  *                      | ((rgb & 0xff0000) >> 16)
       
    55  *                      | ((rgb & 0xff) << 16));
       
    56  *          }
       
    57  *      }
       
    58  *
       
    59  * }</pre>
       
    60  *
       
    61  * @see FilteredImageSource
       
    62  * @see ImageFilter
       
    63  * @see ColorModel#getRGBdefault
       
    64  *
       
    65  * @author      Jim Graham
       
    66  */
       
    67 public abstract class RGBImageFilter extends ImageFilter {
       
    68 
       
    69     /**
       
    70      * The <code>ColorModel</code> to be replaced by
       
    71      * <code>newmodel</code> when the user calls
       
    72      * {@link #substituteColorModel(ColorModel, ColorModel) substituteColorModel}.
       
    73      */
       
    74     protected ColorModel origmodel;
       
    75 
       
    76     /**
       
    77      * The <code>ColorModel</code> with which to
       
    78      * replace <code>origmodel</code> when the user calls
       
    79      * <code>substituteColorModel</code>.
       
    80      */
       
    81     protected ColorModel newmodel;
       
    82 
       
    83     /**
       
    84      * This boolean indicates whether or not it is acceptable to apply
       
    85      * the color filtering of the filterRGB method to the color table
       
    86      * entries of an IndexColorModel object in lieu of pixel by pixel
       
    87      * filtering.  Subclasses should set this variable to true in their
       
    88      * constructor if their filterRGB method does not depend on the
       
    89      * coordinate of the pixel being filtered.
       
    90      * @see #substituteColorModel
       
    91      * @see #filterRGB
       
    92      * @see IndexColorModel
       
    93      */
       
    94     protected boolean canFilterIndexColorModel;
       
    95 
       
    96     /**
       
    97      * If the ColorModel is an IndexColorModel and the subclass has
       
    98      * set the canFilterIndexColorModel flag to true, we substitute
       
    99      * a filtered version of the color model here and wherever
       
   100      * that original ColorModel object appears in the setPixels methods.
       
   101      * If the ColorModel is not an IndexColorModel or is null, this method
       
   102      * overrides the default ColorModel used by the ImageProducer and
       
   103      * specifies the default RGB ColorModel instead.
       
   104      * <p>
       
   105      * Note: This method is intended to be called by the
       
   106      * <code>ImageProducer</code> of the <code>Image</code> whose pixels
       
   107      * are being filtered. Developers using
       
   108      * this class to filter pixels from an image should avoid calling
       
   109      * this method directly since that operation could interfere
       
   110      * with the filtering operation.
       
   111      * @see ImageConsumer
       
   112      * @see ColorModel#getRGBdefault
       
   113      */
       
   114     public void setColorModel(ColorModel model) {
       
   115         if (canFilterIndexColorModel && (model instanceof IndexColorModel)) {
       
   116             ColorModel newcm = filterIndexColorModel((IndexColorModel)model);
       
   117             substituteColorModel(model, newcm);
       
   118             consumer.setColorModel(newcm);
       
   119         } else {
       
   120             consumer.setColorModel(ColorModel.getRGBdefault());
       
   121         }
       
   122     }
       
   123 
       
   124     /**
       
   125      * Registers two ColorModel objects for substitution.  If the oldcm
       
   126      * is encountered during any of the setPixels methods, the newcm
       
   127      * is substituted and the pixels passed through
       
   128      * untouched (but with the new ColorModel object).
       
   129      * @param oldcm the ColorModel object to be replaced on the fly
       
   130      * @param newcm the ColorModel object to replace oldcm on the fly
       
   131      */
       
   132     public void substituteColorModel(ColorModel oldcm, ColorModel newcm) {
       
   133         origmodel = oldcm;
       
   134         newmodel = newcm;
       
   135     }
       
   136 
       
   137     /**
       
   138      * Filters an IndexColorModel object by running each entry in its
       
   139      * color tables through the filterRGB function that RGBImageFilter
       
   140      * subclasses must provide.  Uses coordinates of -1 to indicate that
       
   141      * a color table entry is being filtered rather than an actual
       
   142      * pixel value.
       
   143      * @param icm the IndexColorModel object to be filtered
       
   144      * @exception NullPointerException if <code>icm</code> is null
       
   145      * @return a new IndexColorModel representing the filtered colors
       
   146      */
       
   147     public IndexColorModel filterIndexColorModel(IndexColorModel icm) {
       
   148         int mapsize = icm.getMapSize();
       
   149         byte r[] = new byte[mapsize];
       
   150         byte g[] = new byte[mapsize];
       
   151         byte b[] = new byte[mapsize];
       
   152         byte a[] = new byte[mapsize];
       
   153         icm.getReds(r);
       
   154         icm.getGreens(g);
       
   155         icm.getBlues(b);
       
   156         icm.getAlphas(a);
       
   157         int trans = icm.getTransparentPixel();
       
   158         boolean needalpha = false;
       
   159         for (int i = 0; i < mapsize; i++) {
       
   160             int rgb = filterRGB(-1, -1, icm.getRGB(i));
       
   161             a[i] = (byte) (rgb >> 24);
       
   162             if (a[i] != ((byte)0xff) && i != trans) {
       
   163                 needalpha = true;
       
   164             }
       
   165             r[i] = (byte) (rgb >> 16);
       
   166             g[i] = (byte) (rgb >> 8);
       
   167             b[i] = (byte) (rgb >> 0);
       
   168         }
       
   169         if (needalpha) {
       
   170             return new IndexColorModel(icm.getPixelSize(), mapsize,
       
   171                                        r, g, b, a);
       
   172         } else {
       
   173             return new IndexColorModel(icm.getPixelSize(), mapsize,
       
   174                                        r, g, b, trans);
       
   175         }
       
   176     }
       
   177 
       
   178     /**
       
   179      * Filters a buffer of pixels in the default RGB ColorModel by passing
       
   180      * them one by one through the filterRGB method.
       
   181      * @param x the X coordinate of the upper-left corner of the region
       
   182      *          of pixels
       
   183      * @param y the Y coordinate of the upper-left corner of the region
       
   184      *          of pixels
       
   185      * @param w the width of the region of pixels
       
   186      * @param h the height of the region of pixels
       
   187      * @param pixels the array of pixels
       
   188      * @param off the offset into the <code>pixels</code> array
       
   189      * @param scansize the distance from one row of pixels to the next
       
   190      *        in the array
       
   191      * @see ColorModel#getRGBdefault
       
   192      * @see #filterRGB
       
   193      */
       
   194     public void filterRGBPixels(int x, int y, int w, int h,
       
   195                                 int pixels[], int off, int scansize) {
       
   196         int index = off;
       
   197         for (int cy = 0; cy < h; cy++) {
       
   198             for (int cx = 0; cx < w; cx++) {
       
   199                 pixels[index] = filterRGB(x + cx, y + cy, pixels[index]);
       
   200                 index++;
       
   201             }
       
   202             index += scansize - w;
       
   203         }
       
   204         consumer.setPixels(x, y, w, h, ColorModel.getRGBdefault(),
       
   205                            pixels, off, scansize);
       
   206     }
       
   207 
       
   208     /**
       
   209      * If the ColorModel object is the same one that has already
       
   210      * been converted, then simply passes the pixels through with the
       
   211      * converted ColorModel. Otherwise converts the buffer of byte
       
   212      * pixels to the default RGB ColorModel and passes the converted
       
   213      * buffer to the filterRGBPixels method to be converted one by one.
       
   214      * <p>
       
   215      * Note: This method is intended to be called by the
       
   216      * <code>ImageProducer</code> of the <code>Image</code> whose pixels
       
   217      * are being filtered. Developers using
       
   218      * this class to filter pixels from an image should avoid calling
       
   219      * this method directly since that operation could interfere
       
   220      * with the filtering operation.
       
   221      * @see ColorModel#getRGBdefault
       
   222      * @see #filterRGBPixels
       
   223      */
       
   224     public void setPixels(int x, int y, int w, int h,
       
   225                           ColorModel model, byte pixels[], int off,
       
   226                           int scansize) {
       
   227         if (model == origmodel) {
       
   228             consumer.setPixels(x, y, w, h, newmodel, pixels, off, scansize);
       
   229         } else {
       
   230             int filteredpixels[] = new int[w];
       
   231             int index = off;
       
   232             for (int cy = 0; cy < h; cy++) {
       
   233                 for (int cx = 0; cx < w; cx++) {
       
   234                     filteredpixels[cx] = model.getRGB((pixels[index] & 0xff));
       
   235                     index++;
       
   236                 }
       
   237                 index += scansize - w;
       
   238                 filterRGBPixels(x, y + cy, w, 1, filteredpixels, 0, w);
       
   239             }
       
   240         }
       
   241     }
       
   242 
       
   243     /**
       
   244      * If the ColorModel object is the same one that has already
       
   245      * been converted, then simply passes the pixels through with the
       
   246      * converted ColorModel, otherwise converts the buffer of integer
       
   247      * pixels to the default RGB ColorModel and passes the converted
       
   248      * buffer to the filterRGBPixels method to be converted one by one.
       
   249      * Converts a buffer of integer pixels to the default RGB ColorModel
       
   250      * and passes the converted buffer to the filterRGBPixels method.
       
   251      * <p>
       
   252      * Note: This method is intended to be called by the
       
   253      * <code>ImageProducer</code> of the <code>Image</code> whose pixels
       
   254      * are being filtered. Developers using
       
   255      * this class to filter pixels from an image should avoid calling
       
   256      * this method directly since that operation could interfere
       
   257      * with the filtering operation.
       
   258      * @see ColorModel#getRGBdefault
       
   259      * @see #filterRGBPixels
       
   260      */
       
   261     public void setPixels(int x, int y, int w, int h,
       
   262                           ColorModel model, int pixels[], int off,
       
   263                           int scansize) {
       
   264         if (model == origmodel) {
       
   265             consumer.setPixels(x, y, w, h, newmodel, pixels, off, scansize);
       
   266         } else {
       
   267             int filteredpixels[] = new int[w];
       
   268             int index = off;
       
   269             for (int cy = 0; cy < h; cy++) {
       
   270                 for (int cx = 0; cx < w; cx++) {
       
   271                     filteredpixels[cx] = model.getRGB(pixels[index]);
       
   272                     index++;
       
   273                 }
       
   274                 index += scansize - w;
       
   275                 filterRGBPixels(x, y + cy, w, 1, filteredpixels, 0, w);
       
   276             }
       
   277         }
       
   278     }
       
   279 
       
   280     /**
       
   281      * Subclasses must specify a method to convert a single input pixel
       
   282      * in the default RGB ColorModel to a single output pixel.
       
   283      * @param x the X coordinate of the pixel
       
   284      * @param y the Y coordinate of the pixel
       
   285      * @param rgb the integer pixel representation in the default RGB
       
   286      *            color model
       
   287      * @return a filtered pixel in the default RGB color model.
       
   288      * @see ColorModel#getRGBdefault
       
   289      * @see #filterRGBPixels
       
   290      */
       
   291     public abstract int filterRGB(int x, int y, int rgb);
       
   292 }