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