1:
37:
38:
39: package ;
40:
41: import ;
42:
43: import ;
44: import ;
45: import ;
46: import ;
47: import ;
48: import ;
49: import ;
50: import ;
51: import ;
52: import ;
53: import ;
54: import ;
55:
56:
66: public class BufferedImage extends Image
67: implements WritableRenderedImage
68: {
69: public static final int TYPE_CUSTOM = 0,
70: TYPE_INT_RGB = 1,
71: TYPE_INT_ARGB = 2,
72: TYPE_INT_ARGB_PRE = 3,
73: TYPE_INT_BGR = 4,
74: TYPE_3BYTE_BGR = 5,
75: TYPE_4BYTE_ABGR = 6,
76: TYPE_4BYTE_ABGR_PRE = 7,
77: TYPE_USHORT_565_RGB = 8,
78: TYPE_USHORT_555_RGB = 9,
79: TYPE_BYTE_GRAY = 10,
80: TYPE_USHORT_GRAY = 11,
81: TYPE_BYTE_BINARY = 12,
82: TYPE_BYTE_INDEXED = 13;
83:
84: static final int[] bits3 = { 8, 8, 8 };
85: static final int[] bits4 = { 8, 8, 8 };
86: static final int[] bits1byte = { 8 };
87: static final int[] bits1ushort = { 16 };
88:
89: static final int[] masks_int = { 0x00ff0000,
90: 0x0000ff00,
91: 0x000000ff,
92: DataBuffer.TYPE_INT };
93: static final int[] masks_565 = { 0xf800,
94: 0x07e0,
95: 0x001f,
96: DataBuffer.TYPE_USHORT};
97: static final int[] masks_555 = { 0x7c00,
98: 0x03e0,
99: 0x001f,
100: DataBuffer.TYPE_USHORT};
101:
102: Vector observers;
103:
104: public BufferedImage(int w, int h, int type)
105: {
106: ColorModel cm = null;
107:
108: boolean alpha = false;
109: boolean premultiplied = false;
110: switch (type)
111: {
112: case TYPE_4BYTE_ABGR_PRE:
113: case TYPE_INT_ARGB_PRE:
114: premultiplied = true;
115:
116: case TYPE_INT_ARGB:
117: case TYPE_4BYTE_ABGR:
118: alpha = true;
119: }
120:
121: ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB);
122: switch (type)
123: {
124: case TYPE_INT_RGB:
125: case TYPE_INT_ARGB:
126: case TYPE_INT_ARGB_PRE:
127: case TYPE_USHORT_565_RGB:
128: case TYPE_USHORT_555_RGB:
129: int[] masks = null;
130: switch (type)
131: {
132: case TYPE_INT_RGB:
133: case TYPE_INT_ARGB:
134: case TYPE_INT_ARGB_PRE:
135: masks = masks_int;
136: break;
137: case TYPE_USHORT_565_RGB:
138: masks = masks_565;
139: break;
140: case TYPE_USHORT_555_RGB:
141: masks = masks_555;
142: break;
143: }
144:
145: cm = new DirectColorModel(cs,
146: 32,
147: masks[0],
148: masks[1],
149: masks[2],
150: alpha ? 0xff000000 : 0,
151: premultiplied,
152: masks[3]
153: );
154: break;
155:
156: case TYPE_INT_BGR:
157: String msg =
158: "FIXME: Programmer is confused. Why (and how) does a " +
159: "TYPE_INT_BGR image use ComponentColorModel to store " +
160: "8-bit values? Is data type TYPE_INT or TYPE_BYTE. What " +
161: "is the difference between TYPE_INT_BGR and TYPE_3BYTE_BGR?";
162: throw new UnsupportedOperationException(msg);
163:
164: case TYPE_3BYTE_BGR:
165: case TYPE_4BYTE_ABGR:
166: case TYPE_4BYTE_ABGR_PRE:
167: case TYPE_BYTE_GRAY:
168: case TYPE_USHORT_GRAY:
169: int[] bits = null;
170: int dataType = DataBuffer.TYPE_BYTE;
171: switch (type) {
172: case TYPE_3BYTE_BGR:
173: bits = bits3;
174: break;
175: case TYPE_4BYTE_ABGR:
176: case TYPE_4BYTE_ABGR_PRE:
177: bits = bits4;
178: break;
179: case TYPE_BYTE_GRAY:
180: bits = bits1byte;
181: break;
182: case TYPE_USHORT_GRAY:
183: bits = bits1ushort;
184: dataType = DataBuffer.TYPE_USHORT;
185: break;
186: }
187: cm = new ComponentColorModel(cs, bits, alpha, premultiplied,
188: alpha ?
189: Transparency.TRANSLUCENT:
190: Transparency.OPAQUE,
191: dataType);
192: break;
193: case TYPE_BYTE_BINARY:
194: byte[] vals = { 0, (byte) 0xff };
195: cm = new IndexColorModel(8, 2, vals, vals, vals);
196: break;
197: case TYPE_BYTE_INDEXED:
198: String msg2 = "type not implemented yet";
199: throw new UnsupportedOperationException(msg2);
200:
201: }
202:
203: init(cm,
204: cm.createCompatibleWritableRaster(w, h),
205: premultiplied,
206: null,
207: type
208: );
209: }
210:
211: public BufferedImage(int w, int h, int type,
212: IndexColorModel indexcolormodel)
213: {
214: if ((type != TYPE_BYTE_BINARY) && (type != TYPE_BYTE_INDEXED))
215: throw new IllegalArgumentException("type must be binary or indexed");
216:
217: init(indexcolormodel,
218: indexcolormodel.createCompatibleWritableRaster(w, h),
219: false,
220: null,
221: type);
222: }
223:
224: public BufferedImage(ColorModel colormodel,
225: WritableRaster writableraster,
226: boolean premultiplied,
227: Hashtable properties)
228: {
229: init(colormodel, writableraster, premultiplied, properties,
230: TYPE_CUSTOM);
231:
232: }
233:
234: WritableRaster raster;
235: ColorModel colorModel;
236: Hashtable properties;
237: boolean isPremultiplied;
238: int type;
239:
240: private void init(ColorModel cm,
241: WritableRaster writableraster,
242: boolean premultiplied,
243: Hashtable properties,
244: int type)
245: {
246: raster = writableraster;
247: colorModel = cm;
248: this.properties = properties;
249: isPremultiplied = premultiplied;
250: this.type = type;
251: }
252:
253:
254:
255: public void coerceData(boolean premultiplied)
256: {
257: colorModel = colorModel.coerceData(raster, premultiplied);
258: }
259:
260: public WritableRaster copyData(WritableRaster dest)
261: {
262: if (dest == null)
263: dest = raster.createCompatibleWritableRaster(getMinX(), getMinY(),
264: getWidth(),getHeight());
265:
266: int x = dest.getMinX();
267: int y = dest.getMinY();
268: int w = dest.getWidth();
269: int h = dest.getHeight();
270:
271:
272: WritableRaster src =
273: raster.createWritableChild(x, y, w, h, x, y,
274: null
275: );
276: if (src.getSampleModel () instanceof ComponentSampleModel
277: && dest.getSampleModel () instanceof ComponentSampleModel)
278:
279: ComponentDataBlitOp.INSTANCE.filter(src, dest);
280: else
281: {
282:
283: int samples[] = src.getPixels (x, y, w, h, (int [])null);
284: dest.setPixels (x, y, w, h, samples);
285: }
286: return dest;
287: }
288:
289: public Graphics2D createGraphics()
290: {
291: GraphicsEnvironment env;
292: env = GraphicsEnvironment.getLocalGraphicsEnvironment ();
293: return env.createGraphics (this);
294: }
295:
296: public void flush() {
297: }
298:
299: public WritableRaster getAlphaRaster()
300: {
301: return colorModel.getAlphaRaster(raster);
302: }
303:
304: public ColorModel getColorModel()
305: {
306: return colorModel;
307: }
308:
309: public Raster getData()
310: {
311: return copyData(null);
312:
314: }
315:
316: public Raster getData(Rectangle rectangle)
317: {
318: WritableRaster dest =
319: raster.createCompatibleWritableRaster(rectangle);
320: return copyData(dest);
321: }
322:
323: public Graphics getGraphics()
324: {
325: return createGraphics();
326: }
327:
328: public int getHeight()
329: {
330: return raster.getHeight();
331: }
332:
333: public int getHeight(ImageObserver imageobserver)
334: {
335: return getHeight();
336: }
337:
338: public int getMinTileX()
339: {
340: return 0;
341: }
342:
343: public int getMinTileY()
344: {
345: return 0;
346: }
347:
348: public int getMinX()
349: {
350: return 0;
351: }
352:
353: public int getMinY()
354: {
355: return 0;
356: }
357:
358: public int getNumXTiles()
359: {
360: return 1;
361: }
362:
363: public int getNumYTiles()
364: {
365: return 1;
366: }
367:
368: public Object getProperty(String string)
369: {
370: if (properties == null)
371: return null;
372: return properties.get(string);
373: }
374:
375: public Object getProperty(String string, ImageObserver imageobserver)
376: {
377: return getProperty(string);
378: }
379:
380:
381: public String[] getPropertyNames()
382: {
383:
384: return null;
385: }
386:
387: public int getRGB(int x, int y)
388: {
389: Object rgbElem = raster.getDataElements(x, y,
390: null
391: );
392: return colorModel.getRGB(rgbElem);
393: }
394:
395: public int[] getRGB(int startX, int startY, int w, int h,
396: int[] rgbArray,
397: int offset, int scanlineStride)
398: {
399: if (rgbArray == null)
400: {
401:
407: int size = (h-1)*scanlineStride + w;
408: rgbArray = new int[size];
409: }
410:
411: int endX = startX + w;
412: int endY = startY + h;
413:
414:
420:
421: Object rgbElem = null;
422: for (int y=startY; y<endY; y++)
423: {
424: int xoffset = offset;
425: for (int x=startX; x<endX; x++)
426: {
427: int rgb;
428: rgbElem = raster.getDataElements(x, y, rgbElem);
429: rgb = colorModel.getRGB(rgbElem);
430: rgbArray[xoffset++] = rgb;
431: }
432: offset += scanlineStride;
433: }
434: return rgbArray;
435: }
436:
437: public WritableRaster getRaster()
438: {
439: return raster;
440: }
441:
442: public SampleModel getSampleModel()
443: {
444: return raster.getSampleModel();
445: }
446:
447: public ImageProducer getSource()
448: {
449: return new ImageProducer() {
450:
451: Vector consumers = new Vector();
452:
453: public void addConsumer(ImageConsumer ic)
454: {
455: if(!consumers.contains(ic))
456: consumers.add(ic);
457: }
458:
459: public boolean isConsumer(ImageConsumer ic)
460: {
461: return consumers.contains(ic);
462: }
463:
464: public void removeConsumer(ImageConsumer ic)
465: {
466: consumers.remove(ic);
467: }
468:
469: public void startProduction(ImageConsumer ic)
470: {
471: int x = 0;
472: int y = 0;
473: int width = getWidth();
474: int height = getHeight();
475: int stride = width;
476: int offset = 0;
477: int[] pixels = getRGB(x, y,
478: width, height,
479: (int[])null, offset, stride);
480: ColorModel model = getColorModel();
481:
482: consumers.add(ic);
483:
484: for(int i=0;i<consumers.size();i++)
485: {
486: ImageConsumer c = (ImageConsumer) consumers.elementAt(i);
487: c.setHints(ImageConsumer.SINGLEPASS);
488: c.setDimensions(getWidth(), getHeight());
489: c.setPixels(x, y, width, height, model, pixels, offset, stride);
490: c.imageComplete(ImageConsumer.STATICIMAGEDONE);
491: }
492: }
493:
494: public void requestTopDownLeftRightResend(ImageConsumer ic)
495: {
496: startProduction(ic);
497: }
498:
499: };
500: }
501:
502: public Vector getSources()
503: {
504: return null;
505: }
506:
507: public BufferedImage getSubimage(int x, int y, int w, int h)
508: {
509: WritableRaster subRaster =
510: getRaster().createWritableChild(x, y, w, h, 0, 0, null);
511:
512: return new BufferedImage(getColorModel(),
513: subRaster,
514: isPremultiplied,
515: properties);
516: }
517:
518: public Raster getTile(int tileX, int tileY)
519: {
520: return getWritableTile(tileX, tileY);
521: }
522:
523: public int getTileGridXOffset()
524: {
525: return 0;
526: }
527:
528: public int getTileGridYOffset()
529: {
530: return 0;
531: }
532:
533: public int getTileHeight()
534: {
535: return getHeight();
536: }
537:
538: public int getTileWidth()
539: {
540: return getWidth();
541: }
542:
543: public int getType()
544: {
545: return type;
546: }
547:
548: public int getWidth()
549: {
550: return raster.getWidth();
551: }
552:
553: public int getWidth(ImageObserver imageobserver)
554: {
555: return getWidth();
556: }
557:
558: public WritableRaster getWritableTile(int tileX, int tileY)
559: {
560: isTileWritable(tileX, tileY);
561: return raster;
562: }
563:
564: private static final Point[] tileIndices = { new Point() };
565:
566: public Point[] getWritableTileIndices()
567: {
568: return tileIndices;
569: }
570:
571: public boolean hasTileWriters()
572: {
573: return true;
574: }
575:
576: public boolean isAlphaPremultiplied()
577: {
578: return isPremultiplied;
579: }
580:
581: public boolean isTileWritable(int tileX, int tileY)
582: {
583: if ((tileX != 0) || (tileY != 0))
584: throw new ArrayIndexOutOfBoundsException("only tile is (0,0)");
585: return true;
586: }
587:
588: public void releaseWritableTile(int tileX, int tileY)
589: {
590: isTileWritable(tileX, tileY);
591: }
592:
593:
594:
595: public void setData(Raster src)
596: {
597: int x = src.getMinX();
598: int y = src.getMinY();
599: int w = src.getWidth();
600: int h = src.getHeight();
601:
602:
603: WritableRaster dest =
604: raster.createWritableChild(x, y, w, h, x, y,
605: null
606: );
607:
608: if (src.getSampleModel () instanceof ComponentSampleModel
609: && dest.getSampleModel () instanceof ComponentSampleModel)
610:
611:
612: ComponentDataBlitOp.INSTANCE.filter(src, dest);
613: else
614: {
615:
616: int samples[] = src.getPixels (x, y, w, h, (int [])null);
617: dest.setPixels (x, y, w, h, samples);
618: }
619: }
620:
621: public void setRGB(int x, int y, int argb)
622: {
623: Object rgbElem = colorModel.getDataElements(argb, null);
624: raster.setDataElements(x, y, rgbElem);
625: }
626:
627: public void setRGB(int startX, int startY, int w, int h,
628: int[] argbArray, int offset, int scanlineStride)
629: {
630: int endX = startX + w;
631: int endY = startY + h;
632:
633: Object rgbElem = null;
634: for (int y=startY; y<endY; y++)
635: {
636: int xoffset = offset;
637: for (int x=startX; x<endX; x++)
638: {
639: int argb = argbArray[xoffset++];
640: rgbElem = colorModel.getDataElements(argb, rgbElem);
641: raster.setDataElements(x, y, rgbElem);
642: }
643: offset += scanlineStride;
644: }
645: }
646:
647: public String toString()
648: {
649: StringBuffer buf;
650:
651: buf = new StringBuffer( 120);
652: buf.append("BufferedImage@");
653: buf.append(Integer.toHexString(hashCode()));
654: buf.append(": type=");
655: buf.append(type);
656: buf.append(' ');
657: buf.append(colorModel);
658: buf.append(' ');
659: buf.append(raster);
660:
661: return buf.toString();
662: }
663:
664:
665:
671: public void addTileObserver (TileObserver to)
672: {
673: if (observers == null)
674: observers = new Vector ();
675:
676: observers.add (to);
677: }
678:
679:
686: public void removeTileObserver (TileObserver to)
687: {
688: if (observers == null)
689: return;
690:
691: observers.remove (to);
692: }
693: }