1. /*
  2. * @(#)RGBImageFilter.java 1.22 03/01/23
  3. *
  4. * Copyright 2003 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.22 01/23/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. Otherwise
  77. * overrides the default ColorModel used by the ImageProducer and
  78. * specifies the default RGB ColorModel instead.
  79. * <p>
  80. * Note: This method is intended to be called by the
  81. * <code>ImageProducer</code> of the <code>Image</code> whose pixels
  82. * are being filtered. Developers using
  83. * this class to filter pixels from an image should avoid calling
  84. * this method directly since that operation could interfere
  85. * with the filtering operation.
  86. * @see ImageConsumer
  87. * @see ColorModel#getRGBdefault
  88. */
  89. public void setColorModel(ColorModel model) {
  90. if (canFilterIndexColorModel && (model instanceof IndexColorModel)) {
  91. ColorModel newcm = filterIndexColorModel((IndexColorModel)model);
  92. substituteColorModel(model, newcm);
  93. consumer.setColorModel(newcm);
  94. } else {
  95. consumer.setColorModel(ColorModel.getRGBdefault());
  96. }
  97. }
  98. /**
  99. * Registers two ColorModel objects for substitution. If the oldcm
  100. * is encountered during any of the setPixels methods, the newcm
  101. * is substituted and the pixels passed through
  102. * untouched (but with the new ColorModel object).
  103. * @param oldcm the ColorModel object to be replaced on the fly
  104. * @param newcm the ColorModel object to replace oldcm on the fly
  105. */
  106. public void substituteColorModel(ColorModel oldcm, ColorModel newcm) {
  107. origmodel = oldcm;
  108. newmodel = newcm;
  109. }
  110. /**
  111. * Filters an IndexColorModel object by running each entry in its
  112. * color tables through the filterRGB function that RGBImageFilter
  113. * subclasses must provide. Uses coordinates of -1 to indicate that
  114. * a color table entry is being filtered rather than an actual
  115. * pixel value.
  116. * @param icm the IndexColorModel object to be filtered
  117. * @return a new IndexColorModel representing the filtered colors
  118. */
  119. public IndexColorModel filterIndexColorModel(IndexColorModel icm) {
  120. int mapsize = icm.getMapSize();
  121. byte r[] = new byte[mapsize];
  122. byte g[] = new byte[mapsize];
  123. byte b[] = new byte[mapsize];
  124. byte a[] = new byte[mapsize];
  125. icm.getReds(r);
  126. icm.getGreens(g);
  127. icm.getBlues(b);
  128. icm.getAlphas(a);
  129. int trans = icm.getTransparentPixel();
  130. boolean needalpha = false;
  131. for (int i = 0; i < mapsize; i++) {
  132. int rgb = filterRGB(-1, -1, icm.getRGB(i));
  133. a[i] = (byte) (rgb >> 24);
  134. if (a[i] != ((byte)0xff) && i != trans) {
  135. needalpha = true;
  136. }
  137. r[i] = (byte) (rgb >> 16);
  138. g[i] = (byte) (rgb >> 8);
  139. b[i] = (byte) (rgb >> 0);
  140. }
  141. if (needalpha) {
  142. return new IndexColorModel(icm.getPixelSize(), mapsize,
  143. r, g, b, a);
  144. } else {
  145. return new IndexColorModel(icm.getPixelSize(), mapsize,
  146. r, g, b, trans);
  147. }
  148. }
  149. /**
  150. * Filters a buffer of pixels in the default RGB ColorModel by passing
  151. * them one by one through the filterRGB method.
  152. * @param x, y the coordinates of the upper-left corner of the
  153. * region of pixels
  154. * @param w the width of the region of pixels
  155. * @param h the height of the region of pixels
  156. * @param pixels the array of pixels
  157. * @param off the offset into the <code>pixels</code> array
  158. * @param scansize the distance from one row of pixels to the next
  159. * in the array
  160. * @see ColorModel#getRGBdefault
  161. * @see #filterRGB
  162. */
  163. public void filterRGBPixels(int x, int y, int w, int h,
  164. int pixels[], int off, int scansize) {
  165. int index = off;
  166. for (int cy = 0; cy < h; cy++) {
  167. for (int cx = 0; cx < w; cx++) {
  168. pixels[index] = filterRGB(x + cx, y + cy, pixels[index]);
  169. index++;
  170. }
  171. index += scansize - w;
  172. }
  173. consumer.setPixels(x, y, w, h, ColorModel.getRGBdefault(),
  174. pixels, off, scansize);
  175. }
  176. /**
  177. * If the ColorModel object is the same one that has already
  178. * been converted, then simply passes the pixels through with the
  179. * converted ColorModel. Otherwise converts the buffer of byte
  180. * pixels to the default RGB ColorModel and passes the converted
  181. * buffer to the filterRGBPixels method to be converted one by one.
  182. * <p>
  183. * Note: This method is intended to be called by the
  184. * <code>ImageProducer</code> of the <code>Image</code> whose pixels
  185. * are being filtered. Developers using
  186. * this class to filter pixels from an image should avoid calling
  187. * this method directly since that operation could interfere
  188. * with the filtering operation.
  189. * @see ColorModel#getRGBdefault
  190. * @see #filterRGBPixels
  191. */
  192. public void setPixels(int x, int y, int w, int h,
  193. ColorModel model, byte pixels[], int off,
  194. int scansize) {
  195. if (model == origmodel) {
  196. consumer.setPixels(x, y, w, h, newmodel, pixels, off, scansize);
  197. } else {
  198. int filteredpixels[] = new int[w];
  199. int index = off;
  200. for (int cy = 0; cy < h; cy++) {
  201. for (int cx = 0; cx < w; cx++) {
  202. filteredpixels[cx] = model.getRGB((pixels[index] & 0xff));
  203. index++;
  204. }
  205. index += scansize - w;
  206. filterRGBPixels(x, y + cy, w, 1, filteredpixels, 0, w);
  207. }
  208. }
  209. }
  210. /**
  211. * If the ColorModel object is the same one that has already
  212. * been converted, then simply passes the pixels through with the
  213. * converted ColorModel, otherwise converts the buffer of integer
  214. * pixels to the default RGB ColorModel and passes the converted
  215. * buffer to the filterRGBPixels method to be converted one by one.
  216. * Converts a buffer of integer pixels to the default RGB ColorModel
  217. * and passes the converted buffer to the filterRGBPixels method.
  218. * <p>
  219. * Note: This method is intended to be called by the
  220. * <code>ImageProducer</code> of the <code>Image</code> whose pixels
  221. * 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 ColorModel#getRGBdefault
  226. * @see #filterRGBPixels
  227. */
  228. public void setPixels(int x, int y, int w, int h,
  229. ColorModel model, int pixels[], int off,
  230. int scansize) {
  231. if (model == origmodel) {
  232. consumer.setPixels(x, y, w, h, newmodel, pixels, off, scansize);
  233. } else {
  234. int filteredpixels[] = new int[w];
  235. int index = off;
  236. for (int cy = 0; cy < h; cy++) {
  237. for (int cx = 0; cx < w; cx++) {
  238. filteredpixels[cx] = model.getRGB(pixels[index]);
  239. index++;
  240. }
  241. index += scansize - w;
  242. filterRGBPixels(x, y + cy, w, 1, filteredpixels, 0, w);
  243. }
  244. }
  245. }
  246. /**
  247. * Subclasses must specify a method to convert a single input pixel
  248. * in the default RGB ColorModel to a single output pixel.
  249. * @param x, y the coordinates of the pixel
  250. * @param rgb the integer pixel representation in the default RGB
  251. * color model
  252. * @return a filtered pixel in the default RGB color model.
  253. * @see ColorModel#getRGBdefault
  254. * @see #filterRGBPixels
  255. */
  256. public abstract int filterRGB(int x, int y, int rgb);
  257. }