1:
37:
38:
39: package ;
40:
41: import ;
42: import ;
43: import ;
44: import ;
45:
46: import ;
47: import ;
48: import ;
49: import ;
50: import ;
51: import ;
52: import ;
53: import ;
54: import ;
55: import ;
56:
57:
67: public class BufferedImage extends Image
68: implements WritableRenderedImage, Transparency
69: {
70: public static final int TYPE_CUSTOM = 0,
71: TYPE_INT_RGB = 1,
72: TYPE_INT_ARGB = 2,
73: TYPE_INT_ARGB_PRE = 3,
74: TYPE_INT_BGR = 4,
75: TYPE_3BYTE_BGR = 5,
76: TYPE_4BYTE_ABGR = 6,
77: TYPE_4BYTE_ABGR_PRE = 7,
78: TYPE_USHORT_565_RGB = 8,
79: TYPE_USHORT_555_RGB = 9,
80: TYPE_BYTE_GRAY = 10,
81: TYPE_USHORT_GRAY = 11,
82: TYPE_BYTE_BINARY = 12,
83: TYPE_BYTE_INDEXED = 13;
84:
85:
88: Vector<TileObserver> tileObservers;
89:
90:
93: WritableRaster raster;
94:
95:
98: ColorModel colorModel;
99:
100:
103: Hashtable properties;
104:
105:
108: boolean isPremultiplied;
109:
110:
113: int type;
114:
115:
144: public BufferedImage(int width, int height, int type)
145: {
146: SampleModel sm = null;
147: ColorModel cm = null;
148: boolean premultiplied = (type == BufferedImage.TYPE_INT_ARGB_PRE
149: || type == BufferedImage.TYPE_4BYTE_ABGR_PRE);
150:
151: switch( type )
152: {
153: case BufferedImage.TYPE_INT_RGB:
154: sm = new SinglePixelPackedSampleModel( DataBuffer.TYPE_INT,
155: width, height,
156: new int[]{ 0x00FF0000,
157: 0x0000FF00,
158: 0x000000FF } ) ;
159: cm = new DirectColorModel( 24, 0xff0000, 0xff00, 0xff );
160: break;
161:
162: case BufferedImage.TYPE_3BYTE_BGR:
163: sm = new PixelInterleavedSampleModel( DataBuffer.TYPE_BYTE,
164: width, height,
165: 3, width * 3,
166: new int[]{ 2, 1, 0 } );
167: cm = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB),
168: false, false,
169: BufferedImage.OPAQUE,
170: DataBuffer.TYPE_BYTE);
171: break;
172:
173: case BufferedImage.TYPE_INT_ARGB:
174: case BufferedImage.TYPE_INT_ARGB_PRE:
175: sm = new SinglePixelPackedSampleModel( DataBuffer.TYPE_INT,
176: width, height,
177: new int[]{ 0x00FF0000,
178: 0x0000FF00,
179: 0x000000FF,
180: 0xFF000000 } );
181: if (premultiplied)
182: cm = new DirectColorModel( ColorSpace.getInstance(ColorSpace.CS_sRGB),
183: 32, 0xff0000, 0xff00, 0xff, 0xff000000,
184: true,
185: Buffers.smallestAppropriateTransferType(32));
186: else
187: cm = new DirectColorModel( 32, 0xff0000, 0xff00, 0xff, 0xff000000 );
188:
189: break;
190:
191: case BufferedImage.TYPE_4BYTE_ABGR:
192: case BufferedImage.TYPE_4BYTE_ABGR_PRE:
193: sm = new PixelInterleavedSampleModel(DataBuffer.TYPE_BYTE,
194: width, height,
195: 4, 4*width,
196: new int[]{3, 2, 1, 0});
197: cm = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB),
198: true, premultiplied,
199: BufferedImage.TRANSLUCENT,
200: DataBuffer.TYPE_BYTE);
201: break;
202:
203: case BufferedImage.TYPE_INT_BGR:
204: sm = new SinglePixelPackedSampleModel( DataBuffer.TYPE_INT,
205: width, height,
206: new int[]{ 0x000000FF,
207: 0x0000FF00,
208: 0x00FF0000 } ) ;
209: cm = new DirectColorModel( 24, 0xff, 0xff00, 0xff0000 );
210: break;
211:
212: case BufferedImage.TYPE_USHORT_565_RGB:
213: sm = new SinglePixelPackedSampleModel( DataBuffer.TYPE_USHORT,
214: width, height,
215: new int[]{ 0xF800,
216: 0x7E0,
217: 0x1F } ) ;
218: cm = new DirectColorModel( 16, 0xF800, 0x7E0, 0x1F );
219: break;
220:
221: case BufferedImage.TYPE_USHORT_555_RGB:
222: sm = new SinglePixelPackedSampleModel( DataBuffer.TYPE_USHORT,
223: width, height,
224: new int[]{ 0x7C00,
225: 0x3E0,
226: 0x1F } ) ;
227: cm = new DirectColorModel( 15, 0x7C00, 0x3E0, 0x1F );
228: break;
229:
230: case BufferedImage.TYPE_BYTE_INDEXED:
231: cm = createDefaultIndexedColorModel( false );
232:
233: case BufferedImage.TYPE_BYTE_GRAY:
234: sm = new PixelInterleavedSampleModel( DataBuffer.TYPE_BYTE,
235: width, height,
236: 1, width, new int[]{ 0 } );
237: break;
238:
239: case BufferedImage.TYPE_USHORT_GRAY:
240: sm = new PixelInterleavedSampleModel( DataBuffer.TYPE_USHORT,
241: width, height,
242: 1, width, new int[]{ 0 } );
243: break;
244:
245: case BufferedImage.TYPE_BYTE_BINARY:
246: cm = createDefaultIndexedColorModel( true );
247: sm = new MultiPixelPackedSampleModel(DataBuffer.TYPE_BYTE,
248: width, height, 1);
249: break;
250:
251: default:
252: sm = null;
253: }
254:
255: if( sm == null )
256: throw new IllegalArgumentException("Unknown predefined image type.");
257:
258: if( cm == null )
259: {
260: int buftype;
261: int[] bits = new int[1];
262: if( type == BufferedImage.TYPE_BYTE_GRAY )
263: {
264: buftype = DataBuffer.TYPE_BYTE;
265: bits[0] = 8;
266: }
267: else
268: {
269: buftype = DataBuffer.TYPE_USHORT;
270: bits[0] = 16;
271: }
272: ColorSpace graySpace = ColorSpace.getInstance( ColorSpace.CS_GRAY );
273:
274: cm = new ComponentColorModel( graySpace, bits, false, false,
275: Transparency.OPAQUE, buftype );
276: }
277:
278: WritableRaster rst = null;
279:
280:
281: GraphicsEnvironment env = GraphicsEnvironment.getLocalGraphicsEnvironment();
282: if (env instanceof ClasspathGraphicsEnvironment)
283: rst = ((ClasspathGraphicsEnvironment)env).createRaster(cm, sm);
284:
285:
286: if (rst == null)
287: rst = Raster.createWritableRaster(sm, new Point( 0, 0 ) );
288:
289: init(cm, rst, premultiplied,
290: null,
291: type );
292: }
293:
294: public BufferedImage(int w, int h, int type, IndexColorModel indexcolormodel)
295: {
296: if ((type != TYPE_BYTE_BINARY) && (type != TYPE_BYTE_INDEXED))
297: throw new IllegalArgumentException("Type must be TYPE_BYTE_BINARY or TYPE_BYTE_INDEXED");
298: if( indexcolormodel.getMapSize() > 16 && type == TYPE_BYTE_BINARY )
299: throw new IllegalArgumentException("Type TYPE_BYTE_BINARY cannot have a larger than 16-color palette.");
300: if( indexcolormodel.getMapSize() > 256 )
301: throw new IllegalArgumentException("Byte type cannot have a larger than 256-color palette.");
302:
303: init( indexcolormodel,
304: indexcolormodel.createCompatibleWritableRaster(w, h),
305: indexcolormodel.isAlphaPremultiplied(),
306: null,
307: type );
308: }
309:
310: public BufferedImage(ColorModel colormodel, WritableRaster writableraster,
311: boolean premultiplied, Hashtable<?,?> properties)
312: {
313: init(colormodel, writableraster, premultiplied, properties, TYPE_CUSTOM);
314: }
315:
316:
317: private void init(ColorModel cm, WritableRaster writableraster,
318: boolean premultiplied, Hashtable properties, int type)
319: {
320: raster = writableraster;
321: colorModel = cm;
322: this.properties = properties;
323: isPremultiplied = premultiplied;
324: this.type = type;
325: }
326:
327:
334: private IndexColorModel createDefaultIndexedColorModel( boolean binary )
335: {
336: if( binary )
337: {
338: byte[] t = new byte[]{ 0, (byte)255 };
339: return new IndexColorModel( 1, 2, t, t, t );
340: }
341:
342: byte[] r = new byte[256];
343: byte[] g = new byte[256];
344: byte[] b = new byte[256];
345:
346: int index = 0;
347: for( int i = 0; i < 6; i++ )
348: for( int j = 0; j < 6; j++ )
349: for( int k = 0; k < 6; k++ )
350: {
351: r[ index ] = (byte)(i * 51);
352: g[ index ] = (byte)(j * 51);
353: b[ index ] = (byte)(k * 51);
354: index++;
355: }
356:
357: while( index < 256 )
358: {
359: r[ index ] = g[ index ] = b[ index ] =
360: (byte)(18 + (index - 216) * 6);
361: index++;
362: }
363:
364: return new IndexColorModel( 8, 256, r, g, b );
365: }
366:
367: public void coerceData(boolean premultiplied)
368: {
369: colorModel = colorModel.coerceData(raster, premultiplied);
370: isPremultiplied = premultiplied;
371: }
372:
373: public WritableRaster copyData(WritableRaster dest)
374: {
375: if (dest == null)
376: dest = raster.createCompatibleWritableRaster(getMinX(), getMinY(),
377: getWidth(),getHeight());
378:
379: int x = dest.getMinX();
380: int y = dest.getMinY();
381: int w = dest.getWidth();
382: int h = dest.getHeight();
383:
384:
385: WritableRaster src =
386: raster.createWritableChild(x, y, w, h, x, y,
387: null);
388:
389: if (src.getSampleModel () instanceof ComponentSampleModel
390: && dest.getSampleModel () instanceof ComponentSampleModel)
391:
392: ComponentDataBlitOp.INSTANCE.filter(src, dest);
393:
394: else
395: {
396:
397: int samples[] = src.getPixels (x, y, w, h, (int [])null);
398: dest.setPixels (x, y, w, h, samples);
399: }
400: return dest;
401: }
402:
403: public Graphics2D createGraphics()
404: {
405: GraphicsEnvironment env;
406: env = GraphicsEnvironment.getLocalGraphicsEnvironment ();
407: return env.createGraphics (this);
408: }
409:
410: public void flush()
411: {
412: }
413:
414: public WritableRaster getAlphaRaster()
415: {
416: return colorModel.getAlphaRaster(raster);
417: }
418:
419: public ColorModel getColorModel()
420: {
421: return colorModel;
422: }
423:
424: public Raster getData()
425: {
426: return copyData(null);
427:
429: }
430:
431: public Raster getData(Rectangle rectangle)
432: {
433: WritableRaster dest =
434: raster.createCompatibleWritableRaster(rectangle);
435: return copyData(dest);
436: }
437:
438: public Graphics getGraphics()
439: {
440: return createGraphics();
441: }
442:
443: public int getHeight()
444: {
445: return raster.getHeight();
446: }
447:
448: public int getHeight(ImageObserver imageobserver)
449: {
450: return getHeight();
451: }
452:
453: public int getMinTileX()
454: {
455: return 0;
456: }
457:
458: public int getMinTileY()
459: {
460: return 0;
461: }
462:
463: public int getMinX()
464: {
465: return 0;
466: }
467:
468: public int getMinY()
469: {
470: return 0;
471: }
472:
473: public int getNumXTiles()
474: {
475: return 1;
476: }
477:
478: public int getNumYTiles()
479: {
480: return 1;
481: }
482:
483:
493: public Object getProperty(String string)
494: {
495: if (string == null)
496: throw new NullPointerException("The property name cannot be null.");
497: Object result = Image.UndefinedProperty;
498: if (properties != null)
499: {
500: Object v = properties.get(string);
501: if (v != null)
502: result = v;
503: }
504: return result;
505: }
506:
507: public Object getProperty(String string, ImageObserver imageobserver)
508: {
509: return getProperty(string);
510: }
511:
512:
517: public String[] getPropertyNames()
518: {
519:
520:
521: return null;
522: }
523:
524: public int getRGB(int x, int y)
525: {
526: Object rgbElem = raster.getDataElements(x, y, null);
527: return colorModel.getRGB(rgbElem);
528: }
529:
530: public int[] getRGB(int startX, int startY, int w, int h, int[] rgbArray,
531: int offset, int scanlineStride)
532: {
533: if (rgbArray == null)
534: {
535:
542: int size = (h-1)*scanlineStride + w;
543: rgbArray = new int[size];
544: }
545:
546: int endX = startX + w;
547: int endY = startY + h;
548:
549:
555:
556: Object rgbElem = null;
557: for (int y=startY; y<endY; y++)
558: {
559: int xoffset = offset;
560: for (int x=startX; x<endX; x++)
561: {
562: int rgb;
563: rgbElem = raster.getDataElements(x, y, rgbElem);
564: rgb = colorModel.getRGB(rgbElem);
565: rgbArray[xoffset++] = rgb;
566: }
567: offset += scanlineStride;
568: }
569: return rgbArray;
570: }
571:
572: public WritableRaster getRaster()
573: {
574: return raster;
575: }
576:
577: public SampleModel getSampleModel()
578: {
579: return raster.getSampleModel();
580: }
581:
582: public ImageProducer getSource()
583: {
584: return new ImageProducer()
585: {
586: Vector<ImageConsumer> consumers = new Vector<ImageConsumer>();
587:
588: public void addConsumer(ImageConsumer ic)
589: {
590: if(!consumers.contains(ic))
591: consumers.add(ic);
592: }
593:
594: public boolean isConsumer(ImageConsumer ic)
595: {
596: return consumers.contains(ic);
597: }
598:
599: public void removeConsumer(ImageConsumer ic)
600: {
601: consumers.remove(ic);
602: }
603:
604: public void startProduction(ImageConsumer ic)
605: {
606: int x = 0;
607: int y = 0;
608: int width = getWidth();
609: int height = getHeight();
610: int stride = width;
611: int offset = 0;
612: int[] pixels = getRGB(x, y,
613: width, height,
614: (int[])null, offset, stride);
615:
616:
617: ColorModel model = new DirectColorModel(32, 0xff0000, 0xff00, 0xff,
618: 0xff000000);
619:
620: consumers.add(ic);
621:
622: for(int i = 0; i < consumers.size(); i++)
623: {
624: ImageConsumer c = consumers.elementAt(i);
625: c.setHints(ImageConsumer.SINGLEPASS);
626: c.setDimensions(getWidth(), getHeight());
627: c.setPixels(x, y, width, height, model, pixels, offset, stride);
628: c.imageComplete(ImageConsumer.STATICIMAGEDONE);
629: }
630: }
631:
632: public void requestTopDownLeftRightResend(ImageConsumer ic)
633: {
634: startProduction(ic);
635: }
636:
637: };
638: }
639:
640: public Vector<RenderedImage> getSources()
641: {
642: return null;
643: }
644:
645: public BufferedImage getSubimage(int x, int y, int w, int h)
646: {
647: WritableRaster subRaster =
648: getRaster().createWritableChild(x, y, w, h, 0, 0, null);
649:
650: return new BufferedImage(getColorModel(), subRaster, isPremultiplied,
651: properties);
652: }
653:
654: public Raster getTile(int tileX, int tileY)
655: {
656: return getWritableTile(tileX, tileY);
657: }
658:
659: public int getTileGridXOffset()
660: {
661: return 0;
662: }
663:
664: public int getTileGridYOffset()
665: {
666: return 0;
667: }
668:
669: public int getTileHeight()
670: {
671: return getHeight();
672: }
673:
674: public int getTileWidth()
675: {
676: return getWidth();
677: }
678:
679: public int getType()
680: {
681: return type;
682: }
683:
684: public int getWidth()
685: {
686: return raster.getWidth();
687: }
688:
689: public int getWidth(ImageObserver imageobserver)
690: {
691: return getWidth();
692: }
693:
694: public WritableRaster getWritableTile(int tileX, int tileY)
695: {
696: isTileWritable(tileX, tileY);
697: return raster;
698: }
699:
700: private static final Point[] tileIndices = { new Point() };
701:
702: public Point[] getWritableTileIndices()
703: {
704: return tileIndices;
705: }
706:
707: public boolean hasTileWriters()
708: {
709: return true;
710: }
711:
712: public boolean isAlphaPremultiplied()
713: {
714: return isPremultiplied;
715: }
716:
717: public boolean isTileWritable(int tileX, int tileY)
718: {
719: if ((tileX != 0) || (tileY != 0))
720: throw new ArrayIndexOutOfBoundsException("only tile is (0,0)");
721: return true;
722: }
723:
724: public void releaseWritableTile(int tileX, int tileY)
725: {
726: isTileWritable(tileX, tileY);
727: }
728:
729:
730:
731: public void setData(Raster src)
732: {
733: int x = src.getMinX();
734: int y = src.getMinY();
735: int w = src.getWidth();
736: int h = src.getHeight();
737:
738:
739: WritableRaster dest =
740: raster.createWritableChild(x, y, w, h, x, y, null);
741:
742: if (src.getSampleModel () instanceof ComponentSampleModel
743: && dest.getSampleModel () instanceof ComponentSampleModel)
744:
745:
746: ComponentDataBlitOp.INSTANCE.filter(src, dest);
747: else
748: {
749:
750: int samples[] = src.getPixels (x, y, w, h, (int [])null);
751: dest.setPixels (x, y, w, h, samples);
752: }
753: }
754:
755: public void setRGB(int x, int y, int argb)
756: {
757: Object rgbElem = colorModel.getDataElements(argb, null);
758: raster.setDataElements(x, y, rgbElem);
759: }
760:
761: public void setRGB(int startX, int startY, int w, int h,
762: int[] argbArray, int offset, int scanlineStride)
763: {
764: int endX = startX + w;
765: int endY = startY + h;
766:
767: Object rgbElem = null;
768: for (int y=startY; y<endY; y++)
769: {
770: int xoffset = offset;
771: for (int x=startX; x<endX; x++)
772: {
773: int argb = argbArray[xoffset++];
774: rgbElem = colorModel.getDataElements(argb, rgbElem);
775: raster.setDataElements(x, y, rgbElem);
776: }
777: offset += scanlineStride;
778: }
779: }
780:
781: public String toString()
782: {
783: StringBuffer buf;
784:
785: buf = new StringBuffer( 120);
786: buf.append("BufferedImage@");
787: buf.append(Integer.toHexString(hashCode()));
788: buf.append(": type=");
789: buf.append(type);
790: buf.append(' ');
791: buf.append(colorModel);
792: buf.append(' ');
793: buf.append(raster);
794:
795: return buf.toString();
796: }
797:
798:
799:
805: public void addTileObserver (TileObserver to)
806: {
807: if (tileObservers == null)
808: tileObservers = new Vector<TileObserver>();
809:
810: tileObservers.add (to);
811: }
812:
813:
820: public void removeTileObserver (TileObserver to)
821: {
822: if (tileObservers == null)
823: return;
824:
825: tileObservers.remove (to);
826: }
827:
828:
835: public int getTransparency()
836: {
837: return colorModel.getTransparency();
838: }
839: }