/* * 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. * * @since Android 1.0 */ 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 transferring 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 * the source pixels X coordinate. * @param y * the source pixels Y coordinate. * @param w * the width of the area of the source pixels. * @param h * the height of the area of the source pixels. * @param model * the color model of the source pixels. * @param pixels * the array of source pixels. * @param off * the offset into the source pixels array. * @param scansize * the 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; } }