blob: f4933db67b19cf856c69ad0a180f9cf10b973bd9 [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.
*/
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;
}
}