home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1998 July & August / Pcwk78a98.iso / Internet / Javadraw / DATA.Z / AreaAveragingScaleFilter.java < prev    next >
Text File  |  1997-08-30  |  7KB  |  239 lines

  1. /*
  2.  * @(#)AreaAveragingScaleFilter.java    1.3 97/01/27
  3.  * 
  4.  * Copyright (c) 1995, 1996 Sun Microsystems, Inc. All Rights Reserved.
  5.  * 
  6.  * This software is the confidential and proprietary information of Sun
  7.  * Microsystems, Inc. ("Confidential Information").  You shall not
  8.  * disclose such Confidential Information and shall use it only in
  9.  * accordance with the terms of the license agreement you entered into
  10.  * with Sun.
  11.  * 
  12.  * SUN MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
  13.  * SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
  14.  * IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
  15.  * PURPOSE, OR NON-INFRINGEMENT. SUN SHALL NOT BE LIABLE FOR ANY DAMAGES
  16.  * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
  17.  * THIS SOFTWARE OR ITS DERIVATIVES.
  18.  * 
  19.  * CopyrightVersion 1.1_beta
  20.  * 
  21.  */
  22.  
  23. package java.awt.image;
  24.  
  25. import java.awt.image.ImageConsumer;
  26. import java.awt.image.ColorModel;
  27. import java.util.Hashtable;
  28. import java.awt.Rectangle;
  29.  
  30. /**
  31.  * An ImageFilter class for scaling images using a simple area averaging
  32.  * algorithm that produces smoother results than the nearest neighbor
  33.  * algorithm.
  34.  * This class extends the basic ImageFilter Class to scale an existing
  35.  * image and provide a source for a new image containing the resampled
  36.  * image.  The pixels in the source image are blended to produce pixels
  37.  * for an image of the specified size.  The blending process is analogous
  38.  * to scaling up the source image to a multiple of the destination size
  39.  * using pixel replication and then scaling it back down to the destination
  40.  * size by simply averaging all the pixels in the supersized image that
  41.  * fall within a given pixel of the destination image.  If the data from
  42.  * the source is not delivered in TopDownLeftRight order then the filter
  43.  * will back off to a simple pixel replication behavior and utilize the
  44.  * requestTopDownLeftRightResend() method to refilter the pixels in a
  45.  * better way at the end.
  46.  * It is meant to be used in conjunction with a FilteredImageSource
  47.  * object to produce scaled versions of existing images.
  48.  *
  49.  * @see FilteredImageSource
  50.  * @see ReplicateImageFilter
  51.  * @see ImageFilter
  52.  *
  53.  * @version    1.3 01/27/97
  54.  * @author     Jim Graham
  55.  */
  56. public class AreaAveragingScaleFilter extends ReplicateScaleFilter {
  57.     private static final ColorModel rgbmodel = ColorModel.getRGBdefault();
  58.     private static final int neededHints = (TOPDOWNLEFTRIGHT
  59.                         | COMPLETESCANLINES);
  60.  
  61.     private boolean passthrough;
  62.     private float reds[], greens[], blues[], alphas[];
  63.     private int savedy;
  64.     private int savedyrem;
  65.  
  66.     /**
  67.      * Constructs an AreaAveragingScaleFilter that scales the pixels from
  68.      * its source Image as specified by the width and height parameters.
  69.      * @param width the target width to scale the image
  70.      * @param height the target height to scale the image
  71.      */
  72.     public AreaAveragingScaleFilter(int width, int height) {
  73.     super(width, height);
  74.     }
  75.  
  76.     /**
  77.      * Detect if the data is being delivered with the necessary hints
  78.      * to allow the averaging algorithm to do its work.
  79.      * @see ImageConsumer#setHints
  80.      */
  81.     public void setHints(int hints) {
  82.     passthrough = ((hints & neededHints) != neededHints);
  83.     super.setHints(hints);
  84.     }
  85.  
  86.     private void makeAccumBuffers() {
  87.     reds = new float[destWidth];
  88.     greens = new float[destWidth];
  89.     blues = new float[destWidth];
  90.     alphas = new float[destWidth];
  91.     }
  92.  
  93.     private int[] calcRow() {
  94.     float mult = ((float) srcWidth) * srcHeight;
  95.     if (outpixbuf == null || !(outpixbuf instanceof int[])) {
  96.         outpixbuf = new int[destWidth];
  97.     }
  98.     int[] outpix = (int[]) outpixbuf;
  99.     for (int x = 0; x < destWidth; x++) {
  100.         int a = Math.round(alphas[x] / mult);
  101.         int r = Math.round(reds[x] / mult);
  102.         int g = Math.round(greens[x] / mult);
  103.         int b = Math.round(blues[x] / mult);
  104.         if (a < 0) {a = 0;} else if (a > 255) {a = 255;}
  105.         if (r < 0) {r = 0;} else if (r > 255) {r = 255;}
  106.         if (g < 0) {g = 0;} else if (g > 255) {g = 255;}
  107.         if (b < 0) {b = 0;} else if (b > 255) {b = 255;}
  108.         outpix[x] = (a << 24 | r << 16 | g << 8 | b);
  109.     }
  110.     return outpix;
  111.     }
  112.  
  113.     private void accumPixels(int x, int y, int w, int h,
  114.                  ColorModel model, Object pixels, int off,
  115.                  int scansize) {
  116.     if (reds == null) {
  117.         makeAccumBuffers();
  118.     }
  119.     int sy = y;
  120.     int syrem = destHeight;
  121.     int dy, dyrem;
  122.     if (sy == 0) {
  123.         dy = 0;
  124.         dyrem = 0;
  125.     } else {
  126.         dy = savedy;
  127.         dyrem = savedyrem;
  128.     }
  129.     while (sy < y + h) {
  130.         int amty;
  131.         if (dyrem == 0) {
  132.         for (int i = 0; i < destWidth; i++) {
  133.             alphas[i] = reds[i] = greens[i] = blues[i] = 0f;
  134.         }
  135.         dyrem = srcHeight;
  136.         }
  137.         if (syrem < dyrem) {
  138.         amty = syrem;
  139.         } else {
  140.         amty = dyrem;
  141.         }
  142.         int sx = 0;
  143.         int dx = 0;
  144.         int sxrem = 0;
  145.         int dxrem = srcWidth;
  146.         float a = 0f, r = 0f, g = 0f, b = 0f;
  147.         while (sx < w) {
  148.         if (sxrem == 0) {
  149.             sxrem = destWidth;
  150.             int rgb;
  151.             if (pixels instanceof byte[]) {
  152.             rgb = ((byte[]) pixels)[off + sx] & 0xff;
  153.             } else {
  154.             rgb = ((int[]) pixels)[off + sx];
  155.             }
  156.             rgb = model.getRGB(rgb);
  157.             a = rgb >>> 24;
  158.             r = (rgb >> 16) & 0xff;
  159.             g = (rgb >>  8) & 0xff;
  160.             b = rgb & 0xff;
  161.         }
  162.         int amtx;
  163.         if (sxrem < dxrem) {
  164.             amtx = sxrem;
  165.         } else {
  166.             amtx = dxrem;
  167.         }
  168.         float mult = ((float) amtx) * amty;
  169.         alphas[dx] += mult * a;
  170.         reds[dx] += mult * r;
  171.         greens[dx] += mult * g;
  172.         blues[dx] += mult * b;
  173.         if ((sxrem -= amtx) == 0) {
  174.             sx++;
  175.         }
  176.         if ((dxrem -= amtx) == 0) {
  177.             dx++;
  178.             dxrem = srcWidth;
  179.         }
  180.         }
  181.         if ((dyrem -= amty) == 0) {
  182.         int outpix[] = calcRow();
  183.         do {
  184.             consumer.setPixels(0, dy, destWidth, 1,
  185.                        rgbmodel, outpix, 0, destWidth);
  186.             dy++;
  187.         } while ((syrem -= amty) >= amty && amty == srcHeight);
  188.         } else {
  189.         syrem -= amty;
  190.         }
  191.         if (syrem == 0) {
  192.         syrem = destHeight;
  193.         sy++;
  194.         off += scansize;
  195.         }
  196.     }
  197.     savedyrem = dyrem;
  198.     savedy = dy;
  199.     }
  200.  
  201.     /**
  202.      * Combine the components for the delivered byte pixels into the
  203.      * accumulation arrays and send on any averaged data for rows of
  204.      * pixels that are complete.  If the correct hints were not
  205.      * specified in the setHints call then relay the work to our
  206.      * superclass which is capable of scaling pixels regardless of
  207.      * the delivery hints.
  208.      * @see ReplicateScaleFilter
  209.      */
  210.     public void setPixels(int x, int y, int w, int h,
  211.               ColorModel model, byte pixels[], int off,
  212.               int scansize) {
  213.     if (passthrough) {
  214.         super.setPixels(x, y, w, h, model, pixels, off, scansize);
  215.     } else {
  216.         accumPixels(x, y, w, h, model, pixels, off, scansize);
  217.     }
  218.     }
  219.  
  220.     /**
  221.      * Combine the components for the delivered int pixels into the
  222.      * accumulation arrays and send on any averaged data for rows of
  223.      * pixels that are complete.  If the correct hints were not
  224.      * specified in the setHints call then relay the work to our
  225.      * superclass which is capable of scaling pixels regardless of
  226.      * the delivery hints.
  227.      * @see ReplicateScaleFilter
  228.      */
  229.     public void setPixels(int x, int y, int w, int h,
  230.               ColorModel model, int pixels[], int off,
  231.               int scansize) {
  232.     if (passthrough) {
  233.         super.setPixels(x, y, w, h, model, pixels, off, scansize);
  234.     } else {
  235.         accumPixels(x, y, w, h, model, pixels, off, scansize);
  236.     }
  237.     }
  238. }
  239.