2008-05-14 Sebastien Pouliot <sebastien@ximian.com>
[mono.git] / mcs / class / System.Drawing / System.Drawing / Bitmap.jvm.cs
index f35402a77dbede9ef9826a1258879c465df55326..57b1ca2306ac0ae06422faa347b2ca8ccd3e5d52 100644 (file)
@@ -2,6 +2,7 @@ using System;
 using System.IO;
 using System.Drawing.Imaging;
 using System.Runtime.Serialization;
+using Mainsoft.Drawing.Imaging;
 
 using io = java.io;
 using imageio = javax.imageio;
@@ -16,187 +17,177 @@ namespace System.Drawing
 {
        public sealed class Bitmap : Image {
 
+               # region Static fields
+
+               static readonly image.ColorModel _jpegColorModel = new image.DirectColorModel(24, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x0);
+
+               #endregion
+
                #region constructors
 
-               Bitmap (Bitmap orig):base (orig) {}
+               Bitmap (PlainImage orig) {
+                       base.Initialize( orig, false );
+               }
 
+               [MonoTODO]
                private Bitmap (SerializationInfo info, StreamingContext context) {
                        throw new NotImplementedException ();
                }
 
-               public Bitmap (int width, int height, Graphics g) {
-                       throw new NotImplementedException();                    
+               public Bitmap (int width, int height, Graphics g) 
+                       :this (width, height, PixelFormat.Format32bppArgb) {
+                       CurrentImage.HorizontalResolution = g.DpiX;
+                       CurrentImage.VerticalResolution = g.DpiY;
                }
 
-               public Bitmap (Image orig, Size newSize)
-                       :this (orig, newSize.Width, newSize.Height) {}
-
-               public Bitmap (Image orig, int width, int height)
-                       :base (CreateScaledImage (orig, width, height), ImageFormat.Bmp) {}
-
-               public Bitmap (int width, int height) 
-                       :this (width, height, PixelFormat.Format32bppArgb) {}
-
                public Bitmap (Image original) 
                        :this (original, original.Size) {}
 
-               public Bitmap (Stream stream)
-                       :this (stream, false) {}
+               public Bitmap (Image orig, Size newSize)
+                       :this (orig, newSize.Width, newSize.Height) {}
 
-               public Bitmap (string filename) 
-                       :this (filename, false) {}
+               public Bitmap (Image orig, int width, int height)
+                       :base (CreateScaledImage (orig, width, height), ImageFormat.MemoryBmp) {}
 
                internal Bitmap (java.awt.Image nativeObject, ImageFormat format)
                        :base (nativeObject, format) {}
 
+               [MonoTODO]
                private Bitmap (java.awt.Image nativeObject, ImageFormat format, PixelFormat pixFormat)
                        :this (nativeObject, format) {
                        if (pixFormat != this.PixelFormat)
                                throw new NotImplementedException ("Converting PixelFormat is not implemented yet.");
                }
 
+               public Bitmap (int width, int height) 
+                       :this (width, height, PixelFormat.Format32bppArgb) {}
+
                public Bitmap (int width, int height, PixelFormat format)
                        :base (
-                               new java.awt.image.BufferedImage (width, height,
-                                       ToBufferedImageFormat (format)),
-                               ImageFormat.Bmp)
-               {
-                       //TBD: why the following 3 lines are necessary?
-//                     java.awt.Graphics2D graphics2d = NativeObject.createGraphics();
-//                     graphics2d.drawImage(NativeObject, 0, 0, null);
-//                     graphics2d.dispose();
+                       new java.awt.image.BufferedImage (width, height,
+                       ToBufferedImageFormat (format)),
+                       ImageFormat.Bmp) {
                }
 
+               public Bitmap (Stream stream)
+                       :this (stream, false) {}
+
+               public Bitmap (string filename) 
+                       :this (filename, false) {}
+
+               [MonoTODO]
                public Bitmap (Stream stream, bool useIcm)
                        :this (stream, useIcm, null) {}
 
+               [MonoTODO]
                public Bitmap (string filename, bool useIcm)
                        :this (filename, useIcm, null) {}
 
                internal Bitmap (Stream stream, bool useIcm, ImageFormat format) {
-                       //FIXME: useIcm param
-                       //FIXME: use direct ImageInputStream wrapper for NET Stream
+                       // TBD: useIcm param
                        io.InputStream jis = vmw.common.IOUtils.ToInputStream (stream);
             Initialize (new stream.MemoryCacheImageInputStream (jis), format);
                }
 
                internal Bitmap (string filename, bool useIcm, ImageFormat format) {
-                       //FIXME: useIcm param
-                       java.io.File file = vmw.common.IOUtils.getJavaFile (filename);
-                       if (!file.exists ())
-                               //TBD: check what exception throws NET
-                               throw new System.IO.IOException ("File not found: "+filename);
-                       Initialize (new stream.FileImageInputStream (file), format);
+                       using(FileStream stream = new FileStream(filename, FileMode.Open, FileAccess.Read)) {
+                               // TBD: useIcm param
+                               io.InputStream jis = vmw.common.IOUtils.ToInputStream (stream);
+                               Initialize (new stream.MemoryCacheImageInputStream (jis), format);
+                       }
                }
 
                public Bitmap (Type type, string resource) {
                        using (Stream s = type.Assembly.GetManifestResourceStream (resource)) {
                                if (s == null)
-                                       //TBD: check what type is thrown in MS
-                                       throw new Exception("Resource name was not found: `" + resource + "'");
+                                       throw new ArgumentException("Resource '" + resource + "' could not be found in class '" + type.ToString() + "'");
+
                                io.InputStream jis = vmw.common.IOUtils.ToInputStream (s);
-                               try {
-                                       Initialize (new stream.MemoryCacheImageInputStream (jis), null);
-                               }
-                               catch (Exception e) {
-                                       //FIXME: catch and throw right exception
-                                       throw new Exception ("java exception", e);
-                               }
+                               Initialize (new stream.MemoryCacheImageInputStream (jis), null);
                        }
                }
-
-               //FIXME: should go to imageio helpers class
-               static ImageFormat MimeTypesToImageFormat (string [] mimeTypes)
-               {
-                       foreach (ImageCodecInfo codec in ImageCodecInfo.Decoders.Values)
-                               for (int i=0; i<mimeTypes.Length; i++)
-                                       if (codec.MimeType == mimeTypes [i])
-                                               return new ImageFormat (codec.FormatID);
-                       return null;
+#if INTPTR_SUPPORT
+               [MonoTODO]
+               public Bitmap (int width, int height, int stride, PixelFormat format, IntPtr scan0)
+               {                                               
+                       throw new NotImplementedException();                    
                }
+#endif
+               #endregion
 
-               private void Initialize (stream.ImageInputStream input, ImageFormat format) {
-                       java.util.Iterator iter = null;
-                       if (format != null)
-                               iter = imageio.ImageIO.getImageReadersByMIMEType (
-                                       ImageCodecInfo.ImageFormatToMimeType (format));
-                       else 
-                               iter = imageio.ImageIO.getImageReaders (input);
-
-                       if (!iter.hasNext ())
-                               throw new ArgumentException ("Format not found"); //TBD: make same text as MS
-
-                       imageio.ImageReader r = (imageio.ImageReader) iter.next ();
+               #region Internal Initialization
 
-                       r.setInput (input);
+               private void Initialize (stream.ImageInputStream input, ImageFormat format) {
+                       ImageCodec ic = null;
 
                        if (format == null)
-                               format = MimeTypesToImageFormat (r.getOriginatingProvider ().getMIMETypes ());
+                               ic = ImageCodec.CreateReader(input);
+                       else
+                               ic = ImageCodec.CreateReader(format);
 
-                       Initialize (r, format);
-               }
+                       if (ic == null)
+                               throw new ArgumentException ("Parameter is not valid.");
 
-               private void Initialize (imageio.ImageReader r, ImageFormat format) {
-                       java.awt.Image [] nativeObjects;
-                       java.awt.Image [] thumbnails = null;
                        try {
-                               nativeObjects = new BufferedImage [r.getNumImages (false)];
-                               for (int i = 0; i < nativeObjects.Length; i++) {
-                                       if (r.hasThumbnails(i)) {
-                                               if (thumbnails == null)
-                                                       thumbnails = new BufferedImage[nativeObjects.Length];
-
-                                               thumbnails[i] = r.readThumbnail(i, 0);
-                                       }
-                                       nativeObjects [i] = r.read (i);
+                               ic.NativeStream = input;
+                               PlainImage pi = ic.ReadPlainImage();
+                               base.Initialize( pi, false );
+
+                               pi = ic.ReadNextPlainImage();
+                               while ( pi != null) {
+                                       base.Initialize( pi, true );
+                                       pi = ic.ReadNextPlainImage();
                                }
 
+                               _flags |= (int)(ImageFlags.ImageFlagsReadOnly | ImageFlags.ImageFlagsHasRealPixelSize);
                        }
-                       catch (Exception e) {
-                               //TDB: make exception same as in MS
-                               throw new ArgumentException ("Error reading", e);
+                       catch (IOException ex) {
+                               throw ex;
+                       }
+                       catch (Exception) {
+                               throw new OutOfMemoryException ("Out of memory");
+                       }
+                       finally {
+                               ic.Dispose();
                        }
-                       base.Initialize (nativeObjects, thumbnails, format, FrameDimension.Page.Guid);
                }
 
-#if INTPTR_SUPPORT
-               public Bitmap (int width, int height, int stride, PixelFormat format, IntPtr scan0)
-               {                                               
-                       throw new NotImplementedException();                    
-               }
-#endif
                #endregion
 
                #region InternalSave
                protected override void InternalSave (stream.ImageOutputStream output, Guid clsid) {
-                       string mime=ImageCodecInfo.FindEncoder (clsid).MimeType;
-                       imageio.ImageWriter writer = null;;
-                       try {
-                               writer = (imageio.ImageWriter) imageio.ImageIO.getImageWritersByMIMEType (mime).next ();
-                               writer.setOutput (output);
-                               if (NativeObjectsCount == 1)
-                                       writer.write (NativeObject);
-                               else if (writer.canWriteSequence ())
-                                       SaveSequence (writer);
-                               else
-                                       throw new NotImplementedException ();
-                       }
-                       catch (Exception e) {
-                               //FIXME: check dotnet exceptions in save, and throw same types
-                               throw new Exception ("java threw an exception", e);
-                       }
-               }
 
-               void SaveSequence (imageio.ImageWriter writer) {
-                       //FIXME: does not supports metadata and thumbnails for now
-                       writer.prepareWriteSequence (null);
+                       ImageCodec ic = ImageCodec.CreateWriter( clsid );
+                       using (ic) {
+
+                               PlainImage plainImage = CurrentImage;
+                               plainImage.NativeImage.flush();
+
+                               if ( ImageCodec.ClsidToImageFormat( clsid ).Equals( ImageFormat.Jpeg ) ) {
+                                       image.ColorModel cm = ((image.BufferedImage)CurrentImage.NativeImage).getColorModel();
+                                       if (cm.hasAlpha()) {
+                                               if (cm is image.DirectColorModel) {
+                                                       image.Raster raster = ((image.BufferedImage)CurrentImage.NativeImage).getRaster();
+                                                       image.DataBuffer db = raster.getDataBuffer();
+                                                       image.DirectColorModel dcm = (image.DirectColorModel)cm;
+                                                       image.SinglePixelPackedSampleModel jpegSampleModel = new image.SinglePixelPackedSampleModel( 
+                                                               db.getDataType(), Width, Height, 
+                                                               new int[] {dcm.getRedMask(), dcm.getGreenMask(), dcm.getBlueMask()}     );
+               
+                                                       image.BufferedImage tb = new image.BufferedImage( 
+                                                               _jpegColorModel, 
+                                                               image.Raster.createWritableRaster( jpegSampleModel, db, null ),
+                                                               false, null );
 
-                       for (int i = 0; i < NativeObjectsCount; i++) {
-                               imageio.IIOImage iio = new imageio.IIOImage ((BufferedImage)this[i], null, null);
-                               writer.writeToSequence (iio, null);
-                       }
+                                                       plainImage = new PlainImage( tb, plainImage.Thumbnails, ImageFormat.Jpeg, plainImage.HorizontalResolution, plainImage.VerticalResolution, plainImage.Dimension );
+                                                       plainImage.NativeMetadata = plainImage.NativeMetadata;
+                                               }
+                                       }
+                               }
 
-                       writer.endWriteSequence ();
+                               ic.NativeStream = output;
+                               ic.WritePlainImage( plainImage );
+                       }
                }
 
                #endregion
@@ -222,12 +213,12 @@ namespace System.Drawing
                                case PixelFormat.Indexed:
                                        return BufferedImage.TYPE_BYTE_INDEXED;
                                default:
-                                       return 0;
+                                       return BufferedImage.TYPE_INT_ARGB;
                        }                       
                }
 
                private static java.awt.Image CreateScaledImage(Image original, int width, int height) {
-                       JavaImage oldscaled = original.NativeObject.getScaledInstance(width, height,
+                       JavaImage oldscaled = original.CurrentImage.NativeImage.getScaledInstance(width, height,
                                JavaImage.SCALE_DEFAULT);
                        BufferedImage newimage = new BufferedImage(oldscaled.getWidth(null), 
                                oldscaled.getHeight(null),
@@ -256,41 +247,59 @@ namespace System.Drawing
 
                #region Clone
                public override object Clone () {
-                       return new Bitmap (this);
+                       return new Bitmap ( (PlainImage)CurrentImage.Clone() );
                }
 
-               public Bitmap Clone (Rectangle rect, PixelFormat format)
+               public Bitmap Clone (Rectangle rect, PixelFormat pixFormat)
                {
-                       BufferedImage sub = NativeObject.getSubimage(rect.X,rect.Y,rect.Width,rect.Height);
-                       return new Bitmap(sub, RawFormat, format);
+                       return Clone(new RectangleF( rect.X, rect.Y, rect.Width, rect.Height ), pixFormat);
                }
                
-               public Bitmap Clone (RectangleF rect, PixelFormat format)
+               public Bitmap Clone (RectangleF rect, PixelFormat pixFormat)
                {
-                       //TODO: check if there is more precise API
-                       BufferedImage sub = NativeObject.getSubimage((int)rect.X,(int)rect.Y,(int)rect.Width,(int)rect.Height);
-                       return new Bitmap(sub, RawFormat, format);
+                       PlainImage plainImage = CurrentImage.Clone(false);
+                       BufferedImage clone = new BufferedImage( (int)rect.Width, (int)rect.Height, ToBufferedImageFormat( pixFormat ) );
+                       awt.Graphics2D g = clone.createGraphics();
+                       try {
+                               g.drawImage( NativeObject, -(int)rect.X, -(int)rect.Y, null );
+                       }
+                       finally {
+                               g.dispose();
+                       }
+
+                       plainImage.NativeImage = clone;
+                       return new Bitmap(plainImage);
                }
                #endregion
 
-               #region LockBits [TODO]
+               #region LockBits
+               [MonoTODO]
                public BitmapData LockBits (Rectangle rect, ImageLockMode flags, PixelFormat format) {
                        throw new NotImplementedException();
                }
+
+#if NET_2_0
+               public
+#endif
+               BitmapData LockBits (Rectangle rect, ImageLockMode flags, PixelFormat format, BitmapData bitmapData) {
+                       throw new NotImplementedException();
+               }
                #endregion
 
                #region MakeTransparent
                public void MakeTransparent ()
                {
-                       Color clr = GetPixel(0,0);                      
+                       Color clr = Color.FromArgb(0,0,0);                      
                        MakeTransparent (clr);
                }
 
                public void MakeTransparent (Color transparentColor)
                {
-                       byte A = transparentColor.A;
                        image.WritableRaster raster = NativeObject.getRaster();
                        int numBands  = raster.getNumBands();
+                       if (numBands != 4)
+                               return;
+
                        int maxWidth  = raster.getWidth() + raster.getMinX();
                        int maxHeight = raster.getHeight() + raster.getMinY();
                        int[] srcPix  = new int[numBands];
@@ -298,26 +307,27 @@ namespace System.Drawing
                        for (int y = raster.getMinY(); y < maxHeight; y++) {
                                for (int x = raster.getMinX(); x < maxWidth; x++) {
                                        /*srcPix =*/ raster.getPixel(x, y, srcPix);
-                                       for (int z = 0; z < numBands; z++) {
-                                               int argb = srcPix[z];
-                                               if ((uint)argb >> 24 == A) {
-                                                       argb &= 0x00FFFFFF;
-                                                       srcPix[z] = argb;
-                                               }
+                                       if (srcPix[0] == transparentColor.R &&
+                                               srcPix[1] == transparentColor.G &&
+                                               srcPix[2] == transparentColor.B) {
+                                               srcPix[3] = 0;
+                                               raster.setPixel(x, y, srcPix);
                                        }
                                }
                        }
                }
                #endregion
 
-               #region SetResolution [TODO]
+               #region SetResolution
                public void SetResolution (float xDpi, float yDpi)
                {
-                       throw new NotImplementedException();
+                       CurrentImage.HorizontalResolution = xDpi;
+                       CurrentImage.VerticalResolution = yDpi;
                }
                #endregion 
 
-               #region UnlockBits [TODO]
+               #region UnlockBits
+               [MonoTODO]
                public void UnlockBits (BitmapData bitmap_data)
                {
                        throw new NotImplementedException();
@@ -327,7 +337,7 @@ namespace System.Drawing
                #region NativeObject
                internal new BufferedImage NativeObject {
                        get {
-                               return (BufferedImage)base.NativeObject;
+                               return (BufferedImage)base.NativeObject.CurrentImage.NativeImage;
                        }
                }
 
@@ -357,7 +367,7 @@ namespace System.Drawing
                                        case 11://JavaImage.TYPE_USHORT_GRAY:
                                                return PixelFormat.Format16bppGrayScale;
                                        case 10://JavaImage.TYPE_BYTE_GRAY:
-                                               return PixelFormat.Format1bppIndexed;                           
+                                               return PixelFormat.Format8bppIndexed;                           
                                        case 1: //JavaImage.TYPE_INT_RGB
                                                return PixelFormat.Format32bppRgb;
                                        case 2: //JavaImage.TYPE_INT_ARGB:                      
@@ -370,7 +380,7 @@ namespace System.Drawing
                                                return PixelFormat.Format16bppRgb565;
                                        case 13://JavaImage.TYPE_BYTE_INDEXED:
                                                return PixelFormat.Indexed;
-                                               //TODO: support this
+                                               //TBD: support this
                                        case 12://JavaImage.TYPE_BYTE_BINARY:
                                        case 0://JavaImage.TYPE_CUSTOM:
                                        case 4://JavaImage.TYPE_INT_BGR:
@@ -385,26 +395,31 @@ namespace System.Drawing
                #endregion
 
 #if INTPTR_SUPPORT
+               [MonoTODO]
                public static Bitmap FromHicon (IntPtr hicon)
                {       
                        throw new NotImplementedException();
                }
 
-               public static Bitmap FromResource (IntPtr hinstance, string bitmapName) //TODO: Untested
+               [MonoTODO]
+               public static Bitmap FromResource (IntPtr hinstance, string bitmapName) //TBD: Untested
                {
                        throw new NotImplementedException();
                }
 
+               [MonoTODO]
                public IntPtr GetHbitmap ()
                {
                        throw new NotImplementedException();
                }
 
+               [MonoTODO]
                public IntPtr GetHbitmap (Color background)
                {
                        throw new NotImplementedException();
                }
 
+               [MonoTODO]
                public IntPtr GetHicon ()
                {
                        throw new NotImplementedException();