2 // System.Drawing.Image.cs
4 // Copyright (C) 2002 Ximian, Inc. http://www.ximian.com
5 // Copyright (C) 2004 Novell, Inc. http://www.novell.com
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)
15 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
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:
25 // The above copyright notice and this permission notice shall be
26 // included in all copies or substantial portions of the Software.
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.
38 using System.Runtime.Remoting;
39 using System.Runtime.Serialization;
40 using System.Runtime.InteropServices;
41 using System.ComponentModel;
42 using System.Drawing.Imaging;
44 using System.Reflection;
46 namespace System.Drawing
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
55 public delegate bool GetThumbnailImageAbort();
57 internal IntPtr nativeObject = IntPtr.Zero;
66 private Image (SerializationInfo info, StreamingContext context)
68 foreach (SerializationEntry serEnum in info) {
69 if (String.Compare(serEnum.Name, "Data", true) == 0) {
70 byte[] bytes = (byte[]) serEnum.Value;
73 InitFromStream(new MemoryStream(bytes));
79 private static bool IsIndexedPixelFormat(PixelFormat pixfmt)
81 return ((pixfmt & PixelFormat.Indexed) != 0);
85 void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context)
87 MemoryStream ms = new MemoryStream ();
88 this.Save (ms, ImageFormat.Bmp);
89 info.AddValue ("Data", ms.ToArray ());
94 public static Image FromFile(string filename)
96 return FromFile (filename, false);
99 public static Image FromFile(string filename, bool useEmbeddedColorManagement)
104 if (!File.Exists (filename))
105 throw new FileNotFoundException (filename);
107 if (useEmbeddedColorManagement)
108 st = GDIPlus.GdipLoadImageFromFileICM (filename, out imagePtr);
110 st = GDIPlus.GdipLoadImageFromFile (filename, out imagePtr);
112 GDIPlus.CheckStatus (st);
113 return new Bitmap (imagePtr);
116 public static Bitmap FromHbitmap(IntPtr hbitmap)
118 return FromHbitmap (hbitmap, IntPtr.Zero);
121 public static Bitmap FromHbitmap(IntPtr hbitmap, IntPtr hpalette)
126 st = GDIPlus.GdipCreateBitmapFromHBITMAP (hbitmap, hpalette, out imagePtr);
128 GDIPlus.CheckStatus (st);
129 return new Bitmap (imagePtr);
132 public static Image FromStream (Stream stream)
134 return new Bitmap (stream);
137 public static Image FromStream (Stream stream, bool useECM)
139 return new Bitmap (stream, useECM);
142 public static int GetPixelFormatSize(PixelFormat pixfmt)
146 case PixelFormat.Format16bppArgb1555:
147 case PixelFormat.Format16bppGrayScale:
148 case PixelFormat.Format16bppRgb555:
149 case PixelFormat.Format16bppRgb565:
152 case PixelFormat.Format1bppIndexed:
155 case PixelFormat.Format24bppRgb:
158 case PixelFormat.Format32bppArgb:
159 case PixelFormat.Format32bppPArgb:
160 case PixelFormat.Format32bppRgb:
163 case PixelFormat.Format48bppRgb:
166 case PixelFormat.Format4bppIndexed:
169 case PixelFormat.Format64bppArgb:
170 case PixelFormat.Format64bppPArgb:
173 case PixelFormat.Format8bppIndexed:
180 public static bool IsAlphaPixelFormat(PixelFormat pixfmt)
184 case PixelFormat.Format16bppArgb1555:
185 case PixelFormat.Format32bppArgb:
186 case PixelFormat.Format32bppPArgb:
187 case PixelFormat.Format64bppArgb:
188 case PixelFormat.Format64bppPArgb:
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:
206 public static bool IsCanonicalPixelFormat (PixelFormat pixfmt)
208 return ((pixfmt & PixelFormat.Canonical) != 0);
211 public static bool IsExtendedPixelFormat (PixelFormat pixfmt)
213 return ((pixfmt & PixelFormat.Extended) != 0);
216 internal void InitFromStream (Stream stream)
222 if (!stream.CanSeek) {
223 byte[] buffer = new byte[256];
228 if (buffer.Length < index + 256) {
229 byte[] newBuffer = new byte[buffer.Length * 2];
230 Array.Copy(buffer, newBuffer, buffer.Length);
233 count = stream.Read(buffer, index, 256);
238 stream = new MemoryStream(buffer, 0, index);
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);
251 st = GDIPlus.GdipLoadImageFromDelegate_linux (sh.GetHeaderDelegate, sh.GetBytesDelegate,
252 sh.PutBytesDelegate, sh.SeekDelegate, sh.CloseDelegate, sh.SizeDelegate, out imagePtr);
255 st = GDIPlus.GdipLoadImageFromStream(new ComIStreamWrapper(stream), out imagePtr);
258 GDIPlus.CheckStatus (st);
259 nativeObject = imagePtr;
263 public RectangleF GetBounds (ref GraphicsUnit pageUnit)
267 Status status = GDIPlus.GdipGetImageBounds (nativeObject, out source, ref pageUnit);
268 GDIPlus.CheckStatus (status);
273 public EncoderParameters GetEncoderParameterList(Guid format)
278 status = GDIPlus.GdipGetEncoderParameterListSize (nativeObject, ref format, out sz);
279 GDIPlus.CheckStatus (status);
281 IntPtr rawEPList = Marshal.AllocHGlobal ((int) sz);
282 EncoderParameters eps;
285 status = GDIPlus.GdipGetEncoderParameterList (nativeObject, ref format, sz, rawEPList);
286 eps = EncoderParameters.FromNativePtr (rawEPList);
287 GDIPlus.CheckStatus (status);
289 Marshal.FreeHGlobal (rawEPList);
293 Marshal.FreeHGlobal (rawEPList);
298 public int GetFrameCount(FrameDimension dimension)
301 Guid guid = dimension.Guid;
302 Status status = GDIPlus.GdipImageGetFrameCount (nativeObject, ref guid, out count);
304 GDIPlus.CheckStatus (status);
310 public PropertyItem GetPropertyItem(int propid)
314 PropertyItem item = new PropertyItem ();
315 GdipPropertyItem gdipProperty = new GdipPropertyItem ();
318 status = GDIPlus.GdipGetPropertyItemSize (nativeObject, propid,
320 GDIPlus.CheckStatus (status);
322 /* Get PropertyItem */
323 property = Marshal.AllocHGlobal (propSize);
324 status = GDIPlus.GdipGetPropertyItem (nativeObject, propid, propSize,
326 GDIPlus.CheckStatus (status);
327 gdipProperty = (GdipPropertyItem) Marshal.PtrToStructure ((IntPtr)property,
328 typeof (GdipPropertyItem));
329 GdipPropertyItem.MarshalTo (gdipProperty, item);
331 Marshal.FreeHGlobal (property);
335 public Image GetThumbnailImage(int thumbWidth, int thumbHeight, Image.GetThumbnailImageAbort callback, IntPtr callbackData)
341 ThumbNail=new Bitmap(thumbWidth, thumbHeight);
342 g=Graphics.FromImage(ThumbNail);
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);
355 public void RemovePropertyItem (int propid)
357 Status status = GDIPlus.GdipRemovePropertyItem (nativeObject, propid);
358 GDIPlus.CheckStatus (status);
361 public void RotateFlip (RotateFlipType rotateFlipType)
363 Status status = GDIPlus.GdipImageRotateFlip (nativeObject, rotateFlipType);
364 GDIPlus.CheckStatus (status);
367 internal ImageCodecInfo findEncoderForFormat (ImageFormat format)
369 ImageCodecInfo[] encoders = ImageCodecInfo.GetImageEncoders();
370 ImageCodecInfo encoder = null;
372 if (format.Guid.Equals (ImageFormat.MemoryBmp.Guid))
373 format = ImageFormat.Png;
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];
386 public void Save (string filename)
388 Save (filename, RawFormat);
391 public void Save(string filename, ImageFormat format)
393 ImageCodecInfo encoder = findEncoderForFormat (format);
396 throw new ArgumentException ("No codec available for format:" + format.Guid);
398 Save (filename, encoder, null);
401 public void Save(string filename, ImageCodecInfo encoder, EncoderParameters encoderParams)
404 Guid guid = encoder.Clsid;
406 if (encoderParams == null) {
407 st = GDIPlus.GdipSaveImageToFile (nativeObject, filename, ref guid, IntPtr.Zero);
409 IntPtr nativeEncoderParams = encoderParams.ToNativePtr ();
410 st = GDIPlus.GdipSaveImageToFile (nativeObject, filename, ref guid, nativeEncoderParams);
411 Marshal.FreeHGlobal (nativeEncoderParams);
414 GDIPlus.CheckStatus (st);
417 public void Save (Stream stream, ImageFormat format)
419 ImageCodecInfo encoder = findEncoderForFormat (format);
422 throw new ArgumentException ("No codec available for format:" + format.Guid);
424 Save (stream, encoder, null);
427 public void Save(Stream stream, ImageCodecInfo encoder, EncoderParameters encoderParams)
430 IntPtr nativeEncoderParams;
431 Guid guid = encoder.Clsid;
433 if (encoderParams == null)
434 nativeEncoderParams = IntPtr.Zero;
436 nativeEncoderParams = encoderParams.ToNativePtr ();
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);
448 st = GDIPlus.GdipSaveImageToStream(new HandleRef(this, nativeObject), new ComIStreamWrapper(stream), ref guid, new HandleRef(encoderParams, nativeEncoderParams));
451 if (nativeEncoderParams != IntPtr.Zero)
452 Marshal.FreeHGlobal (nativeEncoderParams);
455 GDIPlus.CheckStatus (st);
458 public void SaveAdd (EncoderParameters encoderParams)
462 IntPtr nativeEncoderParams = encoderParams.ToNativePtr ();
463 st = GDIPlus.GdipSaveAdd (nativeObject, nativeEncoderParams);
464 Marshal.FreeHGlobal (nativeEncoderParams);
465 GDIPlus.CheckStatus (st);
468 public void SaveAdd (Image image, EncoderParameters encoderParams)
472 IntPtr nativeEncoderParams = encoderParams.ToNativePtr ();
473 st = GDIPlus.GdipSaveAddImage (nativeObject, image.NativeObject, nativeEncoderParams);
474 Marshal.FreeHGlobal (nativeEncoderParams);
475 GDIPlus.CheckStatus (st);
478 public int SelectActiveFrame(FrameDimension dimension, int frameIndex)
480 Guid guid = dimension.Guid;
481 Status st = GDIPlus.GdipImageSelectActiveFrame (nativeObject, ref guid, frameIndex);
483 GDIPlus.CheckStatus (st);
488 public void SetPropertyItem(PropertyItem propitem)
491 int size = Marshal.SizeOf (typeof(GdipPropertyItem));
492 property = Marshal.AllocHGlobal (size);
494 Marshal.StructureToPtr (propitem, property, true);
495 Status status = GDIPlus.GdipSetPropertyItem (nativeObject, property);
496 GDIPlus.CheckStatus (status);
505 Status status = GDIPlus.GdipGetImageFlags (nativeObject, out flags);
506 GDIPlus.CheckStatus (status);
512 public Guid[] FrameDimensionsList {
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);
524 [DefaultValue (false)]
526 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
530 Status status = GDIPlus.GdipGetImageHeight (nativeObject, out height);
531 GDIPlus.CheckStatus (status);
537 public float HorizontalResolution {
541 Status status = GDIPlus.GdipGetImageHorizontalResolution (nativeObject, out resolution);
542 GDIPlus.CheckStatus (status);
549 public ColorPalette Palette {
551 return retrieveGDIPalette();
554 storeGDIPalette(value);
558 internal ColorPalette retrieveGDIPalette()
560 ColorPalette ret = new ColorPalette();
561 if (!IsIndexedPixelFormat (PixelFormat)) {
567 st = GDIPlus.GdipGetImagePaletteSize (nativeObject, out bytes);
568 GDIPlus.CheckStatus (st);
569 IntPtr palette_data = Marshal.AllocHGlobal (bytes);
571 st = GDIPlus.GdipGetImagePalette (nativeObject, palette_data, bytes);
572 GDIPlus.CheckStatus (st);
573 ret.setFromGDIPalette (palette_data);
578 Marshal.FreeHGlobal (palette_data);
582 internal void storeGDIPalette(ColorPalette palette)
584 if (palette == null) {
585 throw new ArgumentNullException("palette");
587 IntPtr palette_data = palette.getGDIPalette();
588 if (palette_data == IntPtr.Zero) {
593 Status st = GDIPlus.GdipSetImagePalette (nativeObject, palette_data);
594 GDIPlus.CheckStatus (st);
598 Marshal.FreeHGlobal(palette_data);
603 public SizeF PhysicalDimension {
606 Status status = GDIPlus.GdipGetImageDimension (nativeObject, out width, out height);
607 GDIPlus.CheckStatus (status);
609 return new SizeF (width, height);
613 public PixelFormat PixelFormat {
615 PixelFormat pixFormat;
616 Status status = GDIPlus.GdipGetImagePixelFormat (nativeObject, out pixFormat);
617 GDIPlus.CheckStatus (status);
624 public int[] PropertyIdList {
628 Status status = GDIPlus.GdipGetPropertyCount (nativeObject,
630 GDIPlus.CheckStatus (status);
632 int [] idList = new int [propNumbers];
633 status = GDIPlus.GdipGetPropertyIdList (nativeObject,
634 propNumbers, idList);
635 GDIPlus.CheckStatus (status);
642 public PropertyItem[] PropertyItems {
644 int propNums, propsSize, propSize;
645 IntPtr properties, propPtr;
646 PropertyItem[] items;
647 GdipPropertyItem gdipProperty = new GdipPropertyItem ();
650 status = GDIPlus.GdipGetPropertySize (nativeObject, out propsSize, out propNums);
651 GDIPlus.CheckStatus (status);
653 items = new PropertyItem [propNums];
658 /* Get PropertyItem list*/
659 properties = Marshal.AllocHGlobal (propsSize * propNums);
661 status = GDIPlus.GdipGetAllPropertyItems (nativeObject, propsSize,
662 propNums, properties);
663 GDIPlus.CheckStatus (status);
665 propSize = Marshal.SizeOf (gdipProperty);
666 propPtr = properties;
668 for (int i = 0; i < propNums; i++, propPtr = new IntPtr (propPtr.ToInt64 () + propSize))
670 gdipProperty = (GdipPropertyItem) Marshal.PtrToStructure
671 (propPtr, typeof (GdipPropertyItem));
672 items [i] = new PropertyItem ();
673 GdipPropertyItem.MarshalTo (gdipProperty, items [i]);
676 Marshal.FreeHGlobal (properties);
681 public ImageFormat RawFormat {
684 Status st = GDIPlus.GdipGetImageRawFormat (nativeObject, out guid);
686 GDIPlus.CheckStatus (st);
687 return new ImageFormat (guid);
693 return new Size(Width, Height);
697 public float VerticalResolution {
701 Status status = GDIPlus.GdipGetImageVerticalResolution (nativeObject, out resolution);
702 GDIPlus.CheckStatus (status);
708 [DefaultValue (false)]
710 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
714 Status status = GDIPlus.GdipGetImageWidth (nativeObject, out width);
715 GDIPlus.CheckStatus (status);
721 internal IntPtr NativeObject{
726 nativeObject = value;
730 public void Dispose ()
733 System.GC.SuppressFinalize (this);
741 private void DisposeResources ()
743 Status status = GDIPlus.GdipDisposeImage (nativeObject);
744 GDIPlus.CheckStatus (status);
747 protected virtual void Dispose (bool disposing)
749 if (nativeObject != IntPtr.Zero){
751 nativeObject = IntPtr.Zero;
755 public virtual object Clone()
758 IntPtr newimage = IntPtr.Zero;
760 if (!(this is Bitmap))
761 throw new NotImplementedException ();
763 Status status = GDIPlus.GdipCloneImage (NativeObject, out newimage);
764 GDIPlus.CheckStatus (status);
767 return new Bitmap (newimage);
770 throw new NotImplementedException ();