2010-04-07 Jb Evain <jbevain@novell.com>
[mcs.git] / class / System.Drawing / System.Drawing / Image.cs
blob0c9a0694db0d05463a57d4ff6c04e0c820eb27ff
1 //
2 // System.Drawing.Image.cs
3 //
4 // Authors: Christian Meyer (Christian.Meyer@cs.tum.edu)
5 // Alexandre Pigolkine (pigolkine@gmx.de)
6 // Jordi Mas i Hernandez (jordi@ximian.com)
7 // Sanjay Gupta (gsanjay@novell.com)
8 // Ravindra (rkumar@novell.com)
9 // Sebastien Pouliot <sebastien@ximian.com>
11 // Copyright (C) 2002 Ximian, Inc. http://www.ximian.com
12 // Copyright (C) 2004, 2007 Novell, Inc (http://www.novell.com)
14 // Permission is hereby granted, free of charge, to any person obtaining
15 // a copy of this software and associated documentation files (the
16 // "Software"), to deal in the Software without restriction, including
17 // without limitation the rights to use, copy, modify, merge, publish,
18 // distribute, sublicense, and/or sell copies of the Software, and to
19 // permit persons to whom the Software is furnished to do so, subject to
20 // the following conditions:
21 //
22 // The above copyright notice and this permission notice shall be
23 // included in all copies or substantial portions of the Software.
24 //
25 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
26 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
27 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
28 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
29 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
30 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
31 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 using System;
35 using System.Runtime.Remoting;
36 using System.Runtime.Serialization;
37 using System.Runtime.InteropServices;
38 using System.ComponentModel;
39 using System.Drawing.Imaging;
40 using System.IO;
41 using System.Reflection;
43 namespace System.Drawing
45 [Serializable]
46 [ComVisible (true)]
47 [Editor ("System.Drawing.Design.ImageEditor, " + Consts.AssemblySystem_Drawing_Design, typeof (System.Drawing.Design.UITypeEditor))]
48 [TypeConverter (typeof(ImageConverter))]
49 [ImmutableObject (true)]
50 public abstract class Image : MarshalByRefObject, IDisposable , ICloneable, ISerializable
52 public delegate bool GetThumbnailImageAbort();
53 #if NET_2_0
54 private object tag;
55 #endif
57 internal IntPtr nativeObject = IntPtr.Zero;
58 // when using MS GDI+ and IStream we must ensure the stream stays alive for all the life of the Image
59 // http://groups.google.com/group/microsoft.public.win32.programmer.gdi/browse_thread/thread/4967097db1469a27/4d36385b83532126?lnk=st&q=IStream+gdi&rnum=3&hl=en#4d36385b83532126
60 internal Stream stream;
63 // constructor
64 internal Image()
68 internal Image (SerializationInfo info, StreamingContext context)
70 foreach (SerializationEntry serEnum in info) {
71 if (String.Compare(serEnum.Name, "Data", true) == 0) {
72 byte[] bytes = (byte[]) serEnum.Value;
74 if (bytes != null) {
75 MemoryStream ms = new MemoryStream (bytes);
76 nativeObject = InitFromStream (ms);
77 // under Win32 stream is owned by SD/GDI+ code
78 if (GDIPlus.RunningOnWindows ())
79 stream = ms;
85 // FIXME - find out how metafiles (another decoder-only codec) are handled
86 void ISerializable.GetObjectData (SerializationInfo si, StreamingContext context)
88 using (MemoryStream ms = new MemoryStream ()) {
89 // Icon is a decoder-only codec
90 if (RawFormat.Equals (ImageFormat.Icon)) {
91 Save (ms, ImageFormat.Png);
92 } else {
93 Save (ms, RawFormat);
95 si.AddValue ("Data", ms.ToArray ());
99 // public methods
100 // static
101 public static Image FromFile(string filename)
103 return FromFile (filename, false);
106 public static Image FromFile(string filename, bool useEmbeddedColorManagement)
108 IntPtr imagePtr;
109 Status st;
111 if (!File.Exists (filename))
112 throw new FileNotFoundException (filename);
114 if (useEmbeddedColorManagement)
115 st = GDIPlus.GdipLoadImageFromFileICM (filename, out imagePtr);
116 else
117 st = GDIPlus.GdipLoadImageFromFile (filename, out imagePtr);
118 GDIPlus.CheckStatus (st);
120 return CreateFromHandle (imagePtr);
123 public static Bitmap FromHbitmap(IntPtr hbitmap)
125 return FromHbitmap (hbitmap, IntPtr.Zero);
128 public static Bitmap FromHbitmap(IntPtr hbitmap, IntPtr hpalette)
130 IntPtr imagePtr;
131 Status st;
133 st = GDIPlus.GdipCreateBitmapFromHBITMAP (hbitmap, hpalette, out imagePtr);
135 GDIPlus.CheckStatus (st);
136 return new Bitmap (imagePtr);
139 // note: FromStream can return either a Bitmap or Metafile instance
141 public static Image FromStream (Stream stream)
143 return LoadFromStream (stream, false);
146 [MonoLimitation ("useEmbeddedColorManagement isn't supported.")]
147 public static Image FromStream (Stream stream, bool useEmbeddedColorManagement)
149 return LoadFromStream (stream, false);
152 // See http://support.microsoft.com/default.aspx?scid=kb;en-us;831419 for performance discussion
153 [MonoLimitation ("useEmbeddedColorManagement and validateImageData aren't supported.")]
154 public static Image FromStream (Stream stream, bool useEmbeddedColorManagement, bool validateImageData)
156 return LoadFromStream (stream, false);
159 internal static Image LoadFromStream (Stream stream, bool keepAlive)
161 if (stream == null)
162 throw new ArgumentNullException ("stream");
164 Image img = CreateFromHandle (InitFromStream (stream));
166 // Under Windows, we may need to keep a reference on the stream as long as the image is alive
167 // (GDI+ seems to use a lazy loader)
168 if (keepAlive && GDIPlus.RunningOnWindows ())
169 img.stream = stream;
171 return img;
174 internal static Image CreateFromHandle (IntPtr handle)
176 ImageType type;
177 GDIPlus.CheckStatus (GDIPlus.GdipGetImageType (handle, out type));
178 switch (type) {
179 case ImageType.Bitmap:
180 return new Bitmap (handle);
181 case ImageType.Metafile:
182 return new Metafile (handle);
183 default:
184 throw new NotSupportedException (Locale.GetText ("Unknown image type."));
188 public static int GetPixelFormatSize(PixelFormat pixfmt)
190 int result = 0;
191 switch (pixfmt) {
192 case PixelFormat.Format16bppArgb1555:
193 case PixelFormat.Format16bppGrayScale:
194 case PixelFormat.Format16bppRgb555:
195 case PixelFormat.Format16bppRgb565:
196 result = 16;
197 break;
198 case PixelFormat.Format1bppIndexed:
199 result = 1;
200 break;
201 case PixelFormat.Format24bppRgb:
202 result = 24;
203 break;
204 case PixelFormat.Format32bppArgb:
205 case PixelFormat.Format32bppPArgb:
206 case PixelFormat.Format32bppRgb:
207 result = 32;
208 break;
209 case PixelFormat.Format48bppRgb:
210 result = 48;
211 break;
212 case PixelFormat.Format4bppIndexed:
213 result = 4;
214 break;
215 case PixelFormat.Format64bppArgb:
216 case PixelFormat.Format64bppPArgb:
217 result = 64;
218 break;
219 case PixelFormat.Format8bppIndexed:
220 result = 8;
221 break;
223 return result;
226 public static bool IsAlphaPixelFormat(PixelFormat pixfmt)
228 bool result = false;
229 switch (pixfmt) {
230 case PixelFormat.Format16bppArgb1555:
231 case PixelFormat.Format32bppArgb:
232 case PixelFormat.Format32bppPArgb:
233 case PixelFormat.Format64bppArgb:
234 case PixelFormat.Format64bppPArgb:
235 result = true;
236 break;
237 case PixelFormat.Format16bppGrayScale:
238 case PixelFormat.Format16bppRgb555:
239 case PixelFormat.Format16bppRgb565:
240 case PixelFormat.Format1bppIndexed:
241 case PixelFormat.Format24bppRgb:
242 case PixelFormat.Format32bppRgb:
243 case PixelFormat.Format48bppRgb:
244 case PixelFormat.Format4bppIndexed:
245 case PixelFormat.Format8bppIndexed:
246 result = false;
247 break;
249 return result;
252 public static bool IsCanonicalPixelFormat (PixelFormat pixfmt)
254 return ((pixfmt & PixelFormat.Canonical) != 0);
257 public static bool IsExtendedPixelFormat (PixelFormat pixfmt)
259 return ((pixfmt & PixelFormat.Extended) != 0);
262 internal static IntPtr InitFromStream (Stream stream)
264 if (stream == null)
265 throw new ArgumentException ("stream");
267 IntPtr imagePtr;
268 Status st;
270 // Seeking required
271 if (!stream.CanSeek) {
272 byte[] buffer = new byte[256];
273 int index = 0;
274 int count;
276 do {
277 if (buffer.Length < index + 256) {
278 byte[] newBuffer = new byte[buffer.Length * 2];
279 Array.Copy(buffer, newBuffer, buffer.Length);
280 buffer = newBuffer;
282 count = stream.Read(buffer, index, 256);
283 index += count;
285 while (count != 0);
287 stream = new MemoryStream(buffer, 0, index);
290 if (GDIPlus.RunningOnUnix ()) {
291 // Unix, with libgdiplus
292 // We use a custom API for this, because there's no easy way
293 // to get the Stream down to libgdiplus. So, we wrap the stream
294 // with a set of delegates.
295 GDIPlus.GdiPlusStreamHelper sh = new GDIPlus.GdiPlusStreamHelper (stream, true);
297 st = GDIPlus.GdipLoadImageFromDelegate_linux (sh.GetHeaderDelegate, sh.GetBytesDelegate,
298 sh.PutBytesDelegate, sh.SeekDelegate, sh.CloseDelegate, sh.SizeDelegate, out imagePtr);
299 } else {
300 st = GDIPlus.GdipLoadImageFromStream (new ComIStreamWrapper (stream), out imagePtr);
303 GDIPlus.CheckStatus (st);
304 return imagePtr;
307 // non-static
308 public RectangleF GetBounds (ref GraphicsUnit pageUnit)
310 RectangleF source;
312 Status status = GDIPlus.GdipGetImageBounds (nativeObject, out source, ref pageUnit);
313 GDIPlus.CheckStatus (status);
315 return source;
318 public EncoderParameters GetEncoderParameterList(Guid encoder)
320 Status status;
321 uint sz;
323 status = GDIPlus.GdipGetEncoderParameterListSize (nativeObject, ref encoder, out sz);
324 GDIPlus.CheckStatus (status);
326 IntPtr rawEPList = Marshal.AllocHGlobal ((int) sz);
327 EncoderParameters eps;
329 try {
330 status = GDIPlus.GdipGetEncoderParameterList (nativeObject, ref encoder, sz, rawEPList);
331 eps = EncoderParameters.FromNativePtr (rawEPList);
332 GDIPlus.CheckStatus (status);
334 finally {
335 Marshal.FreeHGlobal (rawEPList);
338 return eps;
341 public int GetFrameCount (FrameDimension dimension)
343 uint count;
344 Guid guid = dimension.Guid;
346 Status status = GDIPlus.GdipImageGetFrameCount (nativeObject, ref guid, out count);
347 GDIPlus.CheckStatus (status);
349 return (int) count;
352 public PropertyItem GetPropertyItem(int propid)
354 int propSize;
355 IntPtr property;
356 PropertyItem item = new PropertyItem ();
357 GdipPropertyItem gdipProperty = new GdipPropertyItem ();
358 Status status;
360 status = GDIPlus.GdipGetPropertyItemSize (nativeObject, propid,
361 out propSize);
362 GDIPlus.CheckStatus (status);
364 /* Get PropertyItem */
365 property = Marshal.AllocHGlobal (propSize);
366 try {
367 status = GDIPlus.GdipGetPropertyItem (nativeObject, propid, propSize, property);
368 GDIPlus.CheckStatus (status);
369 gdipProperty = (GdipPropertyItem) Marshal.PtrToStructure (property,
370 typeof (GdipPropertyItem));
371 GdipPropertyItem.MarshalTo (gdipProperty, item);
373 finally {
374 Marshal.FreeHGlobal (property);
376 return item;
379 public Image GetThumbnailImage (int thumbWidth, int thumbHeight, Image.GetThumbnailImageAbort callback, IntPtr callbackData)
381 if ((thumbWidth <= 0) || (thumbHeight <= 0))
382 throw new OutOfMemoryException ("Invalid thumbnail size");
384 Image ThumbNail = new Bitmap (thumbWidth, thumbHeight);
386 using (Graphics g = Graphics.FromImage (ThumbNail)) {
387 Status status = GDIPlus.GdipDrawImageRectRectI (g.nativeObject, nativeObject,
388 0, 0, thumbWidth, thumbHeight,
389 0, 0, this.Width, this.Height,
390 GraphicsUnit.Pixel, IntPtr.Zero, null, IntPtr.Zero);
392 GDIPlus.CheckStatus (status);
395 return ThumbNail;
399 public void RemovePropertyItem (int propid)
401 Status status = GDIPlus.GdipRemovePropertyItem (nativeObject, propid);
402 GDIPlus.CheckStatus (status);
405 public void RotateFlip (RotateFlipType rotateFlipType)
407 Status status = GDIPlus.GdipImageRotateFlip (nativeObject, rotateFlipType);
408 GDIPlus.CheckStatus (status);
411 internal ImageCodecInfo findEncoderForFormat (ImageFormat format)
413 ImageCodecInfo[] encoders = ImageCodecInfo.GetImageEncoders();
414 ImageCodecInfo encoder = null;
416 if (format.Guid.Equals (ImageFormat.MemoryBmp.Guid))
417 format = ImageFormat.Png;
419 /* Look for the right encoder for our format*/
420 for (int i = 0; i < encoders.Length; i++) {
421 if (encoders[i].FormatID.Equals (format.Guid)) {
422 encoder = encoders[i];
423 break;
427 return encoder;
430 public void Save (string filename)
432 Save (filename, RawFormat);
435 public void Save(string filename, ImageFormat format)
437 ImageCodecInfo encoder = findEncoderForFormat (format);
438 if (encoder == null) {
439 // second chance
440 encoder = findEncoderForFormat (RawFormat);
441 if (encoder == null) {
442 string msg = Locale.GetText ("No codec available for saving format '{0}'.", format.Guid);
443 throw new ArgumentException (msg, "format");
446 Save (filename, encoder, null);
449 public void Save(string filename, ImageCodecInfo encoder, EncoderParameters encoderParams)
451 Status st;
452 Guid guid = encoder.Clsid;
454 if (encoderParams == null) {
455 st = GDIPlus.GdipSaveImageToFile (nativeObject, filename, ref guid, IntPtr.Zero);
456 } else {
457 IntPtr nativeEncoderParams = encoderParams.ToNativePtr ();
458 st = GDIPlus.GdipSaveImageToFile (nativeObject, filename, ref guid, nativeEncoderParams);
459 Marshal.FreeHGlobal (nativeEncoderParams);
462 GDIPlus.CheckStatus (st);
465 public void Save (Stream stream, ImageFormat format)
467 ImageCodecInfo encoder = findEncoderForFormat (format);
469 if (encoder == null)
470 throw new ArgumentException ("No codec available for format:" + format.Guid);
472 Save (stream, encoder, null);
475 public void Save(Stream stream, ImageCodecInfo encoder, EncoderParameters encoderParams)
477 Status st;
478 IntPtr nativeEncoderParams;
479 Guid guid = encoder.Clsid;
481 if (encoderParams == null)
482 nativeEncoderParams = IntPtr.Zero;
483 else
484 nativeEncoderParams = encoderParams.ToNativePtr ();
486 try {
487 if (GDIPlus.RunningOnUnix ()) {
488 GDIPlus.GdiPlusStreamHelper sh = new GDIPlus.GdiPlusStreamHelper (stream, false);
489 st = GDIPlus.GdipSaveImageToDelegate_linux (nativeObject, sh.GetBytesDelegate, sh.PutBytesDelegate,
490 sh.SeekDelegate, sh.CloseDelegate, sh.SizeDelegate, ref guid, nativeEncoderParams);
491 } else {
492 st = GDIPlus.GdipSaveImageToStream (new HandleRef (this, nativeObject),
493 new ComIStreamWrapper (stream), ref guid, new HandleRef (encoderParams, nativeEncoderParams));
496 finally {
497 if (nativeEncoderParams != IntPtr.Zero)
498 Marshal.FreeHGlobal (nativeEncoderParams);
501 GDIPlus.CheckStatus (st);
504 public void SaveAdd (EncoderParameters encoderParams)
506 Status st;
508 IntPtr nativeEncoderParams = encoderParams.ToNativePtr ();
509 st = GDIPlus.GdipSaveAdd (nativeObject, nativeEncoderParams);
510 Marshal.FreeHGlobal (nativeEncoderParams);
511 GDIPlus.CheckStatus (st);
514 public void SaveAdd (Image image, EncoderParameters encoderParams)
516 Status st;
518 IntPtr nativeEncoderParams = encoderParams.ToNativePtr ();
519 st = GDIPlus.GdipSaveAddImage (nativeObject, image.NativeObject, nativeEncoderParams);
520 Marshal.FreeHGlobal (nativeEncoderParams);
521 GDIPlus.CheckStatus (st);
524 public int SelectActiveFrame(FrameDimension dimension, int frameIndex)
526 Guid guid = dimension.Guid;
527 Status st = GDIPlus.GdipImageSelectActiveFrame (nativeObject, ref guid, frameIndex);
529 GDIPlus.CheckStatus (st);
531 return frameIndex;
534 public void SetPropertyItem(PropertyItem propitem)
536 throw new NotImplementedException ();
538 GdipPropertyItem pi = new GdipPropertyItem ();
539 GdipPropertyItem.MarshalTo (pi, propitem);
540 unsafe {
541 Status status = GDIPlus.GdipSetPropertyItem (nativeObject, &pi);
543 GDIPlus.CheckStatus (status);
548 // properties
549 [Browsable (false)]
550 public int Flags {
551 get {
552 int flags;
554 Status status = GDIPlus.GdipGetImageFlags (nativeObject, out flags);
555 GDIPlus.CheckStatus (status);
556 return flags;
560 [Browsable (false)]
561 public Guid[] FrameDimensionsList {
562 get {
563 uint found;
564 Status status = GDIPlus.GdipImageGetFrameDimensionsCount (nativeObject, out found);
565 GDIPlus.CheckStatus (status);
566 Guid [] guid = new Guid [found];
567 status = GDIPlus.GdipImageGetFrameDimensionsList (nativeObject, guid, found);
568 GDIPlus.CheckStatus (status);
569 return guid;
573 [DefaultValue (false)]
574 [Browsable (false)]
575 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
576 public int Height {
577 get {
578 uint height;
579 Status status = GDIPlus.GdipGetImageHeight (nativeObject, out height);
580 GDIPlus.CheckStatus (status);
582 return (int)height;
586 public float HorizontalResolution {
587 get {
588 float resolution;
590 Status status = GDIPlus.GdipGetImageHorizontalResolution (nativeObject, out resolution);
591 GDIPlus.CheckStatus (status);
593 return resolution;
597 [Browsable (false)]
598 public ColorPalette Palette {
599 get {
600 return retrieveGDIPalette();
602 set {
603 storeGDIPalette(value);
607 internal ColorPalette retrieveGDIPalette()
609 int bytes;
610 ColorPalette ret = new ColorPalette ();
612 Status st = GDIPlus.GdipGetImagePaletteSize (nativeObject, out bytes);
613 GDIPlus.CheckStatus (st);
614 IntPtr palette_data = Marshal.AllocHGlobal (bytes);
615 try {
616 st = GDIPlus.GdipGetImagePalette (nativeObject, palette_data, bytes);
617 GDIPlus.CheckStatus (st);
618 ret.setFromGDIPalette (palette_data);
619 return ret;
622 finally {
623 Marshal.FreeHGlobal (palette_data);
627 internal void storeGDIPalette(ColorPalette palette)
629 if (palette == null) {
630 throw new ArgumentNullException("palette");
632 IntPtr palette_data = palette.getGDIPalette();
633 if (palette_data == IntPtr.Zero) {
634 return;
637 try {
638 Status st = GDIPlus.GdipSetImagePalette (nativeObject, palette_data);
639 GDIPlus.CheckStatus (st);
642 finally {
643 Marshal.FreeHGlobal(palette_data);
648 public SizeF PhysicalDimension {
649 get {
650 float width, height;
651 Status status = GDIPlus.GdipGetImageDimension (nativeObject, out width, out height);
652 GDIPlus.CheckStatus (status);
654 return new SizeF (width, height);
658 public PixelFormat PixelFormat {
659 get {
660 PixelFormat pixFormat;
661 Status status = GDIPlus.GdipGetImagePixelFormat (nativeObject, out pixFormat);
662 GDIPlus.CheckStatus (status);
664 return pixFormat;
668 [Browsable (false)]
669 public int[] PropertyIdList {
670 get {
671 uint propNumbers;
673 Status status = GDIPlus.GdipGetPropertyCount (nativeObject,
674 out propNumbers);
675 GDIPlus.CheckStatus (status);
677 int [] idList = new int [propNumbers];
678 status = GDIPlus.GdipGetPropertyIdList (nativeObject,
679 propNumbers, idList);
680 GDIPlus.CheckStatus (status);
682 return idList;
686 [Browsable (false)]
687 public PropertyItem[] PropertyItems {
688 get {
689 int propNums, propsSize, propSize;
690 IntPtr properties, propPtr;
691 PropertyItem[] items;
692 GdipPropertyItem gdipProperty = new GdipPropertyItem ();
693 Status status;
695 status = GDIPlus.GdipGetPropertySize (nativeObject, out propsSize, out propNums);
696 GDIPlus.CheckStatus (status);
698 items = new PropertyItem [propNums];
700 if (propNums == 0)
701 return items;
703 /* Get PropertyItem list*/
704 properties = Marshal.AllocHGlobal (propsSize * propNums);
705 try {
706 status = GDIPlus.GdipGetAllPropertyItems (nativeObject, propsSize,
707 propNums, properties);
708 GDIPlus.CheckStatus (status);
710 propSize = Marshal.SizeOf (gdipProperty);
711 propPtr = properties;
713 for (int i = 0; i < propNums; i++, propPtr = new IntPtr (propPtr.ToInt64 () + propSize)) {
714 gdipProperty = (GdipPropertyItem) Marshal.PtrToStructure
715 (propPtr, typeof (GdipPropertyItem));
716 items [i] = new PropertyItem ();
717 GdipPropertyItem.MarshalTo (gdipProperty, items [i]);
720 finally {
721 Marshal.FreeHGlobal (properties);
723 return items;
727 public ImageFormat RawFormat {
728 get {
729 Guid guid;
730 Status st = GDIPlus.GdipGetImageRawFormat (nativeObject, out guid);
732 GDIPlus.CheckStatus (st);
733 return new ImageFormat (guid);
737 public Size Size {
738 get {
739 return new Size(Width, Height);
743 #if NET_2_0
744 [DefaultValue (null)]
745 [LocalizableAttribute(false)]
746 [BindableAttribute(true)]
747 [TypeConverter (typeof (StringConverter))]
748 public object Tag {
749 get { return tag; }
750 set { tag = value; }
752 #endif
753 public float VerticalResolution {
754 get {
755 float resolution;
757 Status status = GDIPlus.GdipGetImageVerticalResolution (nativeObject, out resolution);
758 GDIPlus.CheckStatus (status);
760 return resolution;
764 [DefaultValue (false)]
765 [Browsable (false)]
766 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
767 public int Width {
768 get {
769 uint width;
770 Status status = GDIPlus.GdipGetImageWidth (nativeObject, out width);
771 GDIPlus.CheckStatus (status);
773 return (int)width;
777 internal IntPtr NativeObject{
778 get{
779 return nativeObject;
781 set {
782 nativeObject = value;
786 public void Dispose ()
788 Dispose (true);
789 System.GC.SuppressFinalize (this);
792 ~Image ()
794 Dispose (false);
797 protected virtual void Dispose (bool disposing)
799 if (GDIPlus.GdiPlusToken != 0 && nativeObject != IntPtr.Zero) {
800 Status status = GDIPlus.GdipDisposeImage (nativeObject);
801 // dispose the stream (set under Win32 only if SD owns the stream) and ...
802 if (stream != null) {
803 stream.Close ();
804 stream = null;
806 // ... set nativeObject to null before (possibly) throwing an exception
807 nativeObject = IntPtr.Zero;
808 GDIPlus.CheckStatus (status);
812 public object Clone ()
814 if (GDIPlus.RunningOnWindows () && stream != null)
815 return CloneFromStream ();
817 IntPtr newimage = IntPtr.Zero;
818 Status status = GDIPlus.GdipCloneImage (NativeObject, out newimage);
819 GDIPlus.CheckStatus (status);
821 if (this is Bitmap)
822 return new Bitmap (newimage);
823 else
824 return new Metafile (newimage);
827 // On win32, when cloning images that were originally created from a stream, we need to
828 // clone both the image and the stream to make sure the gc doesn't kill it
829 // (when using MS GDI+ and IStream we must ensure the stream stays alive for all the life of the Image)
830 object CloneFromStream ()
832 byte[] bytes = new byte [stream.Length];
833 MemoryStream ms = new MemoryStream (bytes);
834 int count = (stream.Length < 4096 ? (int) stream.Length : 4096);
835 byte[] buffer = new byte[count];
836 stream.Position = 0;
837 do {
838 count = stream.Read (buffer, 0, count);
839 ms.Write (buffer, 0, count);
840 } while (count == 4096);
842 IntPtr newimage = IntPtr.Zero;
843 newimage = InitFromStream (ms);
845 if (this is Bitmap)
846 return new Bitmap (newimage, ms);
847 else
848 return new Metafile (newimage, ms);