2005-01-31 Zoltan Varga <vargaz@freemail.hu>
[mono.git] / mcs / class / System.Drawing / System.Drawing / Image.cs
index 41240fe6bb0cd8c13bd781054eea09de9135c2d0..0bfe5c94215db1102aa933a9f7fc273a76e13048 100644 (file)
@@ -1,12 +1,38 @@
 //
 // System.Drawing.Image.cs
 //
-// (C) 2002 Ximian, Inc.  http://www.ximian.com
+// Copyright (C) 2002 Ximian, Inc.  http://www.ximian.com
+// Copyright (C) 2004 Novell, Inc.  http://www.novell.com
+//
 // Author:     Christian Meyer (Christian.Meyer@cs.tum.edu)
 //             Alexandre Pigolkine (pigolkine@gmx.de)
 //             Jordi Mas i Hernandez (jordi@ximian.com)
+//             Sanjay Gupta (gsanjay@novell.com)
+//             Ravindra (rkumar@novell.com)
+//
+
+//
+// Copyright (C) 2004 Novell, Inc (http://www.novell.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
-namespace System.Drawing {
 
 using System;
 using System.Runtime.Remoting;
@@ -16,6 +42,8 @@ using System.ComponentModel;
 using System.Drawing.Imaging;
 using System.IO;
 
+namespace System.Drawing
+{
 [Serializable]
 [ComVisible (true)]
 [Editor ("System.Drawing.Design.ImageEditor, " + Consts.AssemblySystem_Drawing_Design, typeof (System.Drawing.Design.UITypeEditor))]
@@ -26,8 +54,8 @@ public abstract class Image : MarshalByRefObject, IDisposable , ICloneable, ISer
        public delegate bool GetThumbnailImageAbort();
        
        internal IntPtr nativeObject = IntPtr.Zero;     
-       protected ColorPalette colorPalette;
-       protected ImageFormat raw_format;
+       ColorPalette colorPalette;
+       
        
        // constructor
        internal  Image()
@@ -35,15 +63,23 @@ public abstract class Image : MarshalByRefObject, IDisposable , ICloneable, ISer
                colorPalette = new ColorPalette();
        }
        
-       [MonoTODO]      
        private Image (SerializationInfo info, StreamingContext context)
        {
-               
+               foreach (SerializationEntry serEnum in info) {
+                       if (String.Compare(serEnum.Name, "Data", true) == 0) {
+                               byte[] bytes = (byte[]) serEnum.Value;
+
+                               if (bytes != null) {
+                                       InitFromStream(new MemoryStream(bytes));
+                               }
+                       }
+               }
        }
        
        [MonoTODO]      
        void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
        {
+               throw new NotImplementedException();
        }
     
        // public methods
@@ -154,6 +190,32 @@ public abstract class Image : MarshalByRefObject, IDisposable , ICloneable, ISer
                return ((pixfmt & PixelFormat.Extended) != 0);
        }
 
+       internal void InitFromStream (Stream stream)
+       {
+               if (Environment.OSVersion.Platform == (PlatformID) 128) {
+                       // Unix, with libgdiplus
+                       // We use a custom API for this, because there's no easy way
+                       // to get the Stream down to libgdiplus.  So, we wrap the stream
+                       // with a set of delegates.
+                       GDIPlus.GdiPlusStreamHelper sh = new GDIPlus.GdiPlusStreamHelper (stream);
+                       IntPtr imagePtr;
+
+                       Status st = GDIPlus.GdipLoadImageFromDelegate_linux (sh.GetBytesDelegate, sh.PutBytesDelegate,
+                                                                       sh.SeekDelegate, sh.CloseDelegate, sh.SizeDelegate,
+                                                                                    out imagePtr);
+                       GDIPlus.CheckStatus (st);
+                       nativeObject = imagePtr;
+               } else {
+                       // this is MS-land
+                       // FIXME
+                       // We can't call the native gdip functions here, because they expect
+                       // a COM IStream interface.  So, a hack is to create a tmp file, read
+                       // the stream, and then load from the tmp file.
+                       // This is an ugly hack.
+                       throw new NotImplementedException ("Bitmap.InitFromStream (win32)");
+               }
+       }
+
        // non-static   
        public RectangleF GetBounds (ref GraphicsUnit pageUnit)
        {       
@@ -165,124 +227,225 @@ public abstract class Image : MarshalByRefObject, IDisposable , ICloneable, ISer
                return source;
        }
        
-       [MonoTODO]      
-       public EncoderParameters GetEncoderParameterList(Guid encoder)
+       public EncoderParameters GetEncoderParameterList(Guid format)
        {
-               throw new NotImplementedException ();
+               Status status;
+               uint sz;
+
+               status = GDIPlus.GdipGetEncoderParameterListSize (nativeObject, ref format, out sz);
+               GDIPlus.CheckStatus (status);
+
+               IntPtr rawEPList = Marshal.AllocHGlobal ((int) sz);
+               EncoderParameters eps;
+
+               try {
+                       status = GDIPlus.GdipGetEncoderParameterList (nativeObject, ref format, sz, rawEPList);
+                       eps = EncoderParameters.FromNativePtr (rawEPList);
+                       GDIPlus.CheckStatus (status);
+               } catch {
+                       Marshal.FreeHGlobal (rawEPList);
+                       throw;
+               }
+
+               Marshal.FreeHGlobal (rawEPList);
+
+               return eps;
        }
        
        public int GetFrameCount(FrameDimension dimension)
        {
                int count;
                Guid guid = dimension.Guid;
-               
-               Status status = GDIPlus.GdipImageGetFrameCount (nativeObject, ref guid, out  count);
+               Status status = GDIPlus.GdipImageGetFrameCount (nativeObject, ref guid, out  count); 
+
                GDIPlus.CheckStatus (status);           
                
                return count;
                
        }
        
-       [MonoTODO]      
        public PropertyItem GetPropertyItem(int propid)
        {
-               throw new NotImplementedException ();
+               int propSize;
+               IntPtr property;
+               PropertyItem item = new PropertyItem ();
+               GdipPropertyItem gdipProperty = new GdipPropertyItem ();
+               Status status;
+                       
+               status = GDIPlus.GdipGetPropertyItemSize (nativeObject, propid, 
+                                                                       out propSize);
+               GDIPlus.CheckStatus (status);
+
+               /* Get PropertyItem */
+               property = Marshal.AllocHGlobal (propSize);
+               status = GDIPlus.GdipGetPropertyItem (nativeObject, propid, propSize,  
+                                                                               property);
+               GDIPlus.CheckStatus (status);
+               gdipProperty = (GdipPropertyItem) Marshal.PtrToStructure ((IntPtr)property, 
+                                                               typeof (GdipPropertyItem));                                             
+               GdipPropertyItem.MarshalTo (gdipProperty, item);                                                                
+               
+               Marshal.FreeHGlobal (property);
+               return item;
        }
        
-       [MonoTODO]      
        public Image GetThumbnailImage(int thumbWidth, int thumbHeight, Image.GetThumbnailImageAbort callback, IntPtr callbackData)
        {
-               throw new NotImplementedException ();                           
+               Status          status;
+               Image           ThumbNail;
+               Graphics        g;
+
+               ThumbNail=new Bitmap(thumbWidth, thumbHeight);
+               g=Graphics.FromImage(ThumbNail);
+               
+               status = GDIPlus.GdipDrawImageRectRectI(g.nativeObject, nativeObject,
+                                       0, 0, thumbWidth, thumbHeight,
+                                       0, 0, this.Width, this.Height,
+                                       GraphicsUnit.Pixel, IntPtr.Zero, null, IntPtr.Zero);
+                GDIPlus.CheckStatus (status);
+               g.Dispose();
+
+               return(ThumbNail);
        }
        
-       [MonoTODO]      
+       
        public void RemovePropertyItem (int propid)
        {               
-               throw new NotImplementedException ();
-       }
+               Status status = GDIPlus.GdipRemovePropertyItem (nativeObject, propid);
+               GDIPlus.CheckStatus (status);                                   
+       }       
        
-       [MonoTODO]      
        public void RotateFlip (RotateFlipType rotateFlipType)
-       {               
-               throw new NotImplementedException ();
+       {                       
+               Status status = GDIPlus.GdipImageRotateFlip (nativeObject, rotateFlipType);
+               GDIPlus.CheckStatus (status);                           
        }
 
-       public void Save (string filename)
+       internal ImageCodecInfo findEncoderForFormat (ImageFormat format)
        {
-               Save (filename, RawFormat);
+               ImageCodecInfo[] encoders = ImageCodecInfo.GetImageEncoders();                  
+               ImageCodecInfo encoder = null;
+               
+               if (format.Guid.Equals (ImageFormat.MemoryBmp.Guid))
+                       format = ImageFormat.Bmp;
+       
+               /* Look for the right encoder for our format*/
+               for (int i = 0; i < encoders.Length; i++) {
+                       if (encoders[i].FormatID.Equals (format.Guid)) {
+                               encoder = encoders[i];
+                               break;
+                       }                       
+               }
+
+               return encoder;
        }
 
-       public void Save (Stream stream, ImageFormat format)
+       public void Save (string filename)
        {
-               if (Environment.OSVersion.Platform == (PlatformID) 128) {
-                       byte[] g = format.Guid.ToByteArray();
-                       GDIPlus.GdiPlusStreamHelper sh = new GDIPlus.GdiPlusStreamHelper (stream);
-                       Status st = GDIPlus.GdipSaveImageToDelegate_linux (nativeObject, sh.PutBytesDelegate, g, IntPtr.Zero);
-               } else {
-                       throw new NotImplementedException ("Image.Save(Stream) (win32)");
-               }
+               Save (filename, RawFormat);
        }
 
        public void Save(string filename, ImageFormat format) 
        {
-               byte[] g = format.Guid.ToByteArray();
-               Status st = GDIPlus.GdipSaveImageToFile (nativeObject, filename, g, IntPtr.Zero);
-               GDIPlus.CheckStatus (st);
+               ImageCodecInfo encoder = findEncoderForFormat (format);
+
+               if (encoder == null)
+                       throw new ArgumentException ("No codec available for format:" + format.Guid);
+
+               Save (filename, encoder, null);
        }
-       
-       internal void setGDIPalette() 
+
+       public void Save(string filename, ImageCodecInfo encoder, EncoderParameters encoderParams)
        {
-               IntPtr gdipalette;
+               Status st;
+               Guid guid = encoder.Clsid;
 
-               gdipalette = colorPalette.getGDIPalette ();
-               Status st = GDIPlus.GdipSetImagePalette (NativeObject, gdipalette);
-               Marshal.FreeHGlobal (gdipalette);
+               if (encoderParams == null) {
+                       st = GDIPlus.GdipSaveImageToFile (nativeObject, filename, ref guid, IntPtr.Zero);
+               } else {
+                       IntPtr nativeEncoderParams = encoderParams.ToNativePtr ();
+                       st = GDIPlus.GdipSaveImageToFile (nativeObject, filename, ref guid, nativeEncoderParams);
+                       Marshal.FreeHGlobal (nativeEncoderParams);
+               }
 
                GDIPlus.CheckStatus (st);
        }
 
-       [MonoTODO ("Ignoring EncoderParameters")]
-       public void Save(Stream stream, ImageCodecInfo encoder, EncoderParameters encoderParams)
+       public void Save (Stream stream, ImageFormat format)
        {
-               Save (stream, new ImageFormat (encoder.Clsid));
+               ImageCodecInfo encoder = findEncoderForFormat (format);
+
+               if (encoder == null)
+                       throw new ArgumentException ("No codec available for format:" + format.Guid);
+
+               Save (stream, encoder, null);
        }
-       
-       [MonoTODO ("Ignoring EncoderParameters")]       
-       public void Save(string filename, ImageCodecInfo encoder, EncoderParameters encoderParams)
+
+       public void Save(Stream stream, ImageCodecInfo encoder, EncoderParameters encoderParams)
        {
-               Save (filename, new ImageFormat (encoder.Clsid));
+               Status st;
+               Guid guid = encoder.Clsid;
+
+               if (Environment.OSVersion.Platform == (PlatformID) 128) {
+                       GDIPlus.GdiPlusStreamHelper sh = new GDIPlus.GdiPlusStreamHelper (stream);
+                       if (encoderParams == null) {
+                               st = GDIPlus.GdipSaveImageToDelegate_linux (nativeObject, sh.GetBytesDelegate, sh.PutBytesDelegate,
+                                               sh.SeekDelegate, sh.CloseDelegate, sh.SizeDelegate, ref guid, IntPtr.Zero);
+                       } else {
+                               IntPtr nativeEncoderParams = encoderParams.ToNativePtr ();
+                               st = GDIPlus.GdipSaveImageToDelegate_linux (nativeObject, sh.GetBytesDelegate, sh.PutBytesDelegate,
+                                               sh.SeekDelegate, sh.CloseDelegate, sh.SizeDelegate, ref guid, nativeEncoderParams);
+                               Marshal.FreeHGlobal (nativeEncoderParams);
+                       }
+               } else {
+                       throw new NotImplementedException ("Image.Save(Stream) (win32)");
+               }
+               GDIPlus.CheckStatus (st);
        }
        
-       [MonoTODO]      
-       public void SaveAdd(EncoderParameters encoderParams)
+       public void SaveAdd (EncoderParameters encoderParams)
        {
-               throw new NotImplementedException ();
+               Status st;
+               
+               IntPtr nativeEncoderParams = encoderParams.ToNativePtr ();
+               st = GDIPlus.GdipSaveAdd (nativeObject, nativeEncoderParams);
+               Marshal.FreeHGlobal (nativeEncoderParams);\r
+               GDIPlus.CheckStatus (st);
        }
-       
-       [MonoTODO]      
-       public void SaveAdd(Image image, EncoderParameters encoderParams)
+               
+       public void SaveAdd (Image image, EncoderParameters encoderParams)
        {
-               throw new NotImplementedException ();
+               Status st;
+               
+               IntPtr nativeEncoderParams = encoderParams.ToNativePtr ();
+               st = GDIPlus.GdipSaveAddImage (nativeObject, image.NativeObject, nativeEncoderParams);
+               Marshal.FreeHGlobal (nativeEncoderParams);\r
+               GDIPlus.CheckStatus (st);
        }
-       
-       
+               
        public int SelectActiveFrame(FrameDimension dimension, int frameIndex)
        {
                Guid guid = dimension.Guid;             
-                               
-               Status status = GDIPlus.GdipImageSelectActiveFrame (nativeObject, ref guid, frameIndex);                        
-               GDIPlus.CheckStatus (status);                   
+               Status st = GDIPlus.GdipImageSelectActiveFrame (nativeObject, ref guid, frameIndex);
+               
+               GDIPlus.CheckStatus (st);                       
                
                return frameIndex;              
        }
        
-       [MonoTODO]      
        public void SetPropertyItem(PropertyItem propitem)
        {
-               throw new NotImplementedException ();
+               IntPtr property;
+               int size = Marshal.SizeOf (typeof(GdipPropertyItem));
+               property = Marshal.AllocHGlobal (size);
+
+               Marshal.StructureToPtr (propitem, property, true);
+               Status status = GDIPlus.GdipSetPropertyItem (nativeObject, property);
+               GDIPlus.CheckStatus (status);
        }
 
        // properties   
+       [Browsable (false)]
        public int Flags {
                get {
                        int flags;
@@ -293,13 +456,22 @@ public abstract class Image : MarshalByRefObject, IDisposable , ICloneable, ISer
                }
        }
        
-       [MonoTODO]      
+       [Browsable (false)]
        public Guid[] FrameDimensionsList {
                get {
-                       throw new NotImplementedException ();
+                       uint found;
+                       Status status = GDIPlus.GdipImageGetFrameDimensionsCount (nativeObject, out found);
+                       GDIPlus.CheckStatus (status);
+                       Guid [] guid = new Guid [found];
+                       status = GDIPlus.GdipImageGetFrameDimensionsList (nativeObject, guid, found);
+                       GDIPlus.CheckStatus (status);  
+                       return guid;
                }
        }
-       
+
+       [DefaultValue (false)]
+       [Browsable (false)]
+       [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
        public int Height {
                get {
                        int height;                     
@@ -321,6 +493,7 @@ public abstract class Image : MarshalByRefObject, IDisposable , ICloneable, ISer
                }
        }
        
+       [Browsable (false)]
        public ColorPalette Palette {
                get {                                                   
                        
@@ -330,12 +503,10 @@ public abstract class Image : MarshalByRefObject, IDisposable , ICloneable, ISer
                        colorPalette = value;                                   
                }
        }
-       
-       
+               
        public SizeF PhysicalDimension {
                get {
                        float width,  height;
-                       
                        Status status = GDIPlus.GdipGetImageDimension (nativeObject, out width, out height);            
                        GDIPlus.CheckStatus (status);                   
                        
@@ -344,42 +515,82 @@ public abstract class Image : MarshalByRefObject, IDisposable , ICloneable, ISer
        }
        
        public PixelFormat PixelFormat {
-               get {
-                       
-                       PixelFormat value;                              
-                       Status status = GDIPlus.GdipGetImagePixelFormat (nativeObject, out value);              
+               get {                   
+                       PixelFormat pixFormat;                          
+                       Status status = GDIPlus.GdipGetImagePixelFormat (nativeObject, out pixFormat);          
                        GDIPlus.CheckStatus (status);                   
                        
-                       return value;
+                       return pixFormat;
                }               
        }
        
-       
-       [MonoTODO]      
+       [Browsable (false)]
        public int[] PropertyIdList {
                get {
-                       throw new NotImplementedException ();
+                       uint propNumbers;
+                       
+                       Status status = GDIPlus.GdipGetPropertyCount (nativeObject, 
+                                                                       out propNumbers);                       
+                       GDIPlus.CheckStatus (status);
+                       
+                       int [] idList = new int [propNumbers];
+                       status = GDIPlus.GdipGetPropertyIdList (nativeObject, 
+                                                               propNumbers, idList);
+                       GDIPlus.CheckStatus (status);
+                       
+                       return idList;
                }
        }
        
-       [MonoTODO]      
+       [Browsable (false)]
        public PropertyItem[] PropertyItems {
                get {
-                       throw new NotImplementedException ();
+                       int propNums, propsSize, propSize;
+                       IntPtr properties, propPtr;
+                       PropertyItem[] items;
+                       GdipPropertyItem gdipProperty = new GdipPropertyItem ();
+                       Status status;
+                       
+                       status = GDIPlus.GdipGetPropertySize (nativeObject, out propsSize, out propNums);
+                       GDIPlus.CheckStatus (status);
+
+                       items =  new PropertyItem [propNums];
+                       
+                       if (propNums == 0)
+                               return items;                   
+                                       
+                       /* Get PropertyItem list*/
+                       properties = Marshal.AllocHGlobal (propsSize);
+                       status = GDIPlus.GdipGetAllPropertyItems (nativeObject, propsSize, 
+                                                               propNums, properties);
+                       GDIPlus.CheckStatus (status);
+
+                       propSize = Marshal.SizeOf (gdipProperty);                       
+                       propPtr = properties;
+                       
+                       for (int i = 0; i < propNums; i++, propPtr = new IntPtr (propPtr.ToInt64 () + propSize))
+                       {
+                               gdipProperty = (GdipPropertyItem) Marshal.PtrToStructure 
+                                               (propPtr, typeof (GdipPropertyItem));                                           
+                               items [i] = new PropertyItem ();
+                               GdipPropertyItem.MarshalTo (gdipProperty, items [i]);                                                           
+                       }
+                       
+                       Marshal.FreeHGlobal (properties);
+                       return items;
                }
        }
 
        public ImageFormat RawFormat {
                get {
-                       return raw_format;
+                       Guid guid;
+                       Status st = GDIPlus.GdipGetImageRawFormat (nativeObject, out guid);
+                       
+                       GDIPlus.CheckStatus (st);
+                       return new ImageFormat (guid);                  
                }
        }
-
-       internal void SetRawFormat (ImageFormat format)
-       {
-               raw_format = format;
-       }
-
+       
        public Size Size {
                get {
                        return new Size(Width, Height);
@@ -390,11 +601,16 @@ public abstract class Image : MarshalByRefObject, IDisposable , ICloneable, ISer
                get {
                        float resolution;
                        
-                       GDIPlus.GdipGetImageVerticalResolution (nativeObject, out resolution);                  
+                       Status status = GDIPlus.GdipGetImageVerticalResolution (nativeObject, out resolution);
+                       GDIPlus.CheckStatus (status);
+
                        return resolution;
                }
        }
-       
+
+       [DefaultValue (false)]
+       [Browsable (false)]
+       [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
        public int Width {
                get {
                        int width;                      
@@ -417,6 +633,7 @@ public abstract class Image : MarshalByRefObject, IDisposable , ICloneable, ISer
        public void Dispose ()
        {
                Dispose (true);
+               System.GC.SuppressFinalize (this);
        }
 
        ~Image ()
@@ -424,35 +641,46 @@ public abstract class Image : MarshalByRefObject, IDisposable , ICloneable, ISer
                Dispose (false);
        }
 
-       protected virtual void DisposeResources ()
+       private void DisposeResources ()
        {
-               GDIPlus.GdipDisposeImage (nativeObject);
+               lock (this)
+               {
+                       Status status = GDIPlus.GdipDisposeImage (nativeObject);
+                       GDIPlus.CheckStatus (status);
+               }
        }
        
        protected virtual void Dispose (bool disposing)
        {
-               if (nativeObject != (IntPtr) 0){
+               if (nativeObject != IntPtr.Zero){
                        DisposeResources ();
-                       nativeObject=IntPtr.Zero;
+                       nativeObject = IntPtr.Zero;
                }
        }
        
-       
        public virtual object Clone()
        {                               
-               IntPtr newimage = IntPtr.Zero;
-               
-               if (!(this is Bitmap)) 
+               lock (this)
+               {
+                       IntPtr newimage = IntPtr.Zero;
+                       
+                       if (!(this is Bitmap)) 
+                               throw new NotImplementedException (); 
+                       
+                       Status status = GDIPlus.GdipCloneImage (NativeObject, out newimage);                    
+                       GDIPlus.CheckStatus (status);                   
+
+                       if (this is Bitmap){
+                               Bitmap b = new Bitmap (newimage);
+
+                               if (colorPalette != null)
+                                       b.colorPalette = colorPalette.Clone ();
+
+                               return b;
+                       }
+                       
                        throw new NotImplementedException (); 
-               
-               Status status = GDIPlus.GdipCloneImage (NativeObject, out newimage);                    
-               
-               GDIPlus.CheckStatus (status);                   
-               
-               if (this is Bitmap)
-                       return new Bitmap (newimage);
-               
-               throw new NotImplementedException (); 
+               }
        }
 
 }