1. /*
  2. * @(#)RGBImageFilter.java 1.24 03/12/19
  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. /**
  11. * This class provides an easy way to create an ImageFilter which modifies
  12. * the pixels of an image in the default RGB ColorModel. It is meant to
  13. * be used in conjunction with a FilteredImageSource object to produce
  14. * filtered versions of existing images. It is an abstract class that
  15. * provides the calls needed to channel all of the pixel data through a
  16. * single method which converts pixels one at a time in the default RGB
  17. * ColorModel regardless of the ColorModel being used by the ImageProducer.
  18. * The only method which needs to be defined to create a useable image
  19. * filter is the filterRGB method. Here is an example of a definition
  20. * of a filter which swaps the red and blue components of an image:
  21. * <pre>
  22. *
  23. * class RedBlueSwapFilter extends RGBImageFilter {
  24. * public RedBlueSwapFilter() {
  25. * // The filter's operation does not depend on the
  26. * // pixel's location, so IndexColorModels can be
  27. * // filtered directly.
  28. * canFilterIndexColorModel = true;
  29. * }
  30. *
  31. * public int filterRGB(int x, int y, int rgb) {
  32. * return ((rgb & 0xff00ff00)
  33. * | ((rgb & 0xff0000) >> 16)
  34. * | ((rgb & 0xff) << 16));
  35. * }
  36. * }
  37. *
  38. * </pre>
  39. *
  40. * @see FilteredImageSource
  41. * @see ImageFilter
  42. * @see ColorModel#getRGBdefault
  43. *
  44. * @version 1.24 12/19/03
  45. * @author Jim Graham
  46. */
  47. public abstract class RGBImageFilter extends ImageFilter {
  48. /**
  49. * The <code>ColorModel</code> to be replaced by
  50. * <code>newmodel</code> when the user calls
  51. * {@link #substituteColorModel(ColorModel, ColorModel) substituteColorModel}.
  52. */
  53. protected ColorModel origmodel;
  54. /**
  55. * The <code>ColorModel</code> with which to
  56. * replace <code>origmodel</code> when the user calls
  57. * <code>substituteColorModel</code>.
  58. */
  59. protected ColorModel newmodel;
  60. /**
  61. * This boolean indicates whether or not it is acceptable to apply
  62. * the color filtering of the filterRGB method to the color table
  63. * entries of an IndexColorModel object in lieu of pixel by pixel
  64. * filtering. Subclasses should set this variable to true in their
  65. * constructor if their filterRGB method does not depend on the
  66. * coordinate of the pixel being filtered.
  67. * @see #substituteColorModel
  68. * @see #filterRGB
  69. * @see IndexColorModel
  70. */
  71. protected boolean canFilterIndexColorModel;
  72. /**
  73. * If the ColorModel is an IndexColorModel and the subclass has
  74. * set the canFilterIndexColorModel flag to true, we substitute
  75. * a filtered version of the color model here and wherever
  76. * that original ColorModel object appears in the setPixels methods.
  77. * If the ColorModel is not an IndexColorModel or is null, this method
  78. * overrides the default ColorModel used by the ImageProducer and
  79. * specifies the default RGB ColorModel instead.
  80. * <p>
  81. * Note: This method is intended to be called by the
  82. * <code>ImageProducer</code> of the <code>Image</code> whose pixels
  83. * are being filtered. Developers using
  84. * this class to filter pixels from an image should avoid calling
  85. * this method directly since that operation could interfere
  86. * with the filtering operation.
  87. * @see ImageConsumer
  88. * @see ColorModel#getRGBdefault
  89. */
  90. public void setColorModel(ColorModel model) {
  91. if (canFilterIndexColorModel && (model instanceof IndexColorModel)) {
  92. ColorModel newcm = filterIndexColorModel((IndexColorModel)model);
  93. substituteColorModel(model, newcm);
  94. consumer.setColorModel(newcm);
  95. } else {
  96. consumer.setColorModel(ColorModel.getRGBdefault());
  97. }
  98. }
  99. /**
  100. * Registers two ColorModel objects for substitution. If the oldcm
  101. * is encountered during any of the setPixels methods, the newcm
  102. * is substituted and the pixels passed through
  103. * untouched (but with the new ColorModel object).
  104. * @param oldcm the ColorModel object to be replaced on the fly
  105. * @param newcm the ColorModel object to replace oldcm on the fly
  106. */
  107. public void substituteColorModel(ColorModel oldcm, ColorModel newcm) {
  108. origmodel = oldcm;
  109. newmodel = newcm;
  110. }
  111. /**
  112. * Filters an IndexColorModel object by running each entry in its
  113. * color tables through the filterRGB function that RGBImageFilter
  114. * subclasses must provide. Uses coordinates of -1 to indicate that
  115. * a color table entry is being filtered rather than an actual
  116. * pixel value.
  117. * @param icm the IndexColorModel object to be filtered
  118. * @exception NullPointerException if <code>icm</code> is null
  119. * @return a new IndexColorModel representing the filtered colors
  120. */
  121. public IndexColorModel filterIndexColorModel(IndexColorModel icm) {
  122. int mapsize = icm.getMapSize();
  123. byte r[] = new byte[mapsize];
  124. byte g[] = new byte[mapsize];
  125. byte b[] = new byte[mapsize];
  126. byte a[] = new byte[mapsize];
  127. icm.getReds(r);
  128. icm.getGreens(g);
  129. icm.getBlues(b);
  130. icm.getAlphas(a);
  131. int trans = icm.getTransparentPixel();
  132. boolean needalpha = false;
  133. for (int i = 0; i < mapsize; i++) {
  134. int rgb = filterRGB(-1, -1, icm.getRGB(i));
  135. a[i] = (byte) (rgb >> 24);
  136. if (a[i] != ((byte)0xff) && i != trans) {
  137. needalpha = true;
  138. }
  139. r[i] = (byte) (rgb >> 16);
  140. g[i] = (byte) (rgb >> 8);
  141. b[i] = (byte) (rgb >> 0);
  142. }
  143. if (needalpha) {
  144. return new IndexColorModel(icm.getPixelSize(), mapsize,
  145. r, g, b, a);
  146. } else {
  147. return new IndexColorModel(icm.getPixelSize(), mapsize,
  148. r, g, b, trans);
  149. }
  150. }
  151. /**
  152. * Filters a buffer of pixels in the default RGB ColorModel by passing
  153. * them one by one through the filterRGB method.
  154. * @param x, y the coordinates of the upper-left corner of the
  155. * region of pixels
  156. * @param w the width of the region of pixels
  157. * @param h the height of the region of pixels
  158. * @param pixels the array of pixels
  159. * @param off the offset into the <code>pixels</code> array
  160. * @param scansize the distance from one row of pixels to the next
  161. * in the array
  162. * @see ColorModel#getRGBdefault
  163. * @see #filterRGB
  164. */
  165. public void filterRGBPixels(int x, int y, int w, int h,
  166. int pixels[], int off, int scansize) {
  167. int index = off;
  168. for (int cy = 0; cy < h; cy++) {
  169. for (int cx = 0; cx < w; cx++) {
  170. pixels[index] = filterRGB(x + cx, y + cy, pixels[index]);
  171. index++;
  172. }
  173. index += scansize - w;
  174. }
  175. consumer.setPixels(x, y, w, h, ColorModel.getRGBdefault(),
  176. pixels, off, scansize);
  177. }
  178. /**
  179. * If the ColorModel object is the same one that has already
  180. * been converted, then simply passes the pixels through with the
  181. * converted ColorModel. Otherwise converts the buffer of byte
  182. * pixels to the default RGB ColorModel and passes the converted
  183. * buffer to the filterRGBPixels method to be converted one by one.
  184. * <p>
  185. * Note: This method is intended to be called by the
  186. * <code>ImageProducer</code> of the <code>Image</code> whose pixels
  187. * are being filtered. Developers using
  188. * this class to filter pixels from an image should avoid calling
  189. * this method directly since that operation could interfere
  190. * with the filtering operation.
  191. * @see ColorModel#getRGBdefault
  192. * @see #filterRGBPixels
  193. */
  194. public void setPixels(int x, int y, int w, int h,
  195. ColorModel model, byte pixels[], int off,
  196. int scansize) {
  197. if (model == origmodel) {
  198. consumer.setPixels(x, y, w, h, newmodel, pixels, off, scansize);
  199. } else {
  200. int filteredpixels[] = new int[w];
  201. int index = off;
  202. for (int cy = 0; cy < h; cy++) {
  203. for (int cx = 0; cx < w; cx++) {
  204. filteredpixels[cx] = model.getRGB((pixels[index] & 0xff));
  205. index++;
  206. }
  207. index += scansize - w;
  208. filterRGBPixels(x, y + cy, w, 1, filteredpixels, 0, w);
  209. }
  210. }
  211. }
  212. /**
  213. * If the ColorModel object is the same one that has already
  214. * been converted, then simply passes the pixels through with the
  215. * converted ColorModel, otherwise converts the buffer of integer
  216. * pixels to the default RGB ColorModel and passes the converted
  217. * buffer to the filterRGBPixels method to be converted one by one.
  218. * Converts a buffer of integer pixels to the default RGB ColorModel
  219. * and passes the converted buffer to the filterRGBPixels method.
  220. * <p>
  221. * Note: This method is intended to be called by the
  222. * <code>ImageProducer</code> of the <code>Image</code> whose pixels
  223. * are being filtered. Developers using
  224. * this class to filter pixels from an image should avoid calling
  225. * this method directly since that operation could interfere
  226. * with the filtering operation.
  227. * @see ColorModel#getRGBdefault
  228. * @see #filterRGBPixels
  229. */
  230. public void setPixels(int x, int y, int w, int h,
  231. ColorModel model, int pixels[], int off,
  232. int scansize) {
  233. if (model == origmodel) {
  234. consumer.setPixels(x, y, w, h, newmodel, pixels, off, scansize);
  235. } else {
  236. int filteredpixels[] = new int[w];
  237. int index = off;
  238. for (int cy = 0; cy < h; cy++) {
  239. for (int cx = 0; cx < w; cx++) {
  240. filteredpixels[cx] = model.getRGB(pixels[index]);
  241. index++;
  242. }
  243. index += scansize - w;
  244. filterRGBPixels(x, y + cy, w, 1, filteredpixels, 0, w);
  245. }
  246. }
  247. }
  248. /**
  249. * Subclasses must specify a method to convert a single input pixel
  250. * in the default RGB ColorModel to a single output pixel.
  251. * @param x, y the coordinates of the pixel
  252. * @param rgb the integer pixel representation in the default RGB
  253. * color model
  254. * @return a filtered pixel in the default RGB color model.
  255. * @see ColorModel#getRGBdefault
  256. * @see #filterRGBPixels
  257. */
  258. public abstract int filterRGB(int x, int y, int rgb);
  259. }