./
[mono.git] / mcs / class / System.Drawing / System.Drawing / Bitmap.jvm.cs
1 using System;
2 using System.IO;
3 using System.Drawing.Imaging;
4 using System.Runtime.Serialization;
5
6 using io = java.io;
7 using imageio = javax.imageio;
8 using stream = javax.imageio.stream;
9 using spi = javax.imageio.spi;
10 using BufferedImage = java.awt.image.BufferedImage;
11 using JavaImage = java.awt.Image;
12 using awt = java.awt;
13 using image = java.awt.image;
14
15 namespace System.Drawing 
16 {
17         public sealed class Bitmap : Image {
18
19                 #region constructors
20
21                 Bitmap (Bitmap orig):base (orig) {}
22
23                 private Bitmap (SerializationInfo info, StreamingContext context) {
24                         throw new NotImplementedException ();
25                 }
26
27                 public Bitmap (int width, int height, Graphics g) {
28                         throw new NotImplementedException();                    
29                 }
30
31                 public Bitmap (Image orig, Size newSize)
32                         :this (orig, newSize.Width, newSize.Height) {}
33
34                 public Bitmap (Image orig, int width, int height)
35                         :base (CreateScaledImage (orig, width, height), ImageFormat.Bmp) {}
36
37                 public Bitmap (int width, int height) 
38                         :this (width, height, PixelFormat.Format32bppArgb) {}
39
40                 public Bitmap (Image original) 
41                         :this (original, original.Size) {}
42
43                 public Bitmap (Stream stream)
44                         :this (stream, false) {}
45
46                 public Bitmap (string filename) 
47                         :this (filename, false) {}
48
49                 internal Bitmap (java.awt.Image nativeObject, ImageFormat format)
50                         :base (nativeObject, format) {}
51
52                 private Bitmap (java.awt.Image nativeObject, ImageFormat format, PixelFormat pixFormat)
53                         :this (nativeObject, format) {
54                         if (pixFormat != this.PixelFormat)
55                                 throw new NotImplementedException ("Converting PixelFormat is not implemented yet.");
56                 }
57
58                 public Bitmap (int width, int height, PixelFormat format)
59                         :base (
60                                 new java.awt.image.BufferedImage (width, height,
61                                         ToBufferedImageFormat (format)),
62                                 ImageFormat.Bmp)
63                 {
64                         //TBD: why the following 3 lines are necessary?
65 //                      java.awt.Graphics2D graphics2d = NativeObject.createGraphics();
66 //                      graphics2d.drawImage(NativeObject, 0, 0, null);
67 //                      graphics2d.dispose();
68                 }
69
70                 public Bitmap (Stream stream, bool useIcm)
71                         :this (stream, useIcm, null) {}
72
73                 public Bitmap (string filename, bool useIcm)
74                         :this (filename, useIcm, null) {}
75
76                 internal Bitmap (Stream stream, bool useIcm, ImageFormat format) {
77                         //FIXME: useIcm param
78                         //FIXME: use direct ImageInputStream wrapper for NET Stream
79                         io.InputStream jis = vmw.common.IOUtils.ToInputStream (stream);
80             Initialize (new stream.MemoryCacheImageInputStream (jis), format);
81                 }
82
83                 internal Bitmap (string filename, bool useIcm, ImageFormat format) {
84                         //FIXME: useIcm param
85                         java.io.File file = vmw.common.IOUtils.getJavaFile (filename);
86                         if (!file.exists ())
87                                 //TBD: check what exception throws NET
88                                 throw new System.IO.IOException ("File not found: "+filename);
89                         Initialize (new stream.FileImageInputStream (file), format);
90                 }
91
92                 public Bitmap (Type type, string resource) {
93                         using (Stream s = type.Assembly.GetManifestResourceStream (resource)) {
94                                 if (s == null)
95                                         //TBD: check what type is thrown in MS
96                                         throw new Exception("Resource name was not found: `" + resource + "'");
97                                 io.InputStream jis = vmw.common.IOUtils.ToInputStream (s);
98                                 try {
99                                         Initialize (new stream.MemoryCacheImageInputStream (jis), null);
100                                 }
101                                 catch (Exception e) {
102                                         //FIXME: catch and throw right exception
103                                         throw new Exception ("java exception", e);
104                                 }
105                         }
106                 }
107
108                 //FIXME: should go to imageio helpers class
109                 static ImageFormat MimeTypesToImageFormat (string [] mimeTypes)
110                 {
111                         foreach (ImageCodecInfo codec in ImageCodecInfo.Decoders.Values)
112                                 for (int i=0; i<mimeTypes.Length; i++)
113                                         if (codec.MimeType == mimeTypes [i])
114                                                 return new ImageFormat (codec.FormatID);
115                         return null;
116                 }
117
118                 private void Initialize (stream.ImageInputStream input, ImageFormat format) {
119                         java.util.Iterator iter = null;
120                         if (format != null)
121                                 iter = imageio.ImageIO.getImageReadersByMIMEType (
122                                         ImageCodecInfo.ImageFormatToMimeType (format));
123                         else 
124                                 iter = imageio.ImageIO.getImageReaders (input);
125
126                         if (!iter.hasNext ())
127                                 throw new ArgumentException ("Format not found"); //TBD: make same text as MS
128
129                         imageio.ImageReader r = (imageio.ImageReader) iter.next ();
130
131                         r.setInput (input);
132
133                         if (format == null)
134                                 format = MimeTypesToImageFormat (r.getOriginatingProvider ().getMIMETypes ());
135
136                         Initialize (r, format);
137                 }
138
139                 private void Initialize (imageio.ImageReader r, ImageFormat format) {
140                         java.awt.Image [] nativeObjects;
141                         java.awt.Image [] thumbnails = null;
142                         try {
143                                 nativeObjects = new BufferedImage [r.getNumImages (false)];
144                                 for (int i = 0; i < nativeObjects.Length; i++) {
145                                         if (r.hasThumbnails(i)) {
146                                                 if (thumbnails == null)
147                                                         thumbnails = new BufferedImage[nativeObjects.Length];
148
149                                                 thumbnails[i] = r.readThumbnail(i, 0);
150                                         }
151                                         nativeObjects [i] = r.read (i);
152                                 }
153
154                         }
155                         catch (Exception e) {
156                                 //TDB: make exception same as in MS
157                                 throw new ArgumentException ("Error reading", e);
158                         }
159                         base.Initialize (nativeObjects, thumbnails, format, FrameDimension.Page.Guid);
160                 }
161
162 #if INTPTR_SUPPORT
163                 public Bitmap (int width, int height, int stride, PixelFormat format, IntPtr scan0)
164                 {                                               
165                         throw new NotImplementedException();                    
166                 }
167 #endif
168                 #endregion
169
170                 #region InternalSave
171                 protected override void InternalSave (stream.ImageOutputStream output, Guid clsid) {
172                         string mime=ImageCodecInfo.FindEncoder (clsid).MimeType;
173                         imageio.ImageWriter writer = null;;
174                         try {
175                                 writer = (imageio.ImageWriter) imageio.ImageIO.getImageWritersByMIMEType (mime).next ();
176                                 writer.setOutput (output);
177                                 if (NativeObjectsCount == 1)
178                                         writer.write (NativeObject);
179                                 else if (writer.canWriteSequence ())
180                                         SaveSequence (writer);
181                                 else
182                                         throw new NotImplementedException ();
183                         }
184                         catch (Exception e) {
185                                 //FIXME: check dotnet exceptions in save, and throw same types
186                                 throw new Exception ("java threw an exception", e);
187                         }
188                 }
189
190                 void SaveSequence (imageio.ImageWriter writer) {
191                         //FIXME: does not supports metadata and thumbnails for now
192                         writer.prepareWriteSequence (null);
193
194                         for (int i = 0; i < NativeObjectsCount; i++) {
195                                 imageio.IIOImage iio = new imageio.IIOImage ((BufferedImage)this[i], null, null);
196                                 writer.writeToSequence (iio, null);
197                         }
198
199                         writer.endWriteSequence ();
200                 }
201
202                 #endregion
203
204                 #region private statics: ToBufferedImageFormat, CreateScaledImage
205
206                 private static int ToBufferedImageFormat (PixelFormat format) {
207                         switch(format) {
208                                 case PixelFormat.Format16bppGrayScale:
209                                         return BufferedImage.TYPE_USHORT_GRAY;
210                                 case PixelFormat.Format1bppIndexed:
211                                         return BufferedImage.TYPE_BYTE_GRAY;
212                                 case PixelFormat.Format32bppArgb:
213                                         return BufferedImage.TYPE_INT_ARGB;
214                                 case PixelFormat.Format32bppRgb:
215                                         return BufferedImage.TYPE_INT_RGB;
216                                 case PixelFormat.Format32bppPArgb:
217                                         return BufferedImage.TYPE_INT_ARGB_PRE;
218                                 case PixelFormat.Format16bppRgb555:
219                                         return BufferedImage.TYPE_USHORT_555_RGB;
220                                 case PixelFormat.Format16bppRgb565:
221                                         return BufferedImage.TYPE_USHORT_565_RGB;
222                                 case PixelFormat.Indexed:
223                                         return BufferedImage.TYPE_BYTE_INDEXED;
224                                 default:
225                                         return 0;
226                         }                       
227                 }
228
229                 private static java.awt.Image CreateScaledImage(Image original, int width, int height) {
230                         JavaImage oldscaled = original.NativeObject.getScaledInstance(width, height,
231                                 JavaImage.SCALE_DEFAULT);
232                         BufferedImage newimage = new BufferedImage(oldscaled.getWidth(null), 
233                                 oldscaled.getHeight(null),
234                                 BufferedImage.TYPE_INT_ARGB);
235                         java.awt.Graphics2D graphics2d = newimage.createGraphics();
236                         graphics2d.drawImage(oldscaled, 0, 0, null);
237                         graphics2d.dispose();
238                         return newimage;                                
239                 }
240                 #endregion
241
242                 #region Get-SetPixel
243                 public Color GetPixel (int x, int y) 
244                 {
245
246                         int argb = NativeObject.getRGB(x,y);                            
247                         return Color.FromArgb(argb); 
248                 }
249
250                 public void SetPixel (int x, int y, Color color)
251                 {                               
252                         int rgb = color.ToArgb();
253                         NativeObject.setRGB(x,y,rgb);
254                 }
255                 #endregion
256
257                 #region Clone
258                 public override object Clone () {
259                         return new Bitmap (this);
260                 }
261
262                 public Bitmap Clone (Rectangle rect, PixelFormat format)
263                 {
264                         BufferedImage sub = NativeObject.getSubimage(rect.X,rect.Y,rect.Width,rect.Height);
265                         return new Bitmap(sub, RawFormat, format);
266         }
267                 
268                 public Bitmap Clone (RectangleF rect, PixelFormat format)
269                 {
270                         //TODO: check if there is more precise API
271                         BufferedImage sub = NativeObject.getSubimage((int)rect.X,(int)rect.Y,(int)rect.Width,(int)rect.Height);
272                         return new Bitmap(sub, RawFormat, format);
273                 }
274                 #endregion
275
276                 #region LockBits [TODO]
277                 public BitmapData LockBits (Rectangle rect, ImageLockMode flags, PixelFormat format) {
278                         throw new NotImplementedException();
279                 }
280                 #endregion
281
282                 #region MakeTransparent
283                 public void MakeTransparent ()
284                 {
285                         Color clr = GetPixel(0,0);                      
286                         MakeTransparent (clr);
287                 }
288
289                 public void MakeTransparent (Color transparentColor)
290                 {
291                         byte A = transparentColor.A;
292                         image.WritableRaster raster = NativeObject.getRaster();
293                         int numBands  = raster.getNumBands();
294                         int maxWidth  = raster.getWidth() + raster.getMinX();
295                         int maxHeight = raster.getHeight() + raster.getMinY();
296                         int[] srcPix  = new int[numBands];
297
298                         for (int y = raster.getMinY(); y < maxHeight; y++) {
299                                 for (int x = raster.getMinX(); x < maxWidth; x++) {
300                                         /*srcPix =*/ raster.getPixel(x, y, srcPix);
301                                         for (int z = 0; z < numBands; z++) {
302                                                 int argb = srcPix[z];
303                                                 if ((uint)argb >> 24 == A) {
304                                                         argb &= 0x00FFFFFF;
305                                                         srcPix[z] = argb;
306                                                 }
307                                         }
308                                 }
309                         }
310                 }
311                 #endregion
312
313                 #region SetResolution [TODO]
314                 public void SetResolution (float xDpi, float yDpi)
315                 {
316                         throw new NotImplementedException();
317                 }
318                 #endregion 
319
320                 #region UnlockBits [TODO]
321                 public void UnlockBits (BitmapData bitmap_data)
322                 {
323                         throw new NotImplementedException();
324                 }
325                 #endregion 
326
327                 #region NativeObject
328                 internal new BufferedImage NativeObject {
329                         get {
330                                 return (BufferedImage)base.NativeObject;
331                         }
332                 }
333
334                 protected override java.awt.Image[] CloneNativeObjects(java.awt.Image[] src) {
335                         if (src == null)
336                                 return null;
337
338                         awt.Image[] dst = new awt.Image[src.Length];
339                         for (int i = 0; i < dst.Length; i++) {
340                                 BufferedImage image = src[i] as BufferedImage;
341                                 if (image == null)
342                                         throw new ArgumentException(String.Format("Unsupported image type '{0}'", src[i].ToString()), "src");
343
344                                 dst[i] = new BufferedImage(image.getColorModel(), image.copyData(null), image.isAlphaPremultiplied(), null);
345                         }
346
347                         return dst;
348                 }
349
350                 #endregion
351
352                 #region InternalPixelFormat
353                 protected override PixelFormat InternalPixelFormat {
354                         get {
355                                 int t = NativeObject.getType();
356                                 switch(t) {
357                                         case 11://JavaImage.TYPE_USHORT_GRAY:
358                                                 return PixelFormat.Format16bppGrayScale;
359                                         case 10://JavaImage.TYPE_BYTE_GRAY:
360                                                 return PixelFormat.Format1bppIndexed;                           
361                                         case 1: //JavaImage.TYPE_INT_RGB
362                                                 return PixelFormat.Format32bppRgb;
363                                         case 2: //JavaImage.TYPE_INT_ARGB:                      
364                                                 return PixelFormat.Format32bppArgb;
365                                         case 3://JavaImage.TYPE_INT_ARGB_PRE:
366                                                 return PixelFormat.Format32bppPArgb;
367                                         case 9://JavaImage.TYPE_USHORT_555_RGB:
368                                                 return PixelFormat.Format16bppRgb555;
369                                         case 8://JavaImage.TYPE_USHORT_565_RGB:
370                                                 return PixelFormat.Format16bppRgb565;
371                                         case 13://JavaImage.TYPE_BYTE_INDEXED:
372                                                 return PixelFormat.Indexed;
373                                                 //TODO: support this
374                                         case 12://JavaImage.TYPE_BYTE_BINARY:
375                                         case 0://JavaImage.TYPE_CUSTOM:
376                                         case 4://JavaImage.TYPE_INT_BGR:
377                                         case 5://JavaImage.TYPE_3BYTE_BGR:                                      
378                                         case 6://JavaImage.TYPE_4BYTE_ABGR:
379                                         case 7://JavaImage.TYPE_4BYTE_ABGR_PRE:
380                                         default:
381                                                 return PixelFormat.Undefined;
382                                 }                       
383                         }               
384                 }
385                 #endregion
386
387 #if INTPTR_SUPPORT
388                 public static Bitmap FromHicon (IntPtr hicon)
389                 {       
390                         throw new NotImplementedException();
391                 }
392
393                 public static Bitmap FromResource (IntPtr hinstance, string bitmapName) //TODO: Untested
394                 {
395                         throw new NotImplementedException();
396                 }
397
398                 public IntPtr GetHbitmap ()
399                 {
400                         throw new NotImplementedException();
401                 }
402
403                 public IntPtr GetHbitmap (Color background)
404                 {
405                         throw new NotImplementedException();
406                 }
407
408                 public IntPtr GetHicon ()
409                 {
410                         throw new NotImplementedException();
411                 }
412 #endif
413
414         }
415 }