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

    1   /*
    2    * Copyright (c) 1996, 2002, 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   import java.util.Hashtable;
   31   import java.awt.Rectangle;
   32   
   33   /**
   34    * An ImageFilter class for scaling images using a simple area averaging
   35    * algorithm that produces smoother results than the nearest neighbor
   36    * algorithm.
   37    * <p>This class extends the basic ImageFilter Class to scale an existing
   38    * image and provide a source for a new image containing the resampled
   39    * image.  The pixels in the source image are blended to produce pixels
   40    * for an image of the specified size.  The blending process is analogous
   41    * to scaling up the source image to a multiple of the destination size
   42    * using pixel replication and then scaling it back down to the destination
   43    * size by simply averaging all the pixels in the supersized image that
   44    * fall within a given pixel of the destination image.  If the data from
   45    * the source is not delivered in TopDownLeftRight order then the filter
   46    * will back off to a simple pixel replication behavior and utilize the
   47    * requestTopDownLeftRightResend() method to refilter the pixels in a
   48    * better way at the end.
   49    * <p>It is meant to be used in conjunction with a FilteredImageSource
   50    * object to produce scaled versions of existing images.  Due to
   51    * implementation dependencies, there may be differences in pixel values
   52    * of an image filtered on different platforms.
   53    *
   54    * @see FilteredImageSource
   55    * @see ReplicateScaleFilter
   56    * @see ImageFilter
   57    *
   58    * @author      Jim Graham
   59    */
   60   public class AreaAveragingScaleFilter extends ReplicateScaleFilter {
   61       private static final ColorModel rgbmodel = ColorModel.getRGBdefault();
   62       private static final int neededHints = (TOPDOWNLEFTRIGHT
   63                                               | COMPLETESCANLINES);
   64   
   65       private boolean passthrough;
   66       private float reds[], greens[], blues[], alphas[];
   67       private int savedy;
   68       private int savedyrem;
   69   
   70       /**
   71        * Constructs an AreaAveragingScaleFilter that scales the pixels from
   72        * its source Image as specified by the width and height parameters.
   73        * @param width the target width to scale the image
   74        * @param height the target height to scale the image
   75        */
   76       public AreaAveragingScaleFilter(int width, int height) {
   77           super(width, height);
   78       }
   79   
   80       /**
   81        * Detect if the data is being delivered with the necessary hints
   82        * to allow the averaging algorithm to do its work.
   83        * <p>
   84        * Note: This method is intended to be called by the
   85        * <code>ImageProducer</code> of the <code>Image</code> whose
   86        * pixels are being filtered.  Developers using
   87        * this class to filter pixels from an image should avoid calling
   88        * this method directly since that operation could interfere
   89        * with the filtering operation.
   90        * @see ImageConsumer#setHints
   91        */
   92       public void setHints(int hints) {
   93           passthrough = ((hints & neededHints) != neededHints);
   94           super.setHints(hints);
   95       }
   96   
   97       private void makeAccumBuffers() {
   98           reds = new float[destWidth];
   99           greens = new float[destWidth];
  100           blues = new float[destWidth];
  101           alphas = new float[destWidth];
  102       }
  103   
  104       private int[] calcRow() {
  105           float origmult = ((float) srcWidth) * srcHeight;
  106           if (outpixbuf == null || !(outpixbuf instanceof int[])) {
  107               outpixbuf = new int[destWidth];
  108           }
  109           int[] outpix = (int[]) outpixbuf;
  110           for (int x = 0; x < destWidth; x++) {
  111               float mult = origmult;
  112               int a = Math.round(alphas[x] / mult);
  113               if (a <= 0) {
  114                   a = 0;
  115               } else if (a >= 255) {
  116                   a = 255;
  117               } else {
  118                   // un-premultiply the components (by modifying mult here, we
  119                   // are effectively doing the divide by mult and divide by
  120                   // alpha in the same step)
  121                   mult = alphas[x] / 255;
  122               }
  123               int r = Math.round(reds[x] / mult);
  124               int g = Math.round(greens[x] / mult);
  125               int b = Math.round(blues[x] / mult);
  126               if (r < 0) {r = 0;} else if (r > 255) {r = 255;}
  127               if (g < 0) {g = 0;} else if (g > 255) {g = 255;}
  128               if (b < 0) {b = 0;} else if (b > 255) {b = 255;}
  129               outpix[x] = (a << 24 | r << 16 | g << 8 | b);
  130           }
  131           return outpix;
  132       }
  133   
  134       private void accumPixels(int x, int y, int w, int h,
  135                                ColorModel model, Object pixels, int off,
  136                                int scansize) {
  137           if (reds == null) {
  138               makeAccumBuffers();
  139           }
  140           int sy = y;
  141           int syrem = destHeight;
  142           int dy, dyrem;
  143           if (sy == 0) {
  144               dy = 0;
  145               dyrem = 0;
  146           } else {
  147               dy = savedy;
  148               dyrem = savedyrem;
  149           }
  150           while (sy < y + h) {
  151               int amty;
  152               if (dyrem == 0) {
  153                   for (int i = 0; i < destWidth; i++) {
  154                       alphas[i] = reds[i] = greens[i] = blues[i] = 0f;
  155                   }
  156                   dyrem = srcHeight;
  157               }
  158               if (syrem < dyrem) {
  159                   amty = syrem;
  160               } else {
  161                   amty = dyrem;
  162               }
  163               int sx = 0;
  164               int dx = 0;
  165               int sxrem = 0;
  166               int dxrem = srcWidth;
  167               float a = 0f, r = 0f, g = 0f, b = 0f;
  168               while (sx < w) {
  169                   if (sxrem == 0) {
  170                       sxrem = destWidth;
  171                       int rgb;
  172                       if (pixels instanceof byte[]) {
  173                           rgb = ((byte[]) pixels)[off + sx] & 0xff;
  174                       } else {
  175                           rgb = ((int[]) pixels)[off + sx];
  176                       }
  177                       // getRGB() always returns non-premultiplied components
  178                       rgb = model.getRGB(rgb);
  179                       a = rgb >>> 24;
  180                       r = (rgb >> 16) & 0xff;
  181                       g = (rgb >>  8) & 0xff;
  182                       b = rgb & 0xff;
  183                       // premultiply the components if necessary
  184                       if (a != 255.0f) {
  185                           float ascale = a / 255.0f;
  186                           r *= ascale;
  187                           g *= ascale;
  188                           b *= ascale;
  189                       }
  190                   }
  191                   int amtx;
  192                   if (sxrem < dxrem) {
  193                       amtx = sxrem;
  194                   } else {
  195                       amtx = dxrem;
  196                   }
  197                   float mult = ((float) amtx) * amty;
  198                   alphas[dx] += mult * a;
  199                   reds[dx] += mult * r;
  200                   greens[dx] += mult * g;
  201                   blues[dx] += mult * b;
  202                   if ((sxrem -= amtx) == 0) {
  203                       sx++;
  204                   }
  205                   if ((dxrem -= amtx) == 0) {
  206                       dx++;
  207                       dxrem = srcWidth;
  208                   }
  209               }
  210               if ((dyrem -= amty) == 0) {
  211                   int outpix[] = calcRow();
  212                   do {
  213                       consumer.setPixels(0, dy, destWidth, 1,
  214                                          rgbmodel, outpix, 0, destWidth);
  215                       dy++;
  216                   } while ((syrem -= amty) >= amty && amty == srcHeight);
  217               } else {
  218                   syrem -= amty;
  219               }
  220               if (syrem == 0) {
  221                   syrem = destHeight;
  222                   sy++;
  223                   off += scansize;
  224               }
  225           }
  226           savedyrem = dyrem;
  227           savedy = dy;
  228       }
  229   
  230       /**
  231        * Combine the components for the delivered byte pixels into the
  232        * accumulation arrays and send on any averaged data for rows of
  233        * pixels that are complete.  If the correct hints were not
  234        * specified in the setHints call then relay the work to our
  235        * superclass which is capable of scaling pixels regardless of
  236        * the delivery hints.
  237        * <p>
  238        * Note: This method is intended to be called by the
  239        * <code>ImageProducer</code> of the <code>Image</code>
  240        * whose pixels are being filtered.  Developers using
  241        * this class to filter pixels from an image should avoid calling
  242        * this method directly since that operation could interfere
  243        * with the filtering operation.
  244        * @see ReplicateScaleFilter
  245        */
  246       public void setPixels(int x, int y, int w, int h,
  247                             ColorModel model, byte pixels[], int off,
  248                             int scansize) {
  249           if (passthrough) {
  250               super.setPixels(x, y, w, h, model, pixels, off, scansize);
  251           } else {
  252               accumPixels(x, y, w, h, model, pixels, off, scansize);
  253           }
  254       }
  255   
  256       /**
  257        * Combine the components for the delivered int pixels into the
  258        * accumulation arrays and send on any averaged data for rows of
  259        * pixels that are complete.  If the correct hints were not
  260        * specified in the setHints call then relay the work to our
  261        * superclass which is capable of scaling pixels regardless of
  262        * the delivery hints.
  263        * <p>
  264        * Note: This method is intended to be called by the
  265        * <code>ImageProducer</code> of the <code>Image</code>
  266        * whose pixels are being filtered.  Developers using
  267        * this class to filter pixels from an image should avoid calling
  268        * this method directly since that operation could interfere
  269        * with the filtering operation.
  270        * @see ReplicateScaleFilter
  271        */
  272       public void setPixels(int x, int y, int w, int h,
  273                             ColorModel model, int pixels[], int off,
  274                             int scansize) {
  275           if (passthrough) {
  276               super.setPixels(x, y, w, h, model, pixels, off, scansize);
  277           } else {
  278               accumPixels(x, y, w, h, model, pixels, off, scansize);
  279           }
  280       }
  281   }

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