1. /*
  2. * @(#)AreaAveragingScaleFilter.java 1.10 00/02/02
  3. *
  4. * Copyright 1996-2000 Sun Microsystems, Inc. All Rights Reserved.
  5. *
  6. * This software is the proprietary information of Sun Microsystems, Inc.
  7. * Use is subject to license terms.
  8. *
  9. */
  10. package java.awt.image;
  11. import java.awt.image.ImageConsumer;
  12. import java.awt.image.ColorModel;
  13. import java.util.Hashtable;
  14. import java.awt.Rectangle;
  15. /**
  16. * An ImageFilter class for scaling images using a simple area averaging
  17. * algorithm that produces smoother results than the nearest neighbor
  18. * algorithm.
  19. * This class extends the basic ImageFilter Class to scale an existing
  20. * image and provide a source for a new image containing the resampled
  21. * image. The pixels in the source image are blended to produce pixels
  22. * for an image of the specified size. The blending process is analogous
  23. * to scaling up the source image to a multiple of the destination size
  24. * using pixel replication and then scaling it back down to the destination
  25. * size by simply averaging all the pixels in the supersized image that
  26. * fall within a given pixel of the destination image. If the data from
  27. * the source is not delivered in TopDownLeftRight order then the filter
  28. * will back off to a simple pixel replication behavior and utilize the
  29. * requestTopDownLeftRightResend() method to refilter the pixels in a
  30. * better way at the end.
  31. * It is meant to be used in conjunction with a FilteredImageSource
  32. * object to produce scaled versions of existing images.
  33. *
  34. * @see FilteredImageSource
  35. * @see ReplicateScaleFilter
  36. * @see ImageFilter
  37. *
  38. * @version 1.10 02/02/00
  39. * @author Jim Graham
  40. */
  41. public class AreaAveragingScaleFilter extends ReplicateScaleFilter {
  42. private static final ColorModel rgbmodel = ColorModel.getRGBdefault();
  43. private static final int neededHints = (TOPDOWNLEFTRIGHT
  44. | COMPLETESCANLINES);
  45. private boolean passthrough;
  46. private float reds[], greens[], blues[], alphas[];
  47. private int savedy;
  48. private int savedyrem;
  49. /**
  50. * Constructs an AreaAveragingScaleFilter that scales the pixels from
  51. * its source Image as specified by the width and height parameters.
  52. * @param width the target width to scale the image
  53. * @param height the target height to scale the image
  54. */
  55. public AreaAveragingScaleFilter(int width, int height) {
  56. super(width, height);
  57. }
  58. /**
  59. * Detect if the data is being delivered with the necessary hints
  60. * to allow the averaging algorithm to do its work.
  61. * <p>
  62. * Note: This method is intended to be called by the
  63. * <code>ImageProducer</code> of the <code>Image</code> whose
  64. * pixels are being filtered. Developers using
  65. * this class to filter pixels from an image should avoid calling
  66. * this method directly since that operation could interfere
  67. * with the filtering operation.
  68. * @see ImageConsumer#setHints
  69. */
  70. public void setHints(int hints) {
  71. passthrough = ((hints & neededHints) != neededHints);
  72. super.setHints(hints);
  73. }
  74. private void makeAccumBuffers() {
  75. reds = new float[destWidth];
  76. greens = new float[destWidth];
  77. blues = new float[destWidth];
  78. alphas = new float[destWidth];
  79. }
  80. private int[] calcRow() {
  81. float mult = ((float) srcWidth) * srcHeight;
  82. if (outpixbuf == null || !(outpixbuf instanceof int[])) {
  83. outpixbuf = new int[destWidth];
  84. }
  85. int[] outpix = (int[]) outpixbuf;
  86. for (int x = 0; x < destWidth; x++) {
  87. int a = Math.round(alphas[x] / mult);
  88. int r = Math.round(reds[x] / mult);
  89. int g = Math.round(greens[x] / mult);
  90. int b = Math.round(blues[x] / mult);
  91. if (a < 0) {a = 0;} else if (a > 255) {a = 255;}
  92. if (r < 0) {r = 0;} else if (r > 255) {r = 255;}
  93. if (g < 0) {g = 0;} else if (g > 255) {g = 255;}
  94. if (b < 0) {b = 0;} else if (b > 255) {b = 255;}
  95. outpix[x] = (a << 24 | r << 16 | g << 8 | b);
  96. }
  97. return outpix;
  98. }
  99. private void accumPixels(int x, int y, int w, int h,
  100. ColorModel model, Object pixels, int off,
  101. int scansize) {
  102. if (reds == null) {
  103. makeAccumBuffers();
  104. }
  105. int sy = y;
  106. int syrem = destHeight;
  107. int dy, dyrem;
  108. if (sy == 0) {
  109. dy = 0;
  110. dyrem = 0;
  111. } else {
  112. dy = savedy;
  113. dyrem = savedyrem;
  114. }
  115. while (sy < y + h) {
  116. int amty;
  117. if (dyrem == 0) {
  118. for (int i = 0; i < destWidth; i++) {
  119. alphas[i] = reds[i] = greens[i] = blues[i] = 0f;
  120. }
  121. dyrem = srcHeight;
  122. }
  123. if (syrem < dyrem) {
  124. amty = syrem;
  125. } else {
  126. amty = dyrem;
  127. }
  128. int sx = 0;
  129. int dx = 0;
  130. int sxrem = 0;
  131. int dxrem = srcWidth;
  132. float a = 0f, r = 0f, g = 0f, b = 0f;
  133. while (sx < w) {
  134. if (sxrem == 0) {
  135. sxrem = destWidth;
  136. int rgb;
  137. if (pixels instanceof byte[]) {
  138. rgb = ((byte[]) pixels)[off + sx] & 0xff;
  139. } else {
  140. rgb = ((int[]) pixels)[off + sx];
  141. }
  142. rgb = model.getRGB(rgb);
  143. a = rgb >>> 24;
  144. r = (rgb >> 16) & 0xff;
  145. g = (rgb >> 8) & 0xff;
  146. b = rgb & 0xff;
  147. }
  148. int amtx;
  149. if (sxrem < dxrem) {
  150. amtx = sxrem;
  151. } else {
  152. amtx = dxrem;
  153. }
  154. float mult = ((float) amtx) * amty;
  155. alphas[dx] += mult * a;
  156. reds[dx] += mult * r;
  157. greens[dx] += mult * g;
  158. blues[dx] += mult * b;
  159. if ((sxrem -= amtx) == 0) {
  160. sx++;
  161. }
  162. if ((dxrem -= amtx) == 0) {
  163. dx++;
  164. dxrem = srcWidth;
  165. }
  166. }
  167. if ((dyrem -= amty) == 0) {
  168. int outpix[] = calcRow();
  169. do {
  170. consumer.setPixels(0, dy, destWidth, 1,
  171. rgbmodel, outpix, 0, destWidth);
  172. dy++;
  173. } while ((syrem -= amty) >= amty && amty == srcHeight);
  174. } else {
  175. syrem -= amty;
  176. }
  177. if (syrem == 0) {
  178. syrem = destHeight;
  179. sy++;
  180. off += scansize;
  181. }
  182. }
  183. savedyrem = dyrem;
  184. savedy = dy;
  185. }
  186. /**
  187. * Combine the components for the delivered byte pixels into the
  188. * accumulation arrays and send on any averaged data for rows of
  189. * pixels that are complete. If the correct hints were not
  190. * specified in the setHints call then relay the work to our
  191. * superclass which is capable of scaling pixels regardless of
  192. * the delivery hints.
  193. * <p>
  194. * Note: This method is intended to be called by the
  195. * <code>ImageProducer</code> of the <code>Image</code>
  196. * whose pixels are being filtered. Developers using
  197. * this class to filter pixels from an image should avoid calling
  198. * this method directly since that operation could interfere
  199. * with the filtering operation.
  200. * @see ReplicateScaleFilter
  201. */
  202. public void setPixels(int x, int y, int w, int h,
  203. ColorModel model, byte pixels[], int off,
  204. int scansize) {
  205. if (passthrough) {
  206. super.setPixels(x, y, w, h, model, pixels, off, scansize);
  207. } else {
  208. accumPixels(x, y, w, h, model, pixels, off, scansize);
  209. }
  210. }
  211. /**
  212. * Combine the components for the delivered int pixels into the
  213. * accumulation arrays and send on any averaged data for rows of
  214. * pixels that are complete. If the correct hints were not
  215. * specified in the setHints call then relay the work to our
  216. * superclass which is capable of scaling pixels regardless of
  217. * the delivery hints.
  218. * <p>
  219. * Note: This method is intended to be called by the
  220. * <code>ImageProducer</code> of the <code>Image</code>
  221. * whose pixels are being filtered. Developers using
  222. * this class to filter pixels from an image should avoid calling
  223. * this method directly since that operation could interfere
  224. * with the filtering operation.
  225. * @see ReplicateScaleFilter
  226. */
  227. public void setPixels(int x, int y, int w, int h,
  228. ColorModel model, int pixels[], int off,
  229. int scansize) {
  230. if (passthrough) {
  231. super.setPixels(x, y, w, h, model, pixels, off, scansize);
  232. } else {
  233. accumPixels(x, y, w, h, model, pixels, off, scansize);
  234. }
  235. }
  236. }