1. /*
  2. * @(#)BufferedImageFilter.java 1.22 01/11/29
  3. *
  4. * Copyright 2002 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.util.Hashtable;
  9. import java.awt.image.ImageConsumer;
  10. import java.awt.image.ImageFilter;
  11. /**
  12. * This class subclasses an ImageFilter to provide a simple means of
  13. * using a single-source/single-destination image operator
  14. * (BufferedImageOp) to filter
  15. * a BufferedImage in the Image Producer/Consumer/Observer
  16. * paradigm. Examples of these image operators are: ConvolveOp,
  17. * AffineTransformOp and LookupOp.
  18. *
  19. * @see ImageFilter
  20. * @see BufferedImage
  21. * @see BufferedImageOp
  22. * @version 10 Feb 1997
  23. */
  24. public class BufferedImageFilter extends ImageFilter implements Cloneable {
  25. BufferedImageOp bufferedImageOp;
  26. ColorModel model;
  27. int width;
  28. int height;
  29. byte[] bytePixels;
  30. int[] intPixels;
  31. /**
  32. * Constructs a BufferedImageFilter with the
  33. * specified single-source/single-destination operator.
  34. */
  35. public BufferedImageFilter (BufferedImageOp op) {
  36. super();
  37. bufferedImageOp = op;
  38. }
  39. /**
  40. * Returns the BufferedImageOp.
  41. */
  42. public BufferedImageOp getBufferedImageOp() {
  43. return bufferedImageOp;
  44. }
  45. /**
  46. * Filters the information provided in the setDimensions method
  47. * of the ImageConsumer interface.
  48. * <p>
  49. * Note: This method is intended to be called by the ImageProducer
  50. * of the Image whose pixels are being filtered. Developers using
  51. * this class to retrieve pixels from an image should avoid calling
  52. * this method directly since that operation could result in problems
  53. * with retrieving the requested pixels.
  54. * @see ImageConsumer#setDimensions
  55. */
  56. public void setDimensions(int width, int height) {
  57. if (width <= 0 || height <= 0) {
  58. imageComplete(STATICIMAGEDONE);
  59. return;
  60. }
  61. this.width = width;
  62. this.height = height;
  63. }
  64. /**
  65. * Filters the information provided in the setColorModel method
  66. * of the ImageConsumer interface.
  67. * <p>
  68. * Note: This method is intended to be called by the ImageProducer
  69. * of the Image whose pixels are being filtered. Developers using
  70. * this class to retrieve pixels from an image should avoid calling
  71. * this method directly since that operation could result in problems
  72. * with retrieving the requested pixels.
  73. * @see ImageConsumer#setColorModel
  74. */
  75. public void setColorModel(ColorModel model) {
  76. this.model = model;
  77. }
  78. private void convertToRGB() {
  79. int size = width * height;
  80. int newpixels[] = new int[size];
  81. if (bytePixels != null) {
  82. for (int i = 0; i < size; i++) {
  83. newpixels[i] = this.model.getRGB(bytePixels[i] & 0xff);
  84. }
  85. } else if (intPixels != null) {
  86. for (int i = 0; i < size; i++) {
  87. newpixels[i] = this.model.getRGB(intPixels[i]);
  88. }
  89. }
  90. bytePixels = null;
  91. intPixels = newpixels;
  92. this.model = ColorModel.getRGBdefault();
  93. }
  94. /**
  95. * Filters the information provided in the setPixels method of the
  96. * ImageConsumer interface which takes an array of bytes.
  97. * <p>
  98. * Note: This method is intended to be called by the ImageProducer
  99. * of the Image whose pixels are being filtered. Developers using
  100. * this class to retrieve pixels from an image should avoid calling
  101. * this method directly since that operation could result in problems
  102. * with retrieving the requested pixels.
  103. * @see ImageConsumer#setPixels(int, int, int, int, ColorModel, byte[],
  104. int, int)
  105. */
  106. public void setPixels(int x, int y, int w, int h,
  107. ColorModel model, byte pixels[], int off,
  108. int scansize) {
  109. if (y < 0) {
  110. int diff = -y;
  111. if (diff >= h) {
  112. return;
  113. }
  114. off += scansize * diff;
  115. y += diff;
  116. h -= diff;
  117. }
  118. if (y + h > height) {
  119. h = height - y;
  120. if (h <= 0) {
  121. return;
  122. }
  123. }
  124. if (x < 0) {
  125. int diff = -x;
  126. if (diff >= w) {
  127. return;
  128. }
  129. off += diff;
  130. x += diff;
  131. w -= diff;
  132. }
  133. if (x + w > width) {
  134. w = width - x;
  135. if (w <= 0) {
  136. return;
  137. }
  138. }
  139. int dstPtr = y*width + x;
  140. if (intPixels == null) {
  141. if (bytePixels == null) {
  142. bytePixels = new byte[width*height];
  143. this.model = model;
  144. } else if (this.model != model) {
  145. convertToRGB();
  146. }
  147. if (bytePixels != null) {
  148. for (int sh = h; sh > 0; sh--) {
  149. System.arraycopy(pixels, off, bytePixels, dstPtr, w);
  150. off += scansize;
  151. dstPtr += width;
  152. }
  153. }
  154. }
  155. if (intPixels != null) {
  156. int dstRem = width - w;
  157. int srcRem = scansize - w;
  158. for (int sh = h; sh > 0; sh--) {
  159. for (int sw = w; sw > 0; sw--) {
  160. intPixels[dstPtr++] = model.getRGB(pixels[off++]&0xff);
  161. }
  162. off += srcRem;
  163. dstPtr += dstRem;
  164. }
  165. }
  166. }
  167. /**
  168. * Filters the information provided in the setPixels method of the
  169. * ImageConsumer interface which takes an array of integers.
  170. * <p>
  171. * Note: This method is intended to be called by the ImageProducer
  172. * of the Image whose pixels are being filtered. Developers using
  173. * this class to retrieve pixels from an image should avoid calling
  174. * this method directly since that operation could result in problems
  175. * with retrieving the requested pixels.
  176. * @see ImageConsumer#setPixels(int, int, int, int, ColorModel, int[],
  177. int, int)
  178. */
  179. public void setPixels(int x, int y, int w, int h,
  180. ColorModel model, int pixels[], int off,
  181. int scansize) {
  182. if (y < 0) {
  183. int diff = -y;
  184. if (diff >= h) {
  185. return;
  186. }
  187. off += scansize * diff;
  188. y += diff;
  189. h -= diff;
  190. }
  191. if (y + h > height) {
  192. h = height - y;
  193. if (h <= 0) {
  194. return;
  195. }
  196. }
  197. if (x < 0) {
  198. int diff = -x;
  199. if (diff >= w) {
  200. return;
  201. }
  202. off += diff;
  203. x += diff;
  204. w -= diff;
  205. }
  206. if (x + w > width) {
  207. w = width - x;
  208. if (w <= 0) {
  209. return;
  210. }
  211. }
  212. if (intPixels == null) {
  213. if (bytePixels == null) {
  214. intPixels = new int[width * height];
  215. this.model = model;
  216. } else {
  217. convertToRGB();
  218. }
  219. }
  220. int dstPtr = y*width + x;
  221. if (this.model == model) {
  222. for (int sh = h; sh > 0; sh--) {
  223. System.arraycopy(pixels, off, intPixels, dstPtr, w);
  224. off += scansize;
  225. dstPtr += width;
  226. }
  227. } else {
  228. if (this.model != ColorModel.getRGBdefault()) {
  229. convertToRGB();
  230. }
  231. int dstRem = width - w;
  232. int srcRem = scansize - w;
  233. for (int sh = h; sh > 0; sh--) {
  234. for (int sw = w; sw > 0; sw--) {
  235. intPixels[dstPtr++] = model.getRGB(pixels[off++]);
  236. }
  237. off += srcRem;
  238. dstPtr += dstRem;
  239. }
  240. }
  241. }
  242. /**
  243. * Filters the information provided in the imageComplete method of
  244. * the ImageConsumer interface.
  245. * <p>
  246. * Note: This method is intended to be called by the ImageProducer
  247. * of the Image whose pixels are being filtered. Developers using
  248. * this class to retrieve pixels from an image should avoid calling
  249. * this method directly since that operation could result in problems
  250. * with retrieving the requested pixels.
  251. * @see ImageConsumer#imageComplete
  252. * @throws ImagingOpException if there was a problem calling the filter
  253. * method of the BufferedImageOp associated with this instance.
  254. */
  255. public void imageComplete(int status) {
  256. WritableRaster wr;
  257. switch(status) {
  258. case IMAGEERROR:
  259. case IMAGEABORTED:
  260. // reinitialize the params
  261. model = null;
  262. width = -1;
  263. height = -1;
  264. intPixels = null;
  265. bytePixels = null;
  266. break;
  267. case SINGLEFRAMEDONE:
  268. case STATICIMAGEDONE:
  269. if (width <= 0 || height <= 0) break;
  270. if (model instanceof DirectColorModel) {
  271. if (intPixels == null) break;
  272. wr = createDCMraster();
  273. }
  274. else if (model instanceof IndexColorModel) {
  275. int[] bandOffsets = {0};
  276. if (bytePixels == null) break;
  277. DataBufferByte db = new DataBufferByte(bytePixels,
  278. width*height);
  279. wr = Raster.createInterleavedRaster(db, width, height, width,
  280. 1, bandOffsets, null);
  281. }
  282. else {
  283. convertToRGB();
  284. if (intPixels == null) break;
  285. wr = createDCMraster();
  286. }
  287. BufferedImage bi = new BufferedImage(model, wr,
  288. model.isAlphaPremultiplied(),
  289. null);
  290. bi = bufferedImageOp.filter(bi, null);
  291. WritableRaster r = bi.getRaster();
  292. ColorModel cm = bi.getColorModel();
  293. int w = r.getWidth();
  294. int h = r.getHeight();
  295. consumer.setDimensions(w, h);
  296. consumer.setColorModel(cm);
  297. if (cm instanceof DirectColorModel) {
  298. DataBufferInt db = (DataBufferInt) r.getDataBuffer();
  299. consumer.setPixels(0, 0, w, h,
  300. cm, db.getData(), 0, w);
  301. }
  302. else if (cm instanceof IndexColorModel) {
  303. DataBufferByte db = (DataBufferByte) r.getDataBuffer();
  304. consumer.setPixels(0, 0, w, h,
  305. cm, db.getData(), 0, w);
  306. }
  307. else {
  308. throw new InternalError("Unknown color model "+cm);
  309. }
  310. break;
  311. }
  312. consumer.imageComplete(status);
  313. }
  314. private final WritableRaster createDCMraster() {
  315. WritableRaster wr;
  316. DirectColorModel dcm = (DirectColorModel) model;
  317. boolean hasAlpha = model.hasAlpha();
  318. int[] bandMasks = new int[3+(hasAlpha ? 1 : 0)];
  319. bandMasks[0] = dcm.getRedMask();
  320. bandMasks[1] = dcm.getGreenMask();
  321. bandMasks[2] = dcm.getBlueMask();
  322. if (hasAlpha) {
  323. bandMasks[3] = dcm.getAlphaMask();
  324. }
  325. DataBufferInt db = new DataBufferInt(intPixels, width*height);
  326. wr = Raster.createPackedRaster(db, width, height, width,
  327. bandMasks, null);
  328. return wr;
  329. }
  330. }