blob: 7fb138e7fa22547bf3c04b8834fa539fc5ddae46 [file] [log] [blame]
/*
* 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;
}
}