OSDN Git Service

9eba6fcb96c9a9d3a4dcebf30456486db1ceca95
[pf3gnuchains/gcc-fork.git] / libjava / java / awt / image / BufferedImage.java
1 /* Copyright (C) 2000  Free Software Foundation
2
3    This file is part of libgcj.
4
5 This software is copyrighted work licensed under the terms of the
6 Libgcj License.  Please consult the file "LIBGCJ_LICENSE" for
7 details.  */
8
9 package java.awt.image;
10
11 import java.awt.*;
12 import java.awt.color.*;
13 import java.util.*;
14
15 import gnu.gcj.awt.ComponentDataBlitOp;
16
17 /**
18  * A buffered image always starts at coordinates (0, 0).
19  *
20  * The buffered image is not subdivided into multiple tiles. Instead,
21  * the image consists of one large tile (0,0) with the width and
22  * height of the image. This tile is always considered to be checked
23  * out.
24  * 
25  * @author Rolf W. Rasmussen <rolfwr@ii.uib.no>
26  */
27 public class BufferedImage extends java.awt.Image
28     //implements java.awt.image.WritableRenderedImage
29 {
30   public static final int TYPE_CUSTOM         =  0,
31                           TYPE_INT_RGB        =  1,
32                           TYPE_INT_ARGB       =  2,
33                           TYPE_INT_ARGB_PRE   =  3,
34                           TYPE_INT_BGR        =  4,
35                           TYPE_3BYTE_BGR      =  5,
36                           TYPE_4BYTE_ABGR     =  6,
37                           TYPE_4BYTE_ABGR_PRE =  7,
38                           TYPE_USHORT_565_RGB =  8,
39                           TYPE_USHORT_555_RGB =  9,
40                           TYPE_BYTE_GRAY      = 10,
41                           TYPE_USHORT_GRAY    = 11,
42                           TYPE_BYTE_BINARY    = 12,
43                           TYPE_BYTE_INDEXED   = 13;
44   
45   final static int[] bits3 = { 8, 8, 8 };
46   final static int[] bits4 = { 8, 8, 8 };
47   final static int[] bits1byte = { 8 };
48   final static int[] bits1ushort = { 16 };
49   
50   final static int[] masks_int = { 0x00ff0000,
51                                    0x0000ff00,
52                                    0x000000ff,
53                                    DataBuffer.TYPE_INT };
54   final static int[] masks_565 = { 0xf800,
55                                    0x07e0,
56                                    0x001f,
57                                    DataBuffer.TYPE_USHORT};
58   final static int[] masks_555 = { 0x7c00,
59                                    0x03e0,
60                                    0x001f,
61                                    DataBuffer.TYPE_USHORT};
62   
63   public BufferedImage(int w, int h, int type)
64   {
65     ColorModel cm;
66     
67     boolean alpha = false;
68     boolean premultiplied = false;
69     switch (type)
70       {
71       case TYPE_4BYTE_ABGR_PRE:
72       case TYPE_INT_ARGB_PRE:
73         premultiplied = true;
74         // fall through
75       case TYPE_INT_ARGB:
76       case TYPE_4BYTE_ABGR:
77         alpha = true;
78       }
79         
80     ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB);
81     switch (type)
82       {
83       case TYPE_INT_RGB:
84       case TYPE_INT_ARGB:
85       case TYPE_INT_ARGB_PRE:
86       case TYPE_USHORT_565_RGB:
87       case TYPE_USHORT_555_RGB:
88         int[] masks;
89         switch (type)
90           {
91           case TYPE_INT_RGB:
92           case TYPE_INT_ARGB:
93           case TYPE_INT_ARGB_PRE:
94             masks = masks_int;
95             break;
96           case TYPE_USHORT_565_RGB:
97             masks = masks_565;
98             break;
99           case TYPE_USHORT_555_RGB:
100             masks = masks_555;
101             break;
102           }
103         
104         cm = new DirectColorModel(cs,
105                                   32, // 32 bits in an int
106                                   masks[0], // r
107                                   masks[1], // g
108                                   masks[2], // b
109                                   alpha ? 0xff000000 : 0,
110                                   premultiplied,
111                                   masks[3] // data type
112                                   );
113         break;
114         
115       case TYPE_INT_BGR:
116         String msg =
117           "FIXME: Programmer is confused. Why (and how) does a " +
118           "TYPE_INT_BGR image use ComponentColorModel to store " +
119           "8-bit values? Is data type TYPE_INT or TYPE_BYTE. What " +
120           "is the difference between TYPE_INT_BGR and TYPE_3BYTE_BGR?";
121         throw new UnsupportedOperationException(msg);
122         
123       case TYPE_3BYTE_BGR:
124       case TYPE_4BYTE_ABGR:
125       case TYPE_4BYTE_ABGR_PRE:
126       case TYPE_BYTE_GRAY:
127       case TYPE_USHORT_GRAY:
128         int[] bits = null;
129         int dataType = DataBuffer.TYPE_BYTE;
130         switch (type) {
131         case TYPE_3BYTE_BGR:
132           bits = bits3;
133           break;
134         case TYPE_4BYTE_ABGR:
135         case TYPE_4BYTE_ABGR_PRE:
136           bits = bits4;
137           break;
138         case TYPE_BYTE_GRAY:
139           bits = bits1byte;
140           break;
141         case TYPE_USHORT_GRAY:
142           bits = bits1ushort;
143           dataType = DataBuffer.TYPE_USHORT;
144           break;
145         }
146         cm = new ComponentColorModel(cs, bits, alpha, premultiplied,
147                                      alpha ?
148                                      Transparency.TRANSLUCENT:
149                                      Transparency.OPAQUE,
150                                      dataType);
151         break;
152       case TYPE_BYTE_BINARY:
153         byte[] vals = { 0, (byte) 0xff };
154         cm = new IndexColorModel(8, 2, vals, vals, vals);
155         break;
156       case TYPE_BYTE_INDEXED:
157         String msg2 = "type not implemented yet";
158         throw new UnsupportedOperationException(msg2);
159         // FIXME: build color-cube and create color model
160       }
161     
162     init(cm,
163          cm.createCompatibleWritableRaster(w, h),
164          premultiplied,
165          null, // no properties
166          type
167          );
168   }
169
170   public BufferedImage(int w, int h, int type,
171                        IndexColorModel indexcolormodel)
172   {
173     if ((type != TYPE_BYTE_BINARY) && (type != TYPE_BYTE_INDEXED))
174       throw new IllegalArgumentException("type must be binary or indexed");
175
176     init(indexcolormodel,
177          indexcolormodel.createCompatibleWritableRaster(w, h),
178          false, // not premultiplied (guess)
179          null, // no properties
180          type);
181   }
182
183   public BufferedImage(ColorModel colormodel, 
184                        WritableRaster writableraster,
185                        boolean premultiplied,
186                        Hashtable properties)
187   {
188     init(colormodel, writableraster, premultiplied, properties,
189          TYPE_CUSTOM);
190     // TODO: perhaps try to identify type?
191   }
192  
193   WritableRaster raster;
194   ColorModel colorModel;
195   Hashtable properties;
196   boolean isPremultiplied;
197   int type;
198   
199   private void init(ColorModel cm,
200                     WritableRaster writableraster,
201                     boolean premultiplied,
202                     Hashtable properties,
203                     int type)
204   {
205     raster = writableraster;
206     colorModel = cm;
207     this.properties = properties;
208     isPremultiplied = premultiplied;
209     this.type = type;
210   }
211     
212   //public void addTileObserver(TileObserver tileobserver) {}
213   
214   public void coerceData(boolean premultiplied)
215   {
216     colorModel = colorModel.coerceData(raster, premultiplied);
217   }
218
219   public WritableRaster copyData(WritableRaster dest)
220   {
221     if (dest == null)
222       dest = raster.createCompatibleWritableRaster();
223
224     int x = dest.getMinX();
225     int y = dest.getMinY();
226     int w = dest.getWidth();
227     int h = dest.getHeight();
228     
229     // create a src child that has the right bounds...
230     WritableRaster src =
231       raster.createWritableChild(x, y, w, h, x, y,
232                                  null  // same bands
233                                  );
234     
235     // Refer to ComponentDataBlitOp for optimized data blitting:
236     ComponentDataBlitOp.INSTANCE.filter(src, dest);
237     return dest;
238   }
239
240   public Graphics2D createGraphics()
241   {
242     throw new UnsupportedOperationException("not implemented");
243     // will require a lot of effort to implement
244   }
245
246   public void flush() {
247   }
248   
249   public WritableRaster getAlphaRaster()
250   {
251     return colorModel.getAlphaRaster(raster);
252   }
253   
254   public ColorModel getColorModel()
255   {
256     return colorModel;
257   }
258   
259   public Raster getData()
260   {
261     return copyData(null);
262     /* TODO: this might be optimized by returning the same
263        raster (not writable) as long as image data doesn't change. */
264   }
265
266   public Raster getData(Rectangle rectangle)
267   {
268     WritableRaster dest =
269       raster.createCompatibleWritableRaster(rectangle);
270     return copyData(dest);
271   }
272   
273   public Graphics getGraphics()
274   {
275     return createGraphics();
276   }
277
278   public int getHeight()
279   {
280     return raster.getHeight();
281   }
282   
283   public int getHeight(ImageObserver imageobserver)
284   {
285     return getHeight();
286   }
287     
288   public int getMinTileX()
289   {
290     return 0;
291   }
292   
293   public int getMinTileY()
294   {
295     return 0;
296   }
297
298   public int getMinX()
299   {
300     return 0; 
301   }
302
303   public int getMinY() 
304   {
305     return 0;
306   }
307   
308   public int getNumXTiles()
309   {
310     return 1;
311   }
312
313   public int getNumYTiles()
314   {
315         return 1;
316   }
317
318   public Object getProperty(String string)
319   {
320     if (properties == null)
321       return null;
322     return properties.get(string);
323   }
324
325   public Object getProperty(String string, ImageObserver imageobserver)
326   {
327     return getProperty(string);
328   }
329
330   
331   public String[] getPropertyNames()
332   {
333     // FIXME: implement
334     return null;
335   }
336
337   public int getRGB(int x, int y)
338   {
339     Object rgbElem = raster.getDataElements(x, y,
340                                             null // create as needed
341                                             );
342     return colorModel.getRGB(rgbElem);
343   }
344     
345   public int[] getRGB(int startX, int startY, int w, int h,
346                       int[] rgbArray,
347                       int offset, int scanlineStride)
348   {
349     if (rgbArray == null)
350     {
351       /*
352         000000000000000000
353         00000[#######-----   [ = start
354         -----########-----   ] = end
355         -----#######]00000
356         000000000000000000  */
357       int size = (h-1)*scanlineStride + w;
358       rgbArray = new int[size];
359     }
360         
361     int endX = startX + w;
362     int endY = startY + h;
363     
364     /* *TODO*:
365        Opportunity for optimization by examining color models...
366        
367        Perhaps wrap the rgbArray up in a WritableRaster with packed
368        sRGB color model and perform optimized rendering into the
369        array. */
370
371     Object rgbElem = null;
372     for (int y=startY; y<endY; y++)
373       {
374         int xoffset = offset;
375         for (int x=startX; x<endX; x++)
376           {
377             int rgb;
378             rgbElem = raster.getDataElements(x, y, rgbElem);
379             rgb = colorModel.getRGB(rgbElem);
380             rgbArray[xoffset++] = rgb;
381           }
382         offset += scanlineStride;
383       }
384     return rgbArray;
385   }
386
387   public WritableRaster getRaster()
388   {
389     return raster;
390   }
391   
392   public SampleModel getSampleModel()
393   {
394     return raster.getSampleModel();
395   }
396     
397   public ImageProducer getSource()
398   {
399     throw new UnsupportedOperationException("not implemented");
400   }
401   
402   public Vector getSources()
403   {
404     return null;
405   }
406   
407   public BufferedImage getSubimage(int x, int y, int w, int h)
408   {
409     WritableRaster subRaster = 
410       getRaster().createWritableChild(x, y, w, h, 0, 0, null);
411     
412     return new BufferedImage(getColorModel(),
413                              subRaster,
414                              isPremultiplied,
415                              properties);
416   }
417
418   public Raster getTile(int tileX, int tileY)
419   {
420     return getWritableTile(tileX, tileY);
421   }
422     
423   public int getTileGridXOffset()
424   {
425     return 0; // according to javadocs
426   }
427
428   public int getTileGridYOffset()
429   {
430     return 0; // according to javadocs
431   }
432
433   public int getTileHeight()
434   {
435     return getHeight(); // image is one big tile
436   }
437
438   public int getTileWidth()
439   {
440     return getWidth(); // image is one big tile
441   }
442
443   public int getType()
444   {
445     return type;
446   }
447
448   public int getWidth()
449   {
450     return raster.getWidth();
451   }
452
453   public int getWidth(ImageObserver imageobserver)
454   {
455     return getWidth();
456   }
457
458   public WritableRaster getWritableTile(int tileX, int tileY)
459   {
460     isTileWritable(tileX, tileY);  // for exception
461     return raster;
462   }
463
464   private static final Point[] tileIndices = { new Point() };
465     
466   public Point[] getWritableTileIndices()
467   {
468     return tileIndices;
469   }
470
471   public boolean hasTileWriters()
472   {
473     return true;
474   }
475   
476   public boolean isAlphaPremultiplied()
477   {
478     return isPremultiplied;
479   }
480
481   public boolean isTileWritable(int tileX, int tileY)
482   {
483     if ((tileX != 0) || (tileY != 0))
484       throw new ArrayIndexOutOfBoundsException("only tile is (0,0)");
485     return true;
486   }
487
488   public void releaseWritableTile(int tileX, int tileY)
489   {
490     isTileWritable(tileX, tileY);  // for exception
491   }
492
493   //public void removeTileObserver(TileObserver tileobserver) {}
494
495   public void setData(Raster src)
496   {
497     int x = src.getMinX();
498     int y = src.getMinY();
499     int w = src.getWidth();
500     int h = src.getHeight();
501     
502     // create a dest child that has the right bounds...
503     WritableRaster dest =
504       raster.createWritableChild(x, y, w, h, x, y,
505                                  null  // same bands
506                                  );
507     
508     // Refer to ComponentDataBlitOp for optimized data blitting:
509     ComponentDataBlitOp.INSTANCE.filter(src, dest);
510   }
511
512   public void setRGB(int x, int y, int argb)
513   {
514     Object rgbElem = colorModel.getDataElements(argb, null);
515     raster.setDataElements(x, y, rgbElem);
516   }
517   
518   public void setRGB(int startX, int startY, int w, int h,
519                      int[] argbArray, int offset, int scanlineStride)
520   {
521     int endX = startX + w;
522     int endY = startY + h;
523     
524     Object rgbElem = null;
525     for (int y=startY; y<endY; y++)
526       {
527         int xoffset = offset;
528         for (int x=startX; x<endX; x++)
529           {
530             int argb = argbArray[xoffset++];
531             rgbElem = colorModel.getDataElements(argb, rgbElem);
532             raster.setDataElements(x, y, rgbElem);
533           }
534         offset += scanlineStride;    
535       }
536   }
537     
538   public String toString()
539   {
540     // FIXME: implement:
541     return super.toString();
542   }
543 }