| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| /** |
| * @author Igor V. Stolyarov |
| * @version $Revision$ |
| */ |
| package java.awt.image; |
| |
| import java.util.Arrays; |
| |
| |
| /** |
| * The AreaAveragingScaleFilter class scales the source image using |
| * area averaging algorithm. This algorithm provides a source image |
| * with a new image containing the resampled image. |
| */ |
| public class AreaAveragingScaleFilter extends ReplicateScaleFilter { |
| |
| /** The Constant rgbCM. */ |
| private static final ColorModel rgbCM = ColorModel.getRGBdefault(); |
| |
| /** The Constant averagingFlags. */ |
| private static final int averagingFlags = (ImageConsumer.TOPDOWNLEFTRIGHT | |
| ImageConsumer.COMPLETESCANLINES); |
| |
| /** The reset. */ |
| private boolean reset = true; // Flag for used superclass filter |
| |
| /** The inited. */ |
| private boolean inited = false; // All data inited |
| |
| /** The sum_r. */ |
| private int sum_r[]; // Array for average Red samples |
| |
| /** The sum_g. */ |
| private int sum_g[]; // Array for average Green samples |
| |
| /** The sum_b. */ |
| private int sum_b[]; // Array for average Blue samples |
| |
| /** The sum_a. */ |
| private int sum_a[]; // Array for average Alpha samples |
| |
| /** The buff. */ |
| private int buff[]; // Stride buffer |
| |
| /** The avg factor. */ |
| private int avgFactor; // Global averaging factor |
| |
| /** The cached dy. */ |
| private int cachedDY; // Cached number of the destination scanline |
| |
| /** The cached dv rest. */ |
| private int cachedDVRest; // Cached value of rest src scanlines for sum |
| // pixel samples |
| // Because data if transfering by whole scanlines |
| // we are caching only Y coordinate values |
| |
| /** |
| * Instantiates a new AreaAveragingScaleFilter object which scales |
| * a source image with the specified width and height. |
| * |
| * @param width the scaled width of the image. |
| * @param height the scaled height of the image. |
| */ |
| public AreaAveragingScaleFilter(int width, int height) { |
| super(width, height); |
| } |
| |
| @Override |
| public void setPixels(int x, int y, int w, int h, ColorModel model, int[] pixels, int off, int scansize) { |
| if(reset) { |
| super.setPixels(x, y, w, h, model, pixels, off, scansize); |
| } else { |
| setFilteredPixels(x, y, w, h, model, pixels, off, scansize); |
| } |
| } |
| |
| @Override |
| public void setPixels(int x, int y, int w, int h, ColorModel model, byte[] pixels, int off, int scansize) { |
| if(reset) { |
| super.setPixels(x, y, w, h, model, pixels, off, scansize); |
| } else { |
| setFilteredPixels(x, y, w, h, model, pixels, off, scansize); |
| } |
| } |
| |
| @Override |
| public void setHints(int hints) { |
| super.setHints(hints); |
| reset = ((hints & averagingFlags) != averagingFlags); |
| } |
| |
| /** |
| * This method implements the Area Averaging Scale filter. |
| * The description of algorithm is presented in Java API Specification. |
| * |
| * Arrays sum_r, sum_g, sum_b, sum_a have length equals width of destination |
| * image. In each array's element is accumulating pixel's component values, |
| * proportional to the area which source pixels will occupy in destination |
| * image. Then that values will divide by Global averaging |
| * factor (area of the destination image) for receiving |
| * average values of destination pixels. |
| * |
| * @param x - Src pixels X coordinate |
| * @param y - Src pixels Y coordinate |
| * @param w - width of the area of Src pixels |
| * @param h - height of the area of Src pixels |
| * @param model - Color Model of Src pixels |
| * @param pixels - array of Src pixels |
| * @param off - offset into the Src pixels array |
| * @param scansize - length of scanline in the pixels array |
| */ |
| private void setFilteredPixels(int x, int y, int w, int h, ColorModel model, Object pixels, int off, int scansize){ |
| if(!inited){ |
| initialize(); |
| } |
| |
| int srcX, srcY, dx, dy; |
| int svRest, dvRest, shRest, dhRest, vDif, hDif; |
| |
| if(y == 0){ |
| dy = 0; |
| dvRest = srcHeight; |
| }else{ |
| dy = cachedDY; |
| dvRest = cachedDVRest; |
| } |
| |
| srcY = y; |
| svRest = destHeight; |
| |
| int srcOff = off; |
| while (srcY < y + h) { |
| if (svRest < dvRest) { |
| vDif = svRest; |
| } else { |
| vDif = dvRest; |
| } |
| |
| srcX = 0; |
| dx = 0; |
| shRest = destWidth; |
| dhRest = srcWidth; |
| while (srcX < w) { |
| if (shRest < dhRest) { |
| hDif = shRest; |
| } else { |
| hDif = dhRest; |
| } |
| int avg = hDif * vDif; // calculation of contribution factor |
| |
| int rgb, pix; |
| if (pixels instanceof int[]) { |
| pix = ((int[]) pixels)[srcOff + srcX]; |
| } else { |
| pix = ((byte[]) pixels)[srcOff + srcX] & 0xff; |
| } |
| |
| rgb = model.getRGB(pix); |
| int a = rgb >>> 24; |
| int r = (rgb >> 16) & 0xff; |
| int g = (rgb >> 8) & 0xff; |
| int b = rgb & 0xff; |
| |
| // accumulating pixel's component values |
| sum_a[dx] += a * avg; |
| sum_r[dx] += r * avg; |
| sum_g[dx] += g * avg; |
| sum_b[dx] += b * avg; |
| |
| shRest -= hDif; |
| dhRest -= hDif; |
| |
| if (shRest == 0) { |
| srcX++; |
| shRest = destWidth; |
| } |
| |
| if (dhRest == 0) { |
| dx++; |
| dhRest = srcWidth; |
| } |
| } |
| |
| svRest -= vDif; |
| dvRest -= vDif; |
| |
| if (svRest == 0) { |
| svRest = destHeight; |
| srcY++; |
| srcOff += scansize; |
| } |
| |
| if (dvRest == 0) { |
| // averaging destination pixel's values |
| for(int i = 0; i < destWidth; i++){ |
| int a = (sum_a[i] / avgFactor) & 0xff; |
| int r = (sum_r[i] / avgFactor) & 0xff; |
| int g = (sum_g[i] / avgFactor) & 0xff; |
| int b = (sum_b[i] / avgFactor) & 0xff; |
| int frgb = (a << 24) | (r << 16) | (g << 8) | b; |
| buff[i] = frgb; |
| } |
| consumer.setPixels(0, dy, destWidth, 1, rgbCM, buff, 0, |
| destWidth); |
| dy++; |
| dvRest = srcHeight; |
| Arrays.fill(sum_a, 0); |
| Arrays.fill(sum_r, 0); |
| Arrays.fill(sum_g, 0); |
| Arrays.fill(sum_b, 0); |
| } |
| |
| } |
| |
| cachedDY = dy; |
| cachedDVRest = dvRest; |
| |
| } |
| |
| /** |
| * Initialization of the auxiliary data. |
| */ |
| private void initialize(){ |
| |
| sum_a = new int[destWidth]; |
| sum_r = new int[destWidth]; |
| sum_g = new int[destWidth]; |
| sum_b = new int[destWidth]; |
| |
| buff = new int[destWidth]; |
| outpixbuf = buff; |
| avgFactor = srcWidth * srcHeight; |
| |
| inited = true; |
| } |
| } |
| |