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 new Bitmap (filename);
99 public static Image FromFile(string filename, bool useEmbeddedColorManagement)
101 return new Bitmap (filename, useEmbeddedColorManagement);
105 public static Bitmap FromHbitmap(IntPtr hbitmap)
107 throw new NotImplementedException ();
111 public static Bitmap FromHbitmap(IntPtr hbitmap, IntPtr hpalette)
113 throw new NotImplementedException ();
116 public static Image FromStream (Stream stream)
118 return new Bitmap (stream);
121 public static Image FromStream (Stream stream, bool useECM)
123 return new Bitmap (stream, useECM);
126 public static int GetPixelFormatSize(PixelFormat pixfmt)
130 case PixelFormat.Format16bppArgb1555:
131 case PixelFormat.Format16bppGrayScale:
132 case PixelFormat.Format16bppRgb555:
133 case PixelFormat.Format16bppRgb565:
136 case PixelFormat.Format1bppIndexed:
139 case PixelFormat.Format24bppRgb:
142 case PixelFormat.Format32bppArgb:
143 case PixelFormat.Format32bppPArgb:
144 case PixelFormat.Format32bppRgb:
147 case PixelFormat.Format48bppRgb:
150 case PixelFormat.Format4bppIndexed:
153 case PixelFormat.Format64bppArgb:
154 case PixelFormat.Format64bppPArgb:
157 case PixelFormat.Format8bppIndexed:
164 public static bool IsAlphaPixelFormat(PixelFormat pixfmt)
168 case PixelFormat.Format16bppArgb1555:
169 case PixelFormat.Format32bppArgb:
170 case PixelFormat.Format32bppPArgb:
171 case PixelFormat.Format64bppArgb:
172 case PixelFormat.Format64bppPArgb:
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:
190 public static bool IsCanonicalPixelFormat (PixelFormat pixfmt)
192 return ((pixfmt & PixelFormat.Canonical) != 0);
195 public static bool IsExtendedPixelFormat (PixelFormat pixfmt)
197 return ((pixfmt & PixelFormat.Extended) != 0);
200 internal void InitFromStream (Stream stream)
206 if (!stream.CanSeek) {
207 byte[] buffer = new byte[256];
212 if (buffer.Length < index + 256) {
213 byte[] newBuffer = new byte[buffer.Length * 2];
214 Array.Copy(buffer, newBuffer, buffer.Length);
217 count = stream.Read(buffer, index, 256);
222 stream = new MemoryStream(buffer, 0, index);
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);
235 st = GDIPlus.GdipLoadImageFromDelegate_linux (sh.GetHeaderDelegate, sh.GetBytesDelegate,
236 sh.PutBytesDelegate, sh.SeekDelegate, sh.CloseDelegate, sh.SizeDelegate, out imagePtr);
239 st = GDIPlus.GdipLoadImageFromStream(new ComIStreamWrapper(stream), out imagePtr);
242 GDIPlus.CheckStatus (st);
243 nativeObject = imagePtr;
247 public RectangleF GetBounds (ref GraphicsUnit pageUnit)
251 Status status = GDIPlus.GdipGetImageBounds (nativeObject, out source, ref pageUnit);
252 GDIPlus.CheckStatus (status);
257 public EncoderParameters GetEncoderParameterList(Guid format)
262 status = GDIPlus.GdipGetEncoderParameterListSize (nativeObject, ref format, out sz);
263 GDIPlus.CheckStatus (status);
265 IntPtr rawEPList = Marshal.AllocHGlobal ((int) sz);
266 EncoderParameters eps;
269 status = GDIPlus.GdipGetEncoderParameterList (nativeObject, ref format, sz, rawEPList);
270 eps = EncoderParameters.FromNativePtr (rawEPList);
271 GDIPlus.CheckStatus (status);
273 Marshal.FreeHGlobal (rawEPList);
277 Marshal.FreeHGlobal (rawEPList);
282 public int GetFrameCount(FrameDimension dimension)
285 Guid guid = dimension.Guid;
286 Status status = GDIPlus.GdipImageGetFrameCount (nativeObject, ref guid, out count);
288 GDIPlus.CheckStatus (status);
294 public PropertyItem GetPropertyItem(int propid)
298 PropertyItem item = new PropertyItem ();
299 GdipPropertyItem gdipProperty = new GdipPropertyItem ();
302 status = GDIPlus.GdipGetPropertyItemSize (nativeObject, propid,
304 GDIPlus.CheckStatus (status);
306 /* Get PropertyItem */
307 property = Marshal.AllocHGlobal (propSize);
308 status = GDIPlus.GdipGetPropertyItem (nativeObject, propid, propSize,
310 GDIPlus.CheckStatus (status);
311 gdipProperty = (GdipPropertyItem) Marshal.PtrToStructure ((IntPtr)property,
312 typeof (GdipPropertyItem));
313 GdipPropertyItem.MarshalTo (gdipProperty, item);
315 Marshal.FreeHGlobal (property);
319 public Image GetThumbnailImage(int thumbWidth, int thumbHeight, Image.GetThumbnailImageAbort callback, IntPtr callbackData)
325 ThumbNail=new Bitmap(thumbWidth, thumbHeight);
326 g=Graphics.FromImage(ThumbNail);
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);
339 public void RemovePropertyItem (int propid)
341 Status status = GDIPlus.GdipRemovePropertyItem (nativeObject, propid);
342 GDIPlus.CheckStatus (status);
345 public void RotateFlip (RotateFlipType rotateFlipType)
347 Status status = GDIPlus.GdipImageRotateFlip (nativeObject, rotateFlipType);
348 GDIPlus.CheckStatus (status);
351 internal ImageCodecInfo findEncoderForFormat (ImageFormat format)
353 ImageCodecInfo[] encoders = ImageCodecInfo.GetImageEncoders();
354 ImageCodecInfo encoder = null;
356 if (format.Guid.Equals (ImageFormat.MemoryBmp.Guid))
357 format = ImageFormat.Bmp;
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];
370 public void Save (string filename)
372 Save (filename, RawFormat);
375 public void Save(string filename, ImageFormat format)
377 ImageCodecInfo encoder = findEncoderForFormat (format);
380 throw new ArgumentException ("No codec available for format:" + format.Guid);
382 Save (filename, encoder, null);
385 public void Save(string filename, ImageCodecInfo encoder, EncoderParameters encoderParams)
388 Guid guid = encoder.Clsid;
390 if (encoderParams == null) {
391 st = GDIPlus.GdipSaveImageToFile (nativeObject, filename, ref guid, IntPtr.Zero);
393 IntPtr nativeEncoderParams = encoderParams.ToNativePtr ();
394 st = GDIPlus.GdipSaveImageToFile (nativeObject, filename, ref guid, nativeEncoderParams);
395 Marshal.FreeHGlobal (nativeEncoderParams);
398 GDIPlus.CheckStatus (st);
401 public void Save (Stream stream, ImageFormat format)
403 ImageCodecInfo encoder = findEncoderForFormat (format);
406 throw new ArgumentException ("No codec available for format:" + format.Guid);
408 Save (stream, encoder, null);
411 public void Save(Stream stream, ImageCodecInfo encoder, EncoderParameters encoderParams)
414 IntPtr nativeEncoderParams;
415 Guid guid = encoder.Clsid;
417 if (encoderParams == null)
418 nativeEncoderParams = IntPtr.Zero;
420 nativeEncoderParams = encoderParams.ToNativePtr ();
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);
432 st = GDIPlus.GdipSaveImageToStream(new HandleRef(this, nativeObject), new ComIStreamWrapper(stream), ref guid, new HandleRef(encoderParams, nativeEncoderParams));
435 if (nativeEncoderParams != IntPtr.Zero)
436 Marshal.FreeHGlobal (nativeEncoderParams);
439 GDIPlus.CheckStatus (st);
442 public void SaveAdd (EncoderParameters encoderParams)
446 IntPtr nativeEncoderParams = encoderParams.ToNativePtr ();
447 st = GDIPlus.GdipSaveAdd (nativeObject, nativeEncoderParams);
448 Marshal.FreeHGlobal (nativeEncoderParams);
449 GDIPlus.CheckStatus (st);
452 public void SaveAdd (Image image, EncoderParameters encoderParams)
456 IntPtr nativeEncoderParams = encoderParams.ToNativePtr ();
457 st = GDIPlus.GdipSaveAddImage (nativeObject, image.NativeObject, nativeEncoderParams);
458 Marshal.FreeHGlobal (nativeEncoderParams);
459 GDIPlus.CheckStatus (st);
462 public int SelectActiveFrame(FrameDimension dimension, int frameIndex)
464 Guid guid = dimension.Guid;
465 Status st = GDIPlus.GdipImageSelectActiveFrame (nativeObject, ref guid, frameIndex);
467 GDIPlus.CheckStatus (st);
472 public void SetPropertyItem(PropertyItem propitem)
475 int size = Marshal.SizeOf (typeof(GdipPropertyItem));
476 property = Marshal.AllocHGlobal (size);
478 Marshal.StructureToPtr (propitem, property, true);
479 Status status = GDIPlus.GdipSetPropertyItem (nativeObject, property);
480 GDIPlus.CheckStatus (status);
489 Status status = GDIPlus.GdipGetImageFlags (nativeObject, out flags);
490 GDIPlus.CheckStatus (status);
496 public Guid[] FrameDimensionsList {
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);
508 [DefaultValue (false)]
510 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
514 Status status = GDIPlus.GdipGetImageHeight (nativeObject, out height);
515 GDIPlus.CheckStatus (status);
521 public float HorizontalResolution {
525 Status status = GDIPlus.GdipGetImageHorizontalResolution (nativeObject, out resolution);
526 GDIPlus.CheckStatus (status);
533 public ColorPalette Palette {
535 return retrieveGDIPalette();
538 storeGDIPalette(value);
542 internal ColorPalette retrieveGDIPalette()
544 ColorPalette ret = new ColorPalette();
545 if (!IsIndexedPixelFormat (PixelFormat)) {
551 st = GDIPlus.GdipGetImagePaletteSize (nativeObject, out bytes);
552 GDIPlus.CheckStatus (st);
553 IntPtr palette_data = Marshal.AllocHGlobal (bytes);
555 st = GDIPlus.GdipGetImagePalette (nativeObject, palette_data, bytes);
556 GDIPlus.CheckStatus (st);
557 ret.setFromGDIPalette (palette_data);
562 Marshal.FreeHGlobal (palette_data);
566 internal void storeGDIPalette(ColorPalette palette)
568 if (palette == null) {
569 throw new ArgumentNullException("palette");
571 IntPtr palette_data = palette.getGDIPalette();
572 if (palette_data == IntPtr.Zero) {
577 Status st = GDIPlus.GdipSetImagePalette (nativeObject, palette_data);
578 GDIPlus.CheckStatus (st);
582 Marshal.FreeHGlobal(palette_data);
587 public SizeF PhysicalDimension {
590 Status status = GDIPlus.GdipGetImageDimension (nativeObject, out width, out height);
591 GDIPlus.CheckStatus (status);
593 return new SizeF (width, height);
597 public PixelFormat PixelFormat {
599 PixelFormat pixFormat;
600 Status status = GDIPlus.GdipGetImagePixelFormat (nativeObject, out pixFormat);
601 GDIPlus.CheckStatus (status);
608 public int[] PropertyIdList {
612 Status status = GDIPlus.GdipGetPropertyCount (nativeObject,
614 GDIPlus.CheckStatus (status);
616 int [] idList = new int [propNumbers];
617 status = GDIPlus.GdipGetPropertyIdList (nativeObject,
618 propNumbers, idList);
619 GDIPlus.CheckStatus (status);
626 public PropertyItem[] PropertyItems {
628 int propNums, propsSize, propSize;
629 IntPtr properties, propPtr;
630 PropertyItem[] items;
631 GdipPropertyItem gdipProperty = new GdipPropertyItem ();
634 status = GDIPlus.GdipGetPropertySize (nativeObject, out propsSize, out propNums);
635 GDIPlus.CheckStatus (status);
637 items = new PropertyItem [propNums];
642 /* Get PropertyItem list*/
643 properties = Marshal.AllocHGlobal (propsSize);
644 status = GDIPlus.GdipGetAllPropertyItems (nativeObject, propsSize,
645 propNums, properties);
646 GDIPlus.CheckStatus (status);
648 propSize = Marshal.SizeOf (gdipProperty);
649 propPtr = properties;
651 for (int i = 0; i < propNums; i++, propPtr = new IntPtr (propPtr.ToInt64 () + propSize))
653 gdipProperty = (GdipPropertyItem) Marshal.PtrToStructure
654 (propPtr, typeof (GdipPropertyItem));
655 items [i] = new PropertyItem ();
656 GdipPropertyItem.MarshalTo (gdipProperty, items [i]);
659 Marshal.FreeHGlobal (properties);
664 public ImageFormat RawFormat {
667 Status st = GDIPlus.GdipGetImageRawFormat (nativeObject, out guid);
669 GDIPlus.CheckStatus (st);
670 return new ImageFormat (guid);
676 return new Size(Width, Height);
680 public float VerticalResolution {
684 Status status = GDIPlus.GdipGetImageVerticalResolution (nativeObject, out resolution);
685 GDIPlus.CheckStatus (status);
691 [DefaultValue (false)]
693 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
697 Status status = GDIPlus.GdipGetImageWidth (nativeObject, out width);
698 GDIPlus.CheckStatus (status);
704 internal IntPtr NativeObject{
709 nativeObject = value;
713 public void Dispose ()
716 System.GC.SuppressFinalize (this);
724 private void DisposeResources ()
726 Status status = GDIPlus.GdipDisposeImage (nativeObject);
727 GDIPlus.CheckStatus (status);
730 protected virtual void Dispose (bool disposing)
732 if (nativeObject != IntPtr.Zero){
734 nativeObject = IntPtr.Zero;
738 public virtual object Clone()
741 IntPtr newimage = IntPtr.Zero;
743 if (!(this is Bitmap))
744 throw new NotImplementedException ();
746 Status status = GDIPlus.GdipCloneImage (NativeObject, out newimage);
747 GDIPlus.CheckStatus (status);
750 return new Bitmap (newimage);
753 throw new NotImplementedException ();