54432fc76dbfa0d1e917df1dc699001ce66c332f
[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 new Bitmap (filename);
97         }
98         
99         public static Image FromFile(string filename, bool useEmbeddedColorManagement)
100         {
101                 return new Bitmap (filename, useEmbeddedColorManagement);
102         }
103
104         [MonoTODO]      
105         public static Bitmap FromHbitmap(IntPtr hbitmap)
106         {               
107                 throw new NotImplementedException ();
108         }
109
110         [MonoTODO]      
111         public static Bitmap FromHbitmap(IntPtr hbitmap, IntPtr hpalette)
112         {               
113                 throw new NotImplementedException ();
114         }
115
116         public static Image FromStream (Stream stream)
117         {
118                 return new Bitmap (stream);
119         }
120         
121         public static Image FromStream (Stream stream, bool useECM)
122         {
123                 return new Bitmap (stream, useECM);
124         }
125
126         public static int GetPixelFormatSize(PixelFormat pixfmt)
127         {
128                 int result = 0;
129                 switch (pixfmt) {
130                         case PixelFormat.Format16bppArgb1555:
131                         case PixelFormat.Format16bppGrayScale:
132                         case PixelFormat.Format16bppRgb555:
133                         case PixelFormat.Format16bppRgb565:
134                                 result = 16;
135                                 break;
136                         case PixelFormat.Format1bppIndexed:
137                                 result = 1;
138                                 break;
139                         case PixelFormat.Format24bppRgb:
140                                 result = 24;
141                                 break;
142                         case PixelFormat.Format32bppArgb:
143                         case PixelFormat.Format32bppPArgb:
144                         case PixelFormat.Format32bppRgb:
145                                 result = 32;
146                                 break;
147                         case PixelFormat.Format48bppRgb:
148                                 result = 48;
149                                 break;
150                         case PixelFormat.Format4bppIndexed:
151                                 result = 4;
152                                 break;
153                         case PixelFormat.Format64bppArgb:
154                         case PixelFormat.Format64bppPArgb:
155                                 result = 64;
156                                 break;
157                         case PixelFormat.Format8bppIndexed:
158                                 result = 8;
159                                 break;
160                 }
161                 return result;
162         }
163
164         public static bool IsAlphaPixelFormat(PixelFormat pixfmt)
165         {
166                 bool result = false;
167                 switch (pixfmt) {
168                         case PixelFormat.Format16bppArgb1555:
169                         case PixelFormat.Format32bppArgb:
170                         case PixelFormat.Format32bppPArgb:
171                         case PixelFormat.Format64bppArgb:
172                         case PixelFormat.Format64bppPArgb:
173                                 result = true;
174                                 break;
175                         case PixelFormat.Format16bppGrayScale:
176                         case PixelFormat.Format16bppRgb555:
177                         case PixelFormat.Format16bppRgb565:
178                         case PixelFormat.Format1bppIndexed:
179                         case PixelFormat.Format24bppRgb:
180                         case PixelFormat.Format32bppRgb:
181                         case PixelFormat.Format48bppRgb:
182                         case PixelFormat.Format4bppIndexed:
183                         case PixelFormat.Format8bppIndexed:
184                                 result = false;
185                                 break;
186                 }
187                 return result;
188         }
189         
190         public static bool IsCanonicalPixelFormat (PixelFormat pixfmt)
191         {
192                 return ((pixfmt & PixelFormat.Canonical) != 0);
193         }
194         
195         public static bool IsExtendedPixelFormat (PixelFormat pixfmt)
196         {
197                 return ((pixfmt & PixelFormat.Extended) != 0);
198         }
199
200         internal void InitFromStream (Stream stream)
201         {
202                 IntPtr imagePtr;
203                 Status st;
204                 
205                 // Seeking required
206                 if (!stream.CanSeek) {
207                         byte[] buffer = new byte[256];
208                         int index = 0;
209                         int count;
210
211                         do {
212                                 if (buffer.Length < index + 256) {
213                                         byte[] newBuffer = new byte[buffer.Length * 2];
214                                         Array.Copy(buffer, newBuffer, buffer.Length);
215                                         buffer = newBuffer;
216                                 }
217                                 count = stream.Read(buffer, index, 256);
218                                 index += count;
219                         }
220                         while (count != 0);
221
222                         stream = new MemoryStream(buffer, 0, index);
223                 }
224
225                 // check for Unix platforms - see FAQ for more details
226                 // http://www.mono-project.com/FAQ:_Technical#How_to_detect_the_execution_platform_.3F
227                 int platform = (int) Environment.OSVersion.Platform;
228                 if ((platform == 4) || (platform == 128)) {
229                         // Unix, with libgdiplus
230                         // We use a custom API for this, because there's no easy way
231                         // to get the Stream down to libgdiplus.  So, we wrap the stream
232                         // with a set of delegates.
233                         GDIPlus.GdiPlusStreamHelper sh = new GDIPlus.GdiPlusStreamHelper (stream);
234
235                         st = GDIPlus.GdipLoadImageFromDelegate_linux (sh.GetHeaderDelegate, sh.GetBytesDelegate,
236                                 sh.PutBytesDelegate, sh.SeekDelegate, sh.CloseDelegate, sh.SizeDelegate, out imagePtr);
237                 } else {
238                         // this is MS-land
239                         st = GDIPlus.GdipLoadImageFromStream(new ComIStreamWrapper(stream), out imagePtr);
240                 }
241
242                 GDIPlus.CheckStatus (st);
243                 nativeObject = imagePtr;
244         }
245
246         // non-static   
247         public RectangleF GetBounds (ref GraphicsUnit pageUnit)
248         {       
249                 RectangleF source;                      
250                 
251                 Status status = GDIPlus.GdipGetImageBounds (nativeObject, out source, ref pageUnit);
252                 GDIPlus.CheckStatus (status);           
253                 
254                 return source;
255         }
256         
257         public EncoderParameters GetEncoderParameterList(Guid format)
258         {
259                 Status status;
260                 uint sz;
261
262                 status = GDIPlus.GdipGetEncoderParameterListSize (nativeObject, ref format, out sz);
263                 GDIPlus.CheckStatus (status);
264
265                 IntPtr rawEPList = Marshal.AllocHGlobal ((int) sz);
266                 EncoderParameters eps;
267
268                 try {
269                         status = GDIPlus.GdipGetEncoderParameterList (nativeObject, ref format, sz, rawEPList);
270                         eps = EncoderParameters.FromNativePtr (rawEPList);
271                         GDIPlus.CheckStatus (status);
272                 } catch {
273                         Marshal.FreeHGlobal (rawEPList);
274                         throw;
275                 }
276
277                 Marshal.FreeHGlobal (rawEPList);
278
279                 return eps;
280         }
281         
282         public int GetFrameCount(FrameDimension dimension)
283         {
284                 int count;
285                 Guid guid = dimension.Guid;
286                 Status status = GDIPlus.GdipImageGetFrameCount (nativeObject, ref guid, out  count); 
287
288                 GDIPlus.CheckStatus (status);           
289                 
290                 return count;
291                 
292         }
293         
294         public PropertyItem GetPropertyItem(int propid)
295         {
296                 int propSize;
297                 IntPtr property;
298                 PropertyItem item = new PropertyItem ();
299                 GdipPropertyItem gdipProperty = new GdipPropertyItem ();
300                 Status status;
301                         
302                 status = GDIPlus.GdipGetPropertyItemSize (nativeObject, propid, 
303                                                                         out propSize);
304                 GDIPlus.CheckStatus (status);
305
306                 /* Get PropertyItem */
307                 property = Marshal.AllocHGlobal (propSize);
308                 status = GDIPlus.GdipGetPropertyItem (nativeObject, propid, propSize,  
309                                                                                 property);
310                 GDIPlus.CheckStatus (status);
311                 gdipProperty = (GdipPropertyItem) Marshal.PtrToStructure ((IntPtr)property, 
312                                                                 typeof (GdipPropertyItem));                                             
313                 GdipPropertyItem.MarshalTo (gdipProperty, item);                                                                
314                 
315                 Marshal.FreeHGlobal (property);
316                 return item;
317         }
318         
319         public Image GetThumbnailImage(int thumbWidth, int thumbHeight, Image.GetThumbnailImageAbort callback, IntPtr callbackData)
320         {
321                 Status          status;
322                 Image           ThumbNail;
323                 Graphics        g;
324
325                 ThumbNail=new Bitmap(thumbWidth, thumbHeight);
326                 g=Graphics.FromImage(ThumbNail);
327                 
328                 status = GDIPlus.GdipDrawImageRectRectI(g.nativeObject, nativeObject,
329                                         0, 0, thumbWidth, thumbHeight,
330                                         0, 0, this.Width, this.Height,
331                                         GraphicsUnit.Pixel, IntPtr.Zero, null, IntPtr.Zero);
332                 GDIPlus.CheckStatus (status);
333                 g.Dispose();
334
335                 return(ThumbNail);
336         }
337         
338         
339         public void RemovePropertyItem (int propid)
340         {               
341                 Status status = GDIPlus.GdipRemovePropertyItem (nativeObject, propid);
342                 GDIPlus.CheckStatus (status);                                   
343         }       
344         
345         public void RotateFlip (RotateFlipType rotateFlipType)
346         {                       
347                 Status status = GDIPlus.GdipImageRotateFlip (nativeObject, rotateFlipType);
348                 GDIPlus.CheckStatus (status);                           
349         }
350
351         internal ImageCodecInfo findEncoderForFormat (ImageFormat format)
352         {
353                 ImageCodecInfo[] encoders = ImageCodecInfo.GetImageEncoders();                  
354                 ImageCodecInfo encoder = null;
355                 
356                 if (format.Guid.Equals (ImageFormat.MemoryBmp.Guid))
357                         format = ImageFormat.Bmp;
358         
359                 /* Look for the right encoder for our format*/
360                 for (int i = 0; i < encoders.Length; i++) {
361                         if (encoders[i].FormatID.Equals (format.Guid)) {
362                                 encoder = encoders[i];
363                                 break;
364                         }                       
365                 }
366
367                 return encoder;
368         }
369
370         public void Save (string filename)
371         {
372                 Save (filename, RawFormat);
373         }
374
375         public void Save(string filename, ImageFormat format) 
376         {
377                 ImageCodecInfo encoder = findEncoderForFormat (format);
378
379                 if (encoder == null)
380                         throw new ArgumentException ("No codec available for format:" + format.Guid);
381
382                 Save (filename, encoder, null);
383         }
384
385         public void Save(string filename, ImageCodecInfo encoder, EncoderParameters encoderParams)
386         {
387                 Status st;
388                 Guid guid = encoder.Clsid;
389
390                 if (encoderParams == null) {
391                         st = GDIPlus.GdipSaveImageToFile (nativeObject, filename, ref guid, IntPtr.Zero);
392                 } else {
393                         IntPtr nativeEncoderParams = encoderParams.ToNativePtr ();
394                         st = GDIPlus.GdipSaveImageToFile (nativeObject, filename, ref guid, nativeEncoderParams);
395                         Marshal.FreeHGlobal (nativeEncoderParams);
396                 }
397
398                 GDIPlus.CheckStatus (st);
399         }
400
401         public void Save (Stream stream, ImageFormat format)
402         {
403                 ImageCodecInfo encoder = findEncoderForFormat (format);
404
405                 if (encoder == null)
406                         throw new ArgumentException ("No codec available for format:" + format.Guid);
407
408                 Save (stream, encoder, null);
409         }
410
411         public void Save(Stream stream, ImageCodecInfo encoder, EncoderParameters encoderParams)
412         {
413                 Status st;
414                 IntPtr nativeEncoderParams;
415                 Guid guid = encoder.Clsid;
416
417                 if (encoderParams == null)
418                         nativeEncoderParams = IntPtr.Zero;
419                 else
420                         nativeEncoderParams = encoderParams.ToNativePtr ();
421
422                 try {
423                         // check for Unix platforms - see FAQ for more details
424                         // http://www.mono-project.com/FAQ:_Technical#How_to_detect_the_execution_platform_.3F
425                         int platform = (int) Environment.OSVersion.Platform;
426                         if ((platform == 4) || (platform == 128)) {
427                                 GDIPlus.GdiPlusStreamHelper sh = new GDIPlus.GdiPlusStreamHelper (stream);
428                                 st = GDIPlus.GdipSaveImageToDelegate_linux (nativeObject, sh.GetBytesDelegate, sh.PutBytesDelegate,
429                                         sh.SeekDelegate, sh.CloseDelegate, sh.SizeDelegate, ref guid, nativeEncoderParams);
430                         }
431                         else
432                                 st = GDIPlus.GdipSaveImageToStream(new HandleRef(this, nativeObject), new ComIStreamWrapper(stream), ref guid, new HandleRef(encoderParams, nativeEncoderParams));
433                 }
434                 finally {
435                         if (nativeEncoderParams != IntPtr.Zero)
436                                 Marshal.FreeHGlobal (nativeEncoderParams);
437                 }
438                 
439                 GDIPlus.CheckStatus (st);               
440         }
441         
442         public void SaveAdd (EncoderParameters encoderParams)
443         {
444                 Status st;
445                 
446                 IntPtr nativeEncoderParams = encoderParams.ToNativePtr ();
447                 st = GDIPlus.GdipSaveAdd (nativeObject, nativeEncoderParams);
448                 Marshal.FreeHGlobal (nativeEncoderParams);
449                 GDIPlus.CheckStatus (st);
450         }
451                 
452         public void SaveAdd (Image image, EncoderParameters encoderParams)
453         {
454                 Status st;
455                 
456                 IntPtr nativeEncoderParams = encoderParams.ToNativePtr ();
457                 st = GDIPlus.GdipSaveAddImage (nativeObject, image.NativeObject, nativeEncoderParams);
458                 Marshal.FreeHGlobal (nativeEncoderParams);
459                 GDIPlus.CheckStatus (st);
460         }
461                 
462         public int SelectActiveFrame(FrameDimension dimension, int frameIndex)
463         {
464                 Guid guid = dimension.Guid;             
465                 Status st = GDIPlus.GdipImageSelectActiveFrame (nativeObject, ref guid, frameIndex);
466                 
467                 GDIPlus.CheckStatus (st);                       
468                 
469                 return frameIndex;              
470         }
471         
472         public void SetPropertyItem(PropertyItem propitem)
473         {
474                 IntPtr property;
475                 int size = Marshal.SizeOf (typeof(GdipPropertyItem));
476                 property = Marshal.AllocHGlobal (size);
477
478                 Marshal.StructureToPtr (propitem, property, true);
479                 Status status = GDIPlus.GdipSetPropertyItem (nativeObject, property);
480                 GDIPlus.CheckStatus (status);
481         }
482
483         // properties   
484         [Browsable (false)]
485         public int Flags {
486                 get {
487                         int flags;
488                         
489                         Status status = GDIPlus.GdipGetImageFlags (nativeObject, out flags);                    
490                         GDIPlus.CheckStatus (status);                                           
491                         return flags;                   
492                 }
493         }
494         
495         [Browsable (false)]
496         public Guid[] FrameDimensionsList {
497                 get {
498                         uint found;
499                         Status status = GDIPlus.GdipImageGetFrameDimensionsCount (nativeObject, out found);
500                         GDIPlus.CheckStatus (status);
501                         Guid [] guid = new Guid [found];
502                         status = GDIPlus.GdipImageGetFrameDimensionsList (nativeObject, guid, found);
503                         GDIPlus.CheckStatus (status);  
504                         return guid;
505                 }
506         }
507
508         [DefaultValue (false)]
509         [Browsable (false)]
510         [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
511         public int Height {
512                 get {
513                         int height;                     
514                         Status status = GDIPlus.GdipGetImageHeight (nativeObject, out height);          
515                         GDIPlus.CheckStatus (status);                   
516                         
517                         return height;
518                 }
519         }
520         
521         public float HorizontalResolution {
522                 get {
523                         float resolution;
524                         
525                         Status status = GDIPlus.GdipGetImageHorizontalResolution (nativeObject, out resolution);                        
526                         GDIPlus.CheckStatus (status);                   
527                         
528                         return resolution;
529                 }
530         }
531         
532         [Browsable (false)]
533         public ColorPalette Palette {
534                 get {                                                   
535                         return retrieveGDIPalette();
536                 }
537                 set {
538                         storeGDIPalette(value);
539                 }
540         }
541
542         internal ColorPalette retrieveGDIPalette()
543         {
544                 ColorPalette ret = new ColorPalette();
545                 if (!IsIndexedPixelFormat (PixelFormat)) {
546                         return ret;
547                 }
548                 Status st;
549                 int bytes;
550
551                 st = GDIPlus.GdipGetImagePaletteSize (nativeObject, out bytes);
552                 GDIPlus.CheckStatus (st);
553                 IntPtr palette_data = Marshal.AllocHGlobal (bytes);
554                 try {
555                         st = GDIPlus.GdipGetImagePalette (nativeObject, palette_data, bytes);
556                         GDIPlus.CheckStatus (st);
557                         ret.setFromGDIPalette (palette_data);
558                         return ret;
559                 }
560
561                 finally {
562                         Marshal.FreeHGlobal (palette_data);
563                 }
564         }
565
566         internal void storeGDIPalette(ColorPalette palette)
567         {
568                 if (palette == null) {
569                         throw new ArgumentNullException("palette");
570                 }
571                 IntPtr palette_data = palette.getGDIPalette();
572                 if (palette_data == IntPtr.Zero) {
573                         return;
574                 }
575
576                 try {
577                         Status st = GDIPlus.GdipSetImagePalette (nativeObject, palette_data);
578                         GDIPlus.CheckStatus (st);
579                 }
580
581                 finally {
582                         Marshal.FreeHGlobal(palette_data);
583                 }
584         }
585
586                 
587         public SizeF PhysicalDimension {
588                 get {
589                         float width,  height;
590                         Status status = GDIPlus.GdipGetImageDimension (nativeObject, out width, out height);            
591                         GDIPlus.CheckStatus (status);                   
592                         
593                         return new SizeF (width, height);
594                 }
595         }
596         
597         public PixelFormat PixelFormat {
598                 get {                   
599                         PixelFormat pixFormat;                          
600                         Status status = GDIPlus.GdipGetImagePixelFormat (nativeObject, out pixFormat);          
601                         GDIPlus.CheckStatus (status);                   
602                         
603                         return pixFormat;
604                 }               
605         }
606         
607         [Browsable (false)]
608         public int[] PropertyIdList {
609                 get {
610                         uint propNumbers;
611                         
612                         Status status = GDIPlus.GdipGetPropertyCount (nativeObject, 
613                                                                         out propNumbers);                       
614                         GDIPlus.CheckStatus (status);
615                         
616                         int [] idList = new int [propNumbers];
617                         status = GDIPlus.GdipGetPropertyIdList (nativeObject, 
618                                                                 propNumbers, idList);
619                         GDIPlus.CheckStatus (status);
620                         
621                         return idList;
622                 }
623         }
624         
625         [Browsable (false)]
626         public PropertyItem[] PropertyItems {
627                 get {
628                         int propNums, propsSize, propSize;
629                         IntPtr properties, propPtr;
630                         PropertyItem[] items;
631                         GdipPropertyItem gdipProperty = new GdipPropertyItem ();
632                         Status status;
633                         
634                         status = GDIPlus.GdipGetPropertySize (nativeObject, out propsSize, out propNums);
635                         GDIPlus.CheckStatus (status);
636
637                         items =  new PropertyItem [propNums];
638                         
639                         if (propNums == 0)
640                                 return items;                   
641                                         
642                         /* Get PropertyItem list*/
643                         properties = Marshal.AllocHGlobal (propsSize);
644                         status = GDIPlus.GdipGetAllPropertyItems (nativeObject, propsSize, 
645                                                                 propNums, properties);
646                         GDIPlus.CheckStatus (status);
647
648                         propSize = Marshal.SizeOf (gdipProperty);                       
649                         propPtr = properties;
650                         
651                         for (int i = 0; i < propNums; i++, propPtr = new IntPtr (propPtr.ToInt64 () + propSize))
652                         {
653                                 gdipProperty = (GdipPropertyItem) Marshal.PtrToStructure 
654                                                 (propPtr, typeof (GdipPropertyItem));                                           
655                                 items [i] = new PropertyItem ();
656                                 GdipPropertyItem.MarshalTo (gdipProperty, items [i]);                                                           
657                         }
658                         
659                         Marshal.FreeHGlobal (properties);
660                         return items;
661                 }
662         }
663
664         public ImageFormat RawFormat {
665                 get {
666                         Guid guid;
667                         Status st = GDIPlus.GdipGetImageRawFormat (nativeObject, out guid);
668                         
669                         GDIPlus.CheckStatus (st);
670                         return new ImageFormat (guid);                  
671                 }
672         }
673         
674         public Size Size {
675                 get {
676                         return new Size(Width, Height);
677                 }
678         }
679         
680         public float VerticalResolution {
681                 get {
682                         float resolution;
683                         
684                         Status status = GDIPlus.GdipGetImageVerticalResolution (nativeObject, out resolution);
685                         GDIPlus.CheckStatus (status);
686
687                         return resolution;
688                 }
689         }
690
691         [DefaultValue (false)]
692         [Browsable (false)]
693         [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
694         public int Width {
695                 get {
696                         int width;                      
697                         Status status = GDIPlus.GdipGetImageWidth (nativeObject, out width);            
698                         GDIPlus.CheckStatus (status);                   
699                         
700                         return width;
701                 }
702         }
703         
704         internal IntPtr NativeObject{
705                 get{
706                         return nativeObject;
707                 }
708                 set     {
709                         nativeObject = value;
710                 }
711         }
712         
713         public void Dispose ()
714         {
715                 Dispose (true);
716                 System.GC.SuppressFinalize (this);
717         }
718
719         ~Image ()
720         {
721                 Dispose (false);
722         }
723
724         private void DisposeResources ()
725         {
726                 Status status = GDIPlus.GdipDisposeImage (nativeObject);
727                 GDIPlus.CheckStatus (status);           
728         }
729         
730         protected virtual void Dispose (bool disposing)
731         {
732                 if (nativeObject != IntPtr.Zero){
733                         DisposeResources ();
734                         nativeObject = IntPtr.Zero;
735                 }
736         }
737         
738         public virtual object Clone()
739         {                               
740
741                 IntPtr newimage = IntPtr.Zero;
742                 
743                 if (!(this is Bitmap)) 
744                         throw new NotImplementedException (); 
745                 
746                 Status status = GDIPlus.GdipCloneImage (NativeObject, out newimage);                    
747                 GDIPlus.CheckStatus (status);                   
748
749                 if (this is Bitmap){
750                         return new Bitmap (newimage);
751                 }
752                 
753                 throw new NotImplementedException ();           
754         }
755
756 }
757
758 }