001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: /**
018: * @author Igor V. Stolyarov
019: * @version $Revision$
020: */package java.awt.image;
021:
022: import java.util.Arrays;
023:
024: public class AreaAveragingScaleFilter extends ReplicateScaleFilter {
025:
026: private static final ColorModel rgbCM = ColorModel.getRGBdefault();
027: private static final int averagingFlags = (ImageConsumer.TOPDOWNLEFTRIGHT | ImageConsumer.COMPLETESCANLINES);
028:
029: private boolean reset = true; // Flag for used superclass filter
030: private boolean inited = false; // All data inited
031:
032: private int sum_r[]; // Array for average Red samples
033: private int sum_g[]; // Array for average Green samples
034: private int sum_b[]; // Array for average Blue samples
035: private int sum_a[]; // Array for average Alpha samples
036:
037: private int buff[]; // Stride buffer
038: private int avgFactor; // Global averaging factor
039:
040: private int cachedDY; // Cached number of the destination scanline
041: private int cachedDVRest; // Cached value of rest src scanlines for sum
042:
043: // pixel samples
044: // Because data if transfering by whole scanlines
045: // we are caching only Y coordinate values
046:
047: public AreaAveragingScaleFilter(int width, int height) {
048: super (width, height);
049: }
050:
051: @Override
052: public void setPixels(int x, int y, int w, int h, ColorModel model,
053: int[] pixels, int off, int scansize) {
054: if (reset) {
055: super .setPixels(x, y, w, h, model, pixels, off, scansize);
056: } else {
057: setFilteredPixels(x, y, w, h, model, pixels, off, scansize);
058: }
059: }
060:
061: @Override
062: public void setPixels(int x, int y, int w, int h, ColorModel model,
063: byte[] pixels, int off, int scansize) {
064: if (reset) {
065: super .setPixels(x, y, w, h, model, pixels, off, scansize);
066: } else {
067: setFilteredPixels(x, y, w, h, model, pixels, off, scansize);
068: }
069: }
070:
071: @Override
072: public void setHints(int hints) {
073: super .setHints(hints);
074: reset = ((hints & averagingFlags) != averagingFlags);
075: }
076:
077: /**
078: * This method implemented Area Averaging Scale filter.
079: * The description of algorithm is presented in Java API Specification.
080: *
081: * Arrays sum_r, sum_g, sum_b, sum_a have length equals width of destination
082: * image. In each array's element is accumulating pixel's component values,
083: * proportional to the area which source pixels will occupy in destination
084: * image. Then that values will divide by Global averaging
085: * factor (area of the destination image) for receiving
086: * average values of destination pixels.
087: *
088: * @param x - Src pixels X coordinate
089: * @param y - Src pixels Y coordinate
090: * @param w - width of the area of Src pixels
091: * @param h - height of the area of Src pixels
092: * @param model - Color Model of Src pixels
093: * @param pixels - array of Src pixels
094: * @param off - offset into the Src pixels array
095: * @param scansize - length of scanline in the pixels array
096: */
097: private void setFilteredPixels(int x, int y, int w, int h,
098: ColorModel model, Object pixels, int off, int scansize) {
099: if (!inited) {
100: initialize();
101: }
102:
103: int srcX, srcY, dx, dy;
104: int svRest, dvRest, shRest, dhRest, vDif, hDif;
105:
106: if (y == 0) {
107: dy = 0;
108: dvRest = srcHeight;
109: } else {
110: dy = cachedDY;
111: dvRest = cachedDVRest;
112: }
113:
114: srcY = y;
115: svRest = destHeight;
116:
117: int srcOff = off;
118: while (srcY < y + h) {
119: if (svRest < dvRest) {
120: vDif = svRest;
121: } else {
122: vDif = dvRest;
123: }
124:
125: srcX = 0;
126: dx = 0;
127: shRest = destWidth;
128: dhRest = srcWidth;
129: while (srcX < w) {
130: if (shRest < dhRest) {
131: hDif = shRest;
132: } else {
133: hDif = dhRest;
134: }
135: int avg = hDif * vDif; // calculation of contribution factor
136:
137: int rgb, pix;
138: if (pixels instanceof int[]) {
139: pix = ((int[]) pixels)[srcOff + srcX];
140: } else {
141: pix = ((byte[]) pixels)[srcOff + srcX] & 0xff;
142: }
143:
144: rgb = model.getRGB(pix);
145: int a = rgb >>> 24;
146: int r = (rgb >> 16) & 0xff;
147: int g = (rgb >> 8) & 0xff;
148: int b = rgb & 0xff;
149:
150: // accumulating pixel's component values
151: sum_a[dx] += a * avg;
152: sum_r[dx] += r * avg;
153: sum_g[dx] += g * avg;
154: sum_b[dx] += b * avg;
155:
156: shRest -= hDif;
157: dhRest -= hDif;
158:
159: if (shRest == 0) {
160: srcX++;
161: shRest = destWidth;
162: }
163:
164: if (dhRest == 0) {
165: dx++;
166: dhRest = srcWidth;
167: }
168: }
169:
170: svRest -= vDif;
171: dvRest -= vDif;
172:
173: if (svRest == 0) {
174: svRest = destHeight;
175: srcY++;
176: srcOff += scansize;
177: }
178:
179: if (dvRest == 0) {
180: // averaging destination pixel's values
181: for (int i = 0; i < destWidth; i++) {
182: int a = (sum_a[i] / avgFactor) & 0xff;
183: int r = (sum_r[i] / avgFactor) & 0xff;
184: int g = (sum_g[i] / avgFactor) & 0xff;
185: int b = (sum_b[i] / avgFactor) & 0xff;
186: int frgb = (a << 24) | (r << 16) | (g << 8) | b;
187: buff[i] = frgb;
188: }
189: consumer.setPixels(0, dy, destWidth, 1, rgbCM, buff, 0,
190: destWidth);
191: dy++;
192: dvRest = srcHeight;
193: Arrays.fill(sum_a, 0);
194: Arrays.fill(sum_r, 0);
195: Arrays.fill(sum_g, 0);
196: Arrays.fill(sum_b, 0);
197: }
198:
199: }
200:
201: cachedDY = dy;
202: cachedDVRest = dvRest;
203:
204: }
205:
206: /**
207: * Initialization of the auxiliary data
208: */
209: private void initialize() {
210:
211: sum_a = new int[destWidth];
212: sum_r = new int[destWidth];
213: sum_g = new int[destWidth];
214: sum_b = new int[destWidth];
215:
216: buff = new int[destWidth];
217: outpixbuf = buff;
218: avgFactor = srcWidth * srcHeight;
219:
220: inited = true;
221: }
222: }
|