svn path=/branches/mono-1-1-9/mcs/; revision=51212
[mono.git] / mcs / class / System.Drawing / System.Drawing / Image.cs
1 //
2 // System.Drawing.Image.cs
3 //
4 // Copyright (C) 2002 Ximian, Inc.  http://www.ximian.com
5 // Copyright (C) 2004 Novell, Inc.  http://www.novell.com
6 //
7 // Author:      Christian Meyer (Christian.Meyer@cs.tum.edu)
8 //              Alexandre Pigolkine (pigolkine@gmx.de)
9 //              Jordi Mas i Hernandez (jordi@ximian.com)
10 //              Sanjay Gupta (gsanjay@novell.com)
11 //              Ravindra (rkumar@novell.com)
12 //
13
14 //
15 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
16 //
17 // Permission is hereby granted, free of charge, to any person obtaining
18 // a copy of this software and associated documentation files (the
19 // "Software"), to deal in the Software without restriction, including
20 // without limitation the rights to use, copy, modify, merge, publish,
21 // distribute, sublicense, and/or sell copies of the Software, and to
22 // permit persons to whom the Software is furnished to do so, subject to
23 // the following conditions:
24 // 
25 // The above copyright notice and this permission notice shall be
26 // included in all copies or substantial portions of the Software.
27 // 
28 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
29 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
30 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
31 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
32 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
33 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
34 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
35 //
36
37 using System;
38 using System.Runtime.Remoting;
39 using System.Runtime.Serialization;
40 using System.Runtime.InteropServices;
41 using System.ComponentModel;
42 using System.Drawing.Imaging;
43 using System.IO;
44 using System.Reflection;
45
46 namespace System.Drawing
47 {
48 [Serializable]
49 [ComVisible (true)]
50 [Editor ("System.Drawing.Design.ImageEditor, " + Consts.AssemblySystem_Drawing_Design, typeof (System.Drawing.Design.UITypeEditor))]
51 [TypeConverter (typeof(ImageConverter))]
52 [ImmutableObject (true)]
53 public abstract class Image : MarshalByRefObject, IDisposable , ICloneable, ISerializable 
54 {
55         public delegate bool GetThumbnailImageAbort();
56         
57         internal IntPtr nativeObject = IntPtr.Zero;     
58         
59         
60         // constructor
61         internal  Image()
62         {       
63                 
64         }
65         
66         private Image (SerializationInfo info, StreamingContext context)
67         {
68                 foreach (SerializationEntry serEnum in info) {
69                         if (String.Compare(serEnum.Name, "Data", true) == 0) {
70                                 byte[] bytes = (byte[]) serEnum.Value;
71
72                                 if (bytes != null) {
73                                         InitFromStream(new MemoryStream(bytes));
74                                 }
75                         }
76                 }
77         }
78
79         private static bool IsIndexedPixelFormat(PixelFormat pixfmt)
80         {
81                 return ((pixfmt & PixelFormat.Indexed) != 0);
82         }
83
84         
85         void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
86         {
87                 MemoryStream ms = new MemoryStream ();
88                 this.Save (ms, ImageFormat.Bmp);
89                 info.AddValue ("Data", ms.ToArray ());
90         }
91     
92         // public methods
93         // static
94         public static Image FromFile(string filename)
95         {
96                 return FromFile (filename, false);
97         }
98         
99         public static Image FromFile(string filename, bool useEmbeddedColorManagement)
100         {
101                 IntPtr imagePtr;
102                 Status st;
103
104                 if (!File.Exists (filename))
105                         throw new FileNotFoundException (filename);
106
107                 if (useEmbeddedColorManagement)
108                         st = GDIPlus.GdipLoadImageFromFileICM (filename, out imagePtr);
109                 else
110                         st = GDIPlus.GdipLoadImageFromFile (filename, out imagePtr);
111
112                 GDIPlus.CheckStatus (st);
113                 return new Bitmap (imagePtr);
114         }
115
116         public static Bitmap FromHbitmap(IntPtr hbitmap)
117         {
118                 return FromHbitmap (hbitmap, IntPtr.Zero);
119         }
120
121         public static Bitmap FromHbitmap(IntPtr hbitmap, IntPtr hpalette)
122         {               
123                 IntPtr imagePtr;
124                 Status st;
125
126                 st = GDIPlus.GdipCreateBitmapFromHBITMAP (hbitmap, hpalette, out imagePtr);
127
128                 GDIPlus.CheckStatus (st);
129                 return new Bitmap (imagePtr);
130         }
131
132         public static Image FromStream (Stream stream)
133         {
134                 return new Bitmap (stream);
135         }
136         
137         public static Image FromStream (Stream stream, bool useECM)
138         {
139                 return new Bitmap (stream, useECM);
140         }
141
142         public static int GetPixelFormatSize(PixelFormat pixfmt)
143         {
144                 int result = 0;
145                 switch (pixfmt) {
146                         case PixelFormat.Format16bppArgb1555:
147                         case PixelFormat.Format16bppGrayScale:
148                         case PixelFormat.Format16bppRgb555:
149                         case PixelFormat.Format16bppRgb565:
150                                 result = 16;
151                                 break;
152                         case PixelFormat.Format1bppIndexed:
153                                 result = 1;
154                                 break;
155                         case PixelFormat.Format24bppRgb:
156                                 result = 24;
157                                 break;
158                         case PixelFormat.Format32bppArgb:
159                         case PixelFormat.Format32bppPArgb:
160                         case PixelFormat.Format32bppRgb:
161                                 result = 32;
162                                 break;
163                         case PixelFormat.Format48bppRgb:
164                                 result = 48;
165                                 break;
166                         case PixelFormat.Format4bppIndexed:
167                                 result = 4;
168                                 break;
169                         case PixelFormat.Format64bppArgb:
170                         case PixelFormat.Format64bppPArgb:
171                                 result = 64;
172                                 break;
173                         case PixelFormat.Format8bppIndexed:
174                                 result = 8;
175                                 break;
176                 }
177                 return result;
178         }
179
180         public static bool IsAlphaPixelFormat(PixelFormat pixfmt)
181         {
182                 bool result = false;
183                 switch (pixfmt) {
184                         case PixelFormat.Format16bppArgb1555:
185                         case PixelFormat.Format32bppArgb:
186                         case PixelFormat.Format32bppPArgb:
187                         case PixelFormat.Format64bppArgb:
188                         case PixelFormat.Format64bppPArgb:
189                                 result = true;
190                                 break;
191                         case PixelFormat.Format16bppGrayScale:
192                         case PixelFormat.Format16bppRgb555:
193                         case PixelFormat.Format16bppRgb565:
194                         case PixelFormat.Format1bppIndexed:
195                         case PixelFormat.Format24bppRgb:
196                         case PixelFormat.Format32bppRgb:
197                         case PixelFormat.Format48bppRgb:
198                         case PixelFormat.Format4bppIndexed:
199                         case PixelFormat.Format8bppIndexed:
200                                 result = false;
201                                 break;
202                 }
203                 return result;
204         }
205         
206         public static bool IsCanonicalPixelFormat (PixelFormat pixfmt)
207         {
208                 return ((pixfmt & PixelFormat.Canonical) != 0);
209         }
210         
211         public static bool IsExtendedPixelFormat (PixelFormat pixfmt)
212         {
213                 return ((pixfmt & PixelFormat.Extended) != 0);
214         }
215
216         internal void InitFromStream (Stream stream)
217         {
218                 IntPtr imagePtr;
219                 Status st;
220                 
221                 // Seeking required
222                 if (!stream.CanSeek) {
223                         byte[] buffer = new byte[256];
224                         int index = 0;
225                         int count;
226
227                         do {
228                                 if (buffer.Length < index + 256) {
229                                         byte[] newBuffer = new byte[buffer.Length * 2];
230                                         Array.Copy(buffer, newBuffer, buffer.Length);
231                                         buffer = newBuffer;
232                                 }
233                                 count = stream.Read(buffer, index, 256);
234                                 index += count;
235                         }
236                         while (count != 0);
237
238                         stream = new MemoryStream(buffer, 0, index);
239                 }
240
241                 // check for Unix platforms - see FAQ for more details
242                 // http://www.mono-project.com/FAQ:_Technical#How_to_detect_the_execution_platform_.3F
243                 int platform = (int) Environment.OSVersion.Platform;
244                 if ((platform == 4) || (platform == 128)) {
245                         // Unix, with libgdiplus
246                         // We use a custom API for this, because there's no easy way
247                         // to get the Stream down to libgdiplus.  So, we wrap the stream
248                         // with a set of delegates.
249                         GDIPlus.GdiPlusStreamHelper sh = new GDIPlus.GdiPlusStreamHelper (stream);
250
251                         st = GDIPlus.GdipLoadImageFromDelegate_linux (sh.GetHeaderDelegate, sh.GetBytesDelegate,
252                                 sh.PutBytesDelegate, sh.SeekDelegate, sh.CloseDelegate, sh.SizeDelegate, out imagePtr);
253                 } else {
254                         // this is MS-land
255                         st = GDIPlus.GdipLoadImageFromStream(new ComIStreamWrapper(stream), out imagePtr);
256                 }
257
258                 GDIPlus.CheckStatus (st);
259                 nativeObject = imagePtr;
260         }
261
262         // non-static   
263         public RectangleF GetBounds (ref GraphicsUnit pageUnit)
264         {       
265                 RectangleF source;                      
266                 
267                 Status status = GDIPlus.GdipGetImageBounds (nativeObject, out source, ref pageUnit);
268                 GDIPlus.CheckStatus (status);           
269                 
270                 return source;
271         }
272         
273         public EncoderParameters GetEncoderParameterList(Guid format)
274         {
275                 Status status;
276                 uint sz;
277
278                 status = GDIPlus.GdipGetEncoderParameterListSize (nativeObject, ref format, out sz);
279                 GDIPlus.CheckStatus (status);
280
281                 IntPtr rawEPList = Marshal.AllocHGlobal ((int) sz);
282                 EncoderParameters eps;
283
284                 try {
285                         status = GDIPlus.GdipGetEncoderParameterList (nativeObject, ref format, sz, rawEPList);
286                         eps = EncoderParameters.FromNativePtr (rawEPList);
287                         GDIPlus.CheckStatus (status);
288                 } catch {
289                         Marshal.FreeHGlobal (rawEPList);
290                         throw;
291                 }
292
293                 Marshal.FreeHGlobal (rawEPList);
294
295                 return eps;
296         }
297         
298         public int GetFrameCount(FrameDimension dimension)
299         {
300                 int count;
301                 Guid guid = dimension.Guid;
302                 Status status = GDIPlus.GdipImageGetFrameCount (nativeObject, ref guid, out  count); 
303
304                 GDIPlus.CheckStatus (status);           
305                 
306                 return count;
307                 
308         }
309         
310         public PropertyItem GetPropertyItem(int propid)
311         {
312                 int propSize;
313                 IntPtr property;
314                 PropertyItem item = new PropertyItem ();
315                 GdipPropertyItem gdipProperty = new GdipPropertyItem ();
316                 Status status;
317                         
318                 status = GDIPlus.GdipGetPropertyItemSize (nativeObject, propid, 
319                                                                         out propSize);
320                 GDIPlus.CheckStatus (status);
321
322                 /* Get PropertyItem */
323                 property = Marshal.AllocHGlobal (propSize);
324                 status = GDIPlus.GdipGetPropertyItem (nativeObject, propid, propSize,  
325                                                                                 property);
326                 GDIPlus.CheckStatus (status);
327                 gdipProperty = (GdipPropertyItem) Marshal.PtrToStructure ((IntPtr)property, 
328                                                                 typeof (GdipPropertyItem));                                             
329                 GdipPropertyItem.MarshalTo (gdipProperty, item);                                                                
330                 
331                 Marshal.FreeHGlobal (property);
332                 return item;
333         }
334         
335         public Image GetThumbnailImage(int thumbWidth, int thumbHeight, Image.GetThumbnailImageAbort callback, IntPtr callbackData)
336         {
337                 Status          status;
338                 Image           ThumbNail;
339                 Graphics        g;
340
341                 ThumbNail=new Bitmap(thumbWidth, thumbHeight);
342                 g=Graphics.FromImage(ThumbNail);
343                 
344                 status = GDIPlus.GdipDrawImageRectRectI(g.nativeObject, nativeObject,
345                                         0, 0, thumbWidth, thumbHeight,
346                                         0, 0, this.Width, this.Height,
347                                         GraphicsUnit.Pixel, IntPtr.Zero, null, IntPtr.Zero);
348                 GDIPlus.CheckStatus (status);
349                 g.Dispose();
350
351                 return(ThumbNail);
352         }
353         
354         
355         public void RemovePropertyItem (int propid)
356         {               
357                 Status status = GDIPlus.GdipRemovePropertyItem (nativeObject, propid);
358                 GDIPlus.CheckStatus (status);                                   
359         }       
360         
361         public void RotateFlip (RotateFlipType rotateFlipType)
362         {                       
363                 Status status = GDIPlus.GdipImageRotateFlip (nativeObject, rotateFlipType);
364                 GDIPlus.CheckStatus (status);                           
365         }
366
367         internal ImageCodecInfo findEncoderForFormat (ImageFormat format)
368         {
369                 ImageCodecInfo[] encoders = ImageCodecInfo.GetImageEncoders();                  
370                 ImageCodecInfo encoder = null;
371                 
372                 if (format.Guid.Equals (ImageFormat.MemoryBmp.Guid))
373                         format = ImageFormat.Bmp;
374         
375                 /* Look for the right encoder for our format*/
376                 for (int i = 0; i < encoders.Length; i++) {
377                         if (encoders[i].FormatID.Equals (format.Guid)) {
378                                 encoder = encoders[i];
379                                 break;
380                         }                       
381                 }
382
383                 return encoder;
384         }
385
386         public void Save (string filename)
387         {
388                 Save (filename, RawFormat);
389         }
390
391         public void Save(string filename, ImageFormat format) 
392         {
393                 ImageCodecInfo encoder = findEncoderForFormat (format);
394
395                 if (encoder == null)
396                         throw new ArgumentException ("No codec available for format:" + format.Guid);
397
398                 Save (filename, encoder, null);
399         }
400
401         public void Save(string filename, ImageCodecInfo encoder, EncoderParameters encoderParams)
402         {
403                 Status st;
404                 Guid guid = encoder.Clsid;
405
406                 if (encoderParams == null) {
407                         st = GDIPlus.GdipSaveImageToFile (nativeObject, filename, ref guid, IntPtr.Zero);
408                 } else {
409                         IntPtr nativeEncoderParams = encoderParams.ToNativePtr ();
410                         st = GDIPlus.GdipSaveImageToFile (nativeObject, filename, ref guid, nativeEncoderParams);
411                         Marshal.FreeHGlobal (nativeEncoderParams);
412                 }
413
414                 GDIPlus.CheckStatus (st);
415         }
416
417         public void Save (Stream stream, ImageFormat format)
418         {
419                 ImageCodecInfo encoder = findEncoderForFormat (format);
420
421                 if (encoder == null)
422                         throw new ArgumentException ("No codec available for format:" + format.Guid);
423
424                 Save (stream, encoder, null);
425         }
426
427         public void Save(Stream stream, ImageCodecInfo encoder, EncoderParameters encoderParams)
428         {
429                 Status st;
430                 IntPtr nativeEncoderParams;
431                 Guid guid = encoder.Clsid;
432
433                 if (encoderParams == null)
434                         nativeEncoderParams = IntPtr.Zero;
435                 else
436                         nativeEncoderParams = encoderParams.ToNativePtr ();
437
438                 try {
439                         // check for Unix platforms - see FAQ for more details
440                         // http://www.mono-project.com/FAQ:_Technical#How_to_detect_the_execution_platform_.3F
441                         int platform = (int) Environment.OSVersion.Platform;
442                         if ((platform == 4) || (platform == 128)) {
443                                 GDIPlus.GdiPlusStreamHelper sh = new GDIPlus.GdiPlusStreamHelper (stream);
444                                 st = GDIPlus.GdipSaveImageToDelegate_linux (nativeObject, sh.GetBytesDelegate, sh.PutBytesDelegate,
445                                         sh.SeekDelegate, sh.CloseDelegate, sh.SizeDelegate, ref guid, nativeEncoderParams);
446                         }
447                         else
448                                 st = GDIPlus.GdipSaveImageToStream(new HandleRef(this, nativeObject), new ComIStreamWrapper(stream), ref guid, new HandleRef(encoderParams, nativeEncoderParams));
449                 }
450                 finally {
451                         if (nativeEncoderParams != IntPtr.Zero)
452                                 Marshal.FreeHGlobal (nativeEncoderParams);
453                 }
454                 
455                 GDIPlus.CheckStatus (st);               
456         }
457         
458         public void SaveAdd (EncoderParameters encoderParams)
459         {
460                 Status st;
461                 
462                 IntPtr nativeEncoderParams = encoderParams.ToNativePtr ();
463                 st = GDIPlus.GdipSaveAdd (nativeObject, nativeEncoderParams);
464                 Marshal.FreeHGlobal (nativeEncoderParams);
465                 GDIPlus.CheckStatus (st);
466         }
467                 
468         public void SaveAdd (Image image, EncoderParameters encoderParams)
469         {
470                 Status st;
471                 
472                 IntPtr nativeEncoderParams = encoderParams.ToNativePtr ();
473                 st = GDIPlus.GdipSaveAddImage (nativeObject, image.NativeObject, nativeEncoderParams);
474                 Marshal.FreeHGlobal (nativeEncoderParams);
475                 GDIPlus.CheckStatus (st);
476         }
477                 
478         public int SelectActiveFrame(FrameDimension dimension, int frameIndex)
479         {
480                 Guid guid = dimension.Guid;             
481                 Status st = GDIPlus.GdipImageSelectActiveFrame (nativeObject, ref guid, frameIndex);
482                 
483                 GDIPlus.CheckStatus (st);                       
484                 
485                 return frameIndex;              
486         }
487         
488         public void SetPropertyItem(PropertyItem propitem)
489         {
490                 IntPtr property;
491                 int size = Marshal.SizeOf (typeof(GdipPropertyItem));
492                 property = Marshal.AllocHGlobal (size);
493
494                 Marshal.StructureToPtr (propitem, property, true);
495                 Status status = GDIPlus.GdipSetPropertyItem (nativeObject, property);
496                 GDIPlus.CheckStatus (status);
497         }
498
499         // properties   
500         [Browsable (false)]
501         public int Flags {
502                 get {
503                         int flags;
504                         
505                         Status status = GDIPlus.GdipGetImageFlags (nativeObject, out flags);                    
506                         GDIPlus.CheckStatus (status);                                           
507                         return flags;                   
508                 }
509         }
510         
511         [Browsable (false)]
512         public Guid[] FrameDimensionsList {
513                 get {
514                         uint found;
515                         Status status = GDIPlus.GdipImageGetFrameDimensionsCount (nativeObject, out found);
516                         GDIPlus.CheckStatus (status);
517                         Guid [] guid = new Guid [found];
518                         status = GDIPlus.GdipImageGetFrameDimensionsList (nativeObject, guid, found);
519                         GDIPlus.CheckStatus (status);  
520                         return guid;
521                 }
522         }
523
524         [DefaultValue (false)]
525         [Browsable (false)]
526         [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
527         public int Height {
528                 get {
529                         int height;                     
530                         Status status = GDIPlus.GdipGetImageHeight (nativeObject, out height);          
531                         GDIPlus.CheckStatus (status);                   
532                         
533                         return height;
534                 }
535         }
536         
537         public float HorizontalResolution {
538                 get {
539                         float resolution;
540                         
541                         Status status = GDIPlus.GdipGetImageHorizontalResolution (nativeObject, out resolution);                        
542                         GDIPlus.CheckStatus (status);                   
543                         
544                         return resolution;
545                 }
546         }
547         
548         [Browsable (false)]
549         public ColorPalette Palette {
550                 get {                                                   
551                         return retrieveGDIPalette();
552                 }
553                 set {
554                         storeGDIPalette(value);
555                 }
556         }
557
558         internal ColorPalette retrieveGDIPalette()
559         {
560                 ColorPalette ret = new ColorPalette();
561                 if (!IsIndexedPixelFormat (PixelFormat)) {
562                         return ret;
563                 }
564                 Status st;
565                 int bytes;
566
567                 st = GDIPlus.GdipGetImagePaletteSize (nativeObject, out bytes);
568                 GDIPlus.CheckStatus (st);
569                 IntPtr palette_data = Marshal.AllocHGlobal (bytes);
570                 try {
571                         st = GDIPlus.GdipGetImagePalette (nativeObject, palette_data, bytes);
572                         GDIPlus.CheckStatus (st);
573                         ret.setFromGDIPalette (palette_data);
574                         return ret;
575                 }
576
577                 finally {
578                         Marshal.FreeHGlobal (palette_data);
579                 }
580         }
581
582         internal void storeGDIPalette(ColorPalette palette)
583         {
584                 if (palette == null) {
585                         throw new ArgumentNullException("palette");
586                 }
587                 IntPtr palette_data = palette.getGDIPalette();
588                 if (palette_data == IntPtr.Zero) {
589                         return;
590                 }
591
592                 try {
593                         Status st = GDIPlus.GdipSetImagePalette (nativeObject, palette_data);
594                         GDIPlus.CheckStatus (st);
595                 }
596
597                 finally {
598                         Marshal.FreeHGlobal(palette_data);
599                 }
600         }
601
602                 
603         public SizeF PhysicalDimension {
604                 get {
605                         float width,  height;
606                         Status status = GDIPlus.GdipGetImageDimension (nativeObject, out width, out height);            
607                         GDIPlus.CheckStatus (status);                   
608                         
609                         return new SizeF (width, height);
610                 }
611         }
612         
613         public PixelFormat PixelFormat {
614                 get {                   
615                         PixelFormat pixFormat;                          
616                         Status status = GDIPlus.GdipGetImagePixelFormat (nativeObject, out pixFormat);          
617                         GDIPlus.CheckStatus (status);                   
618                         
619                         return pixFormat;
620                 }               
621         }
622         
623         [Browsable (false)]
624         public int[] PropertyIdList {
625                 get {
626                         uint propNumbers;
627                         
628                         Status status = GDIPlus.GdipGetPropertyCount (nativeObject, 
629                                                                         out propNumbers);                       
630                         GDIPlus.CheckStatus (status);
631                         
632                         int [] idList = new int [propNumbers];
633                         status = GDIPlus.GdipGetPropertyIdList (nativeObject, 
634                                                                 propNumbers, idList);
635                         GDIPlus.CheckStatus (status);
636                         
637                         return idList;
638                 }
639         }
640         
641         [Browsable (false)]
642         public PropertyItem[] PropertyItems {
643                 get {
644                         int propNums, propsSize, propSize;
645                         IntPtr properties, propPtr;
646                         PropertyItem[] items;
647                         GdipPropertyItem gdipProperty = new GdipPropertyItem ();
648                         Status status;
649                         
650                         status = GDIPlus.GdipGetPropertySize (nativeObject, out propsSize, out propNums);
651                         GDIPlus.CheckStatus (status);
652
653                         items =  new PropertyItem [propNums];
654                         
655                         if (propNums == 0)
656                                 return items;                   
657                                         
658                         /* Get PropertyItem list*/
659                         properties = Marshal.AllocHGlobal (propsSize);
660                         status = GDIPlus.GdipGetAllPropertyItems (nativeObject, propsSize, 
661                                                                 propNums, properties);
662                         GDIPlus.CheckStatus (status);
663
664                         propSize = Marshal.SizeOf (gdipProperty);                       
665                         propPtr = properties;
666                         
667                         for (int i = 0; i < propNums; i++, propPtr = new IntPtr (propPtr.ToInt64 () + propSize))
668                         {
669                                 gdipProperty = (GdipPropertyItem) Marshal.PtrToStructure 
670                                                 (propPtr, typeof (GdipPropertyItem));                                           
671                                 items [i] = new PropertyItem ();
672                                 GdipPropertyItem.MarshalTo (gdipProperty, items [i]);                                                           
673                         }
674                         
675                         Marshal.FreeHGlobal (properties);
676                         return items;
677                 }
678         }
679
680         public ImageFormat RawFormat {
681                 get {
682                         Guid guid;
683                         Status st = GDIPlus.GdipGetImageRawFormat (nativeObject, out guid);
684                         
685                         GDIPlus.CheckStatus (st);
686                         return new ImageFormat (guid);                  
687                 }
688         }
689         
690         public Size Size {
691                 get {
692                         return new Size(Width, Height);
693                 }
694         }
695         
696         public float VerticalResolution {
697                 get {
698                         float resolution;
699                         
700                         Status status = GDIPlus.GdipGetImageVerticalResolution (nativeObject, out resolution);
701                         GDIPlus.CheckStatus (status);
702
703                         return resolution;
704                 }
705         }
706
707         [DefaultValue (false)]
708         [Browsable (false)]
709         [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
710         public int Width {
711                 get {
712                         int width;                      
713                         Status status = GDIPlus.GdipGetImageWidth (nativeObject, out width);            
714                         GDIPlus.CheckStatus (status);                   
715                         
716                         return width;
717                 }
718         }
719         
720         internal IntPtr NativeObject{
721                 get{
722                         return nativeObject;
723                 }
724                 set     {
725                         nativeObject = value;
726                 }
727         }
728         
729         public void Dispose ()
730         {
731                 Dispose (true);
732                 System.GC.SuppressFinalize (this);
733         }
734
735         ~Image ()
736         {
737                 Dispose (false);
738         }
739
740         private void DisposeResources ()
741         {
742                 Status status = GDIPlus.GdipDisposeImage (nativeObject);
743                 GDIPlus.CheckStatus (status);           
744         }
745         
746         protected virtual void Dispose (bool disposing)
747         {
748                 if (nativeObject != IntPtr.Zero){
749                         DisposeResources ();
750                         nativeObject = IntPtr.Zero;
751                 }
752         }
753         
754         public virtual object Clone()
755         {                               
756
757                 IntPtr newimage = IntPtr.Zero;
758                 
759                 if (!(this is Bitmap)) 
760                         throw new NotImplementedException (); 
761                 
762                 Status status = GDIPlus.GdipCloneImage (NativeObject, out newimage);                    
763                 GDIPlus.CheckStatus (status);                   
764
765                 if (this is Bitmap){
766                         return new Bitmap (newimage);
767                 }
768                 
769                 throw new NotImplementedException ();           
770         }
771
772 }
773
774 }