1. /*
  2. * @(#)ReplicateScaleFilter.java 1.20 04/07/16
  3. *
  4. * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package java.awt.image;
  8. import java.awt.image.ImageConsumer;
  9. import java.awt.image.ColorModel;
  10. import java.util.Hashtable;
  11. import java.awt.Rectangle;
  12. /**
  13. * An ImageFilter class for scaling images using the simplest algorithm.
  14. * This class extends the basic ImageFilter Class to scale an existing
  15. * image and provide a source for a new image containing the resampled
  16. * image. The pixels in the source image are sampled to produce pixels
  17. * for an image of the specified size by replicating rows and columns of
  18. * pixels to scale up or omitting rows and columns of pixels to scale
  19. * down.
  20. * <p>It is meant to be used in conjunction with a FilteredImageSource
  21. * object to produce scaled versions of existing images. Due to
  22. * implementation dependencies, there may be differences in pixel values
  23. * of an image filtered on different platforms.
  24. *
  25. * @see FilteredImageSource
  26. * @see ImageFilter
  27. *
  28. * @version 1.20 07/16/04
  29. * @author Jim Graham
  30. */
  31. public class ReplicateScaleFilter extends ImageFilter {
  32. /**
  33. * The width of the source image.
  34. */
  35. protected int srcWidth;
  36. /**
  37. * The height of the source image.
  38. */
  39. protected int srcHeight;
  40. /**
  41. * The target width to scale the image.
  42. */
  43. protected int destWidth;
  44. /**
  45. * The target height to scale the image.
  46. */
  47. protected int destHeight;
  48. /**
  49. * An <code>int</code> array containing information about a
  50. * row of pixels.
  51. */
  52. protected int srcrows[];
  53. /**
  54. * An <code>int</code> array containing information about a
  55. * column of pixels.
  56. */
  57. protected int srccols[];
  58. /**
  59. * A <code>byte</code> array initialized with a size of
  60. * {@link #destWidth} and used to deliver a row of pixel
  61. * data to the {@link ImageConsumer}.
  62. */
  63. protected Object outpixbuf;
  64. /**
  65. * Constructs a ReplicateScaleFilter that scales the pixels from
  66. * its source Image as specified by the width and height parameters.
  67. * @param width the target width to scale the image
  68. * @param height the target height to scale the image
  69. * @throws IllegalArgumentException if <code>width</code> equals
  70. * zero or <code>height</code> equals zero
  71. */
  72. public ReplicateScaleFilter(int width, int height) {
  73. if (width == 0 || height == 0) {
  74. throw new IllegalArgumentException("Width ("+width+
  75. ") and height ("+height+
  76. ") must be non-zero");
  77. }
  78. destWidth = width;
  79. destHeight = height;
  80. }
  81. /**
  82. * Passes along the properties from the source object after adding a
  83. * property indicating the scale applied.
  84. * This method invokes <code>super.setProperties</code>,
  85. * which might result in additional properties being added.
  86. * <p>
  87. * Note: This method is intended to be called by the
  88. * <code>ImageProducer</code> of the <code>Image</code> whose pixels
  89. * are being filtered. Developers using
  90. * this class to filter pixels from an image should avoid calling
  91. * this method directly since that operation could interfere
  92. * with the filtering operation.
  93. */
  94. public void setProperties(Hashtable<?,?> props) {
  95. Hashtable<Object,Object> p = (Hashtable<Object,Object>)props.clone();
  96. String key = "rescale";
  97. String val = destWidth + "x" + destHeight;
  98. Object o = p.get(key);
  99. if (o != null && o instanceof String) {
  100. val = ((String) o) + ", " + val;
  101. }
  102. p.put(key, val);
  103. super.setProperties(p);
  104. }
  105. /**
  106. * Override the dimensions of the source image and pass the dimensions
  107. * of the new scaled size to the ImageConsumer.
  108. * <p>
  109. * Note: This method is intended to be called by the
  110. * <code>ImageProducer</code> of the <code>Image</code> whose pixels
  111. * are being filtered. Developers using
  112. * this class to filter pixels from an image should avoid calling
  113. * this method directly since that operation could interfere
  114. * with the filtering operation.
  115. * @see ImageConsumer
  116. */
  117. public void setDimensions(int w, int h) {
  118. srcWidth = w;
  119. srcHeight = h;
  120. if (destWidth < 0) {
  121. if (destHeight < 0) {
  122. destWidth = srcWidth;
  123. destHeight = srcHeight;
  124. } else {
  125. destWidth = srcWidth * destHeight / srcHeight;
  126. }
  127. } else if (destHeight < 0) {
  128. destHeight = srcHeight * destWidth / srcWidth;
  129. }
  130. consumer.setDimensions(destWidth, destHeight);
  131. }
  132. private void calculateMaps() {
  133. srcrows = new int[destHeight + 1];
  134. for (int y = 0; y <= destHeight; y++) {
  135. srcrows[y] = (2 * y * srcHeight + srcHeight) / (2 * destHeight);
  136. }
  137. srccols = new int[destWidth + 1];
  138. for (int x = 0; x <= destWidth; x++) {
  139. srccols[x] = (2 * x * srcWidth + srcWidth) / (2 * destWidth);
  140. }
  141. }
  142. /**
  143. * Choose which rows and columns of the delivered byte pixels are
  144. * needed for the destination scaled image and pass through just
  145. * those rows and columns that are needed, replicated as necessary.
  146. * <p>
  147. * Note: This method is intended to be called by the
  148. * <code>ImageProducer</code> of the <code>Image</code> whose pixels
  149. * are being filtered. Developers using
  150. * this class to filter pixels from an image should avoid calling
  151. * this method directly since that operation could interfere
  152. * with the filtering operation.
  153. */
  154. public void setPixels(int x, int y, int w, int h,
  155. ColorModel model, byte pixels[], int off,
  156. int scansize) {
  157. if (srcrows == null || srccols == null) {
  158. calculateMaps();
  159. }
  160. int sx, sy;
  161. int dx1 = (2 * x * destWidth + srcWidth - 1) / (2 * srcWidth);
  162. int dy1 = (2 * y * destHeight + srcHeight - 1) / (2 * srcHeight);
  163. byte outpix[];
  164. if (outpixbuf != null && outpixbuf instanceof byte[]) {
  165. outpix = (byte[]) outpixbuf;
  166. } else {
  167. outpix = new byte[destWidth];
  168. outpixbuf = outpix;
  169. }
  170. for (int dy = dy1; (sy = srcrows[dy]) < y + h; dy++) {
  171. int srcoff = off + scansize * (sy - y);
  172. int dx;
  173. for (dx = dx1; (sx = srccols[dx]) < x + w; dx++) {
  174. outpix[dx] = pixels[srcoff + sx - x];
  175. }
  176. if (dx > dx1) {
  177. consumer.setPixels(dx1, dy, dx - dx1, 1,
  178. model, outpix, dx1, destWidth);
  179. }
  180. }
  181. }
  182. /**
  183. * Choose which rows and columns of the delivered int pixels are
  184. * needed for the destination scaled image and pass through just
  185. * those rows and columns that are needed, replicated as necessary.
  186. * <p>
  187. * Note: This method is intended to be called by the
  188. * <code>ImageProducer</code> of the <code>Image</code> whose pixels
  189. * are being filtered. Developers using
  190. * this class to filter pixels from an image should avoid calling
  191. * this method directly since that operation could interfere
  192. * with the filtering operation.
  193. */
  194. public void setPixels(int x, int y, int w, int h,
  195. ColorModel model, int pixels[], int off,
  196. int scansize) {
  197. if (srcrows == null || srccols == null) {
  198. calculateMaps();
  199. }
  200. int sx, sy;
  201. int dx1 = (2 * x * destWidth + srcWidth - 1) / (2 * srcWidth);
  202. int dy1 = (2 * y * destHeight + srcHeight - 1) / (2 * srcHeight);
  203. int outpix[];
  204. if (outpixbuf != null && outpixbuf instanceof int[]) {
  205. outpix = (int[]) outpixbuf;
  206. } else {
  207. outpix = new int[destWidth];
  208. outpixbuf = outpix;
  209. }
  210. for (int dy = dy1; (sy = srcrows[dy]) < y + h; dy++) {
  211. int srcoff = off + scansize * (sy - y);
  212. int dx;
  213. for (dx = dx1; (sx = srccols[dx]) < x + w; dx++) {
  214. outpix[dx] = pixels[srcoff + sx - x];
  215. }
  216. if (dx > dx1) {
  217. consumer.setPixels(dx1, dy, dx - dx1, 1,
  218. model, outpix, dx1, destWidth);
  219. }
  220. }
  221. }
  222. }