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