<PackageReference Include="System.Drawing.Common" Version="10.0.0-preview.1.25080.3" />

Image

An abstract base class that provides functionality for the Bitmap and Metafile descended classes.
using System.ComponentModel; using System.Drawing.Imaging; using System.IO; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Serialization; using Windows.Win32; using Windows.Win32.Foundation; using Windows.Win32.Graphics.Gdi; using Windows.Win32.Graphics.GdiPlus; using Windows.Win32.System.Com; namespace System.Drawing { [Serializable] [NullableContext(1)] [Nullable(0)] [Editor("System.Drawing.Design.ImageEditor, System.Drawing.Design, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a", "System.Drawing.Design.UITypeEditor, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")] [ImmutableObject(true)] [TypeForwardedFrom("System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")] [TypeConverter(typeof(ImageConverter))] public abstract class Image : MarshalByRefObject, IImage, IRawData, IPointer<GpImage>, IDisposable, ICloneable, ISerializable { [NullableContext(0)] public delegate bool GetThumbnailImageAbort (); [NonSerialized] [Nullable(0)] private unsafe GpImage* _nativeImage; [Nullable(2)] private object _userData; [Nullable(2)] private byte[] _animatedGifRawData; unsafe IntPtr IPointer<GpImage>.Pointer { get { return (IntPtr)_nativeImage; } } [Nullable(0)] ReadOnlySpan<byte> IRawData.Data { [NullableContext(0)] get { return _animatedGifRawData; } } [Nullable(2)] [Localizable(false)] [DefaultValue(null)] public object Tag { [NullableContext(2)] get { return _userData; } [NullableContext(2)] set { _userData = value; } } public unsafe SizeF PhysicalDimension { get { float width = default(float); float height = default(float); PInvokeGdiPlus.GdipGetImageDimension(_nativeImage, &width, &height).ThrowIfFailed(); GC.KeepAlive(this); return new SizeF(width, height); } } public Size Size => new Size(Width, Height); [DefaultValue(false)] [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public unsafe int Width { get { uint result = default(uint); PInvokeGdiPlus.GdipGetImageWidth(_nativeImage, &result).ThrowIfFailed(); GC.KeepAlive(this); return (int)result; } } [DefaultValue(false)] [Browsable(false)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] public unsafe int Height { get { uint result = default(uint); PInvokeGdiPlus.GdipGetImageHeight(_nativeImage, &result).ThrowIfFailed(); GC.KeepAlive(this); return (int)result; } } public unsafe float HorizontalResolution { get { float result = default(float); PInvokeGdiPlus.GdipGetImageHorizontalResolution(_nativeImage, &result).ThrowIfFailed(); GC.KeepAlive(this); return result; } } public unsafe float VerticalResolution { get { float result = default(float); PInvokeGdiPlus.GdipGetImageVerticalResolution(_nativeImage, &result).ThrowIfFailed(); GC.KeepAlive(this); return result; } } [Browsable(false)] public unsafe int Flags { get { uint result = default(uint); PInvokeGdiPlus.GdipGetImageFlags(_nativeImage, &result).ThrowIfFailed(); GC.KeepAlive(this); return (int)result; } } public unsafe ImageFormat RawFormat { get { Guid guid = default(Guid); PInvokeGdiPlus.GdipGetImageRawFormat(_nativeImage, &guid).ThrowIfFailed(); GC.KeepAlive(this); return new ImageFormat(guid); } } public System.Drawing.Imaging.PixelFormat PixelFormat => (System.Drawing.Imaging.PixelFormat)this.GetPixelFormat(); [Browsable(false)] public unsafe int[] PropertyIdList { get { uint num = default(uint); PInvokeGdiPlus.GdipGetPropertyCount(_nativeImage, &num).ThrowIfFailed(); if (num == 0) return Array.Empty<int>(); int[] obj = new int[num]; fixed (int* list = obj) { PInvokeGdiPlus.GdipGetPropertyIdList(_nativeImage, num, (uint*)list).ThrowIfFailed(); } GC.KeepAlive(this); return obj; } } [Browsable(false)] public unsafe System.Drawing.Imaging.PropertyItem[] PropertyItems { get { uint num = default(uint); uint num2 = default(uint); PInvokeGdiPlus.GdipGetPropertySize(_nativeImage, &num, &num2).ThrowIfFailed(); if (num != 0 && num2 != 0) { System.Drawing.Imaging.PropertyItem[] array = new System.Drawing.Imaging.PropertyItem[num2]; BufferScope<byte> bufferScope = new BufferScope<byte>((int)num); try { fixed (byte* ptr = &bufferScope.GetPinnableReference()) { global::Windows.Win32.Graphics.GdiPlus.PropertyItem* ptr2 = (global::Windows.Win32.Graphics.GdiPlus.PropertyItem*)ptr; PInvokeGdiPlus.GdipGetAllPropertyItems(_nativeImage, num, num2, ptr2); for (int i = 0; i < num2; i++) { array[i] = System.Drawing.Imaging.PropertyItem.FromNative(ptr2 + i); } } GC.KeepAlive(this); return array; } finally { bufferScope.Dispose(); } } return Array.Empty<System.Drawing.Imaging.PropertyItem>(); } } [Browsable(false)] public unsafe System.Drawing.Imaging.ColorPalette Palette { get { int num = default(int); PInvokeGdiPlus.GdipGetImagePaletteSize(_nativeImage, &num).ThrowIfFailed(); BufferScope<uint> scope = new BufferScope<uint>(num / 4); try { fixed (uint* palette = &scope.GetPinnableReference()) { PInvokeGdiPlus.GdipGetImagePalette(_nativeImage, (global::Windows.Win32.Graphics.GdiPlus.ColorPalette*)palette, num).ThrowIfFailed(); GC.KeepAlive(this); return System.Drawing.Imaging.ColorPalette.ConvertFromBuffer(scope); } } finally { scope.Dispose(); } } set { BufferScope<uint> bufferScope = value.ConvertToBuffer(); try { fixed (uint* palette = &bufferScope.GetPinnableReference()) { PInvokeGdiPlus.GdipSetImagePalette(_nativeImage, (global::Windows.Win32.Graphics.GdiPlus.ColorPalette*)palette).ThrowIfFailed(); GC.KeepAlive(this); } } finally { bufferScope.Dispose(); } } } [Browsable(false)] public unsafe Guid[] FrameDimensionsList { get { uint num = default(uint); PInvokeGdiPlus.GdipImageGetFrameDimensionsCount(_nativeImage, &num).ThrowIfFailed(); if (num == 0) return Array.Empty<Guid>(); Guid[] obj = new Guid[num]; fixed (Guid* dimensionIDs = obj) { PInvokeGdiPlus.GdipImageGetFrameDimensionsList(_nativeImage, dimensionIDs, num).ThrowIfFailed(); } GC.KeepAlive(this); return obj; } } private protected Image() { } private protected unsafe Image(SerializationInfo info, StreamingContext context) { byte[] buffer = (byte[])info.GetValue("Data", typeof(byte[])); try { SetNativeImage(InitializeFromStream(new MemoryStream(buffer))); } catch (Exception ex) when (((ex is ExternalException || ex is ArgumentException || ex is OutOfMemoryException || ex is InvalidOperationException || ex is NotImplementedException || ex is FileNotFoundException) ? 1 : 0) != 0) { } } void ISerializable.GetObjectData(SerializationInfo si, StreamingContext context) { using (MemoryStream memoryStream = new MemoryStream()) { this.Save(memoryStream); si.AddValue("Data", memoryStream.ToArray(), typeof(byte[])); } } public static Image FromFile(string filename) { return FromFile(filename, false); } public unsafe static Image FromFile(string filename, bool useEmbeddedColorManagement) { if (!File.Exists(filename)) { filename = Path.GetFullPath(filename); throw new FileNotFoundException(filename); } filename = Path.GetFullPath(filename); GpImage* ptr = null; IntPtr intPtr; if (filename == null) intPtr = (IntPtr)(void*)null; else { ref reference = ref filename.GetPinnableReference(); intPtr = (IntPtr)(&reference); } char* value = (char*)(long)intPtr; if (useEmbeddedColorManagement) PInvokeGdiPlus.GdipLoadImageFromFileICM(value, &ptr).ThrowIfFailed(); else PInvokeGdiPlus.GdipLoadImageFromFile(value, &ptr).ThrowIfFailed(); ref reference = ref *(char*)null; ValidateImage(ptr); Image image = CreateImageObject(ptr); GetAnimatedGifRawData(image, filename, null); return image; } public static Image FromStream(Stream stream) { return FromStream(stream, false); } public static Image FromStream(Stream stream, bool useEmbeddedColorManagement) { return FromStream(stream, useEmbeddedColorManagement, true); } public unsafe static Image FromStream(Stream stream, bool useEmbeddedColorManagement, bool validateImageData) { ArgumentNullException.ThrowIfNull(stream, "stream"); GpImage* ptr = LoadGdipImageFromStream(stream, useEmbeddedColorManagement); if (validateImageData) ValidateImage(ptr); Image image = CreateImageObject(ptr); GetAnimatedGifRawData(image, null, stream); return image; } [NullableContext(0)] private unsafe GpImage* InitializeFromStream([Nullable(1)] Stream stream) { GpImage* ptr = LoadGdipImageFromStream(stream, false); ValidateImage(ptr); _nativeImage = ptr; global::Windows.Win32.Graphics.GdiPlus.ImageType imageType = global::Windows.Win32.Graphics.GdiPlus.ImageType.ImageTypeUnknown; PInvokeGdiPlus.GdipGetImageType(_nativeImage, &imageType).ThrowIfFailed(); GetAnimatedGifRawData(this, null, stream); return ptr; } [NullableContext(0)] private unsafe static GpImage* LoadGdipImageFromStream([Nullable(1)] Stream stream, bool useEmbeddedColorManagement) { ComScope<IStream> scope = stream.ToIStream(true); try { return LoadGdipImageFromStream((IStream*)ref scope, useEmbeddedColorManagement); } finally { scope.Dispose(); } } [NullableContext(0)] private unsafe static GpImage* LoadGdipImageFromStream(IStream* stream, bool useEmbeddedColorManagement) { GpImage* result = default(GpImage*); if (useEmbeddedColorManagement) PInvokeGdiPlus.GdipLoadImageFromStreamICM(stream, &result).ThrowIfFailed(); else PInvokeGdiPlus.GdipLoadImageFromStream(stream, &result).ThrowIfFailed(); return result; } [NullableContext(0)] internal unsafe Image(GpImage* nativeImage) { SetNativeImage(nativeImage); } public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } ~Image() { Dispose(false); } public unsafe object Clone() { GpImage* ptr = default(GpImage*); PInvokeGdiPlus.GdipCloneImage(_nativeImage, &ptr).ThrowIfFailed(); ValidateImage(ptr); GC.KeepAlive(this); return CreateImageObject(ptr); } protected unsafe virtual void Dispose(bool disposing) { if (_nativeImage != null) { if (Gdip.Initialized) PInvokeGdiPlus.GdipDisposeImage(_nativeImage); _nativeImage = null; } } public void Save(string filename) { Save(filename, RawFormat); } public void Save(string filename, ImageFormat format) { ArgumentNullException.ThrowIfNull(format, "format"); Guid guid = format.Encoder; if (guid == Guid.Empty) guid = ImageCodecInfoHelper.GetEncoderClsid(PInvokeGdiPlus.ImageFormatPNG); Save(filename, guid, null); } public void Save(string filename, System.Drawing.Imaging.ImageCodecInfo encoder, [Nullable(2)] System.Drawing.Imaging.EncoderParameters encoderParams) { Save(filename, encoder.Clsid, encoderParams); } private unsafe void Save(string filename, Guid encoder, [Nullable(2)] System.Drawing.Imaging.EncoderParameters encoderParams) { ArgumentNullException.ThrowIfNull(filename, "filename"); if (encoder == Guid.Empty) throw new ArgumentNullException("encoder"); ThrowIfDirectoryDoesntExist(filename); global::Windows.Win32.Graphics.GdiPlus.EncoderParameters* ptr = null; if (encoderParams != null) { _animatedGifRawData = null; ptr = encoderParams.ConvertToNative(); } try { if (_animatedGifRawData == null || !(RawFormat.Encoder == encoder)) try { IntPtr intPtr; if (filename == null) intPtr = (IntPtr)(void*)null; else { ref reference = ref filename.GetPinnableReference(); intPtr = (IntPtr)(&reference); } char* value = (char*)(long)intPtr; PInvokeGdiPlus.GdipSaveImageToFile(_nativeImage, value, &encoder, ptr).ThrowIfFailed(); } finally { ref reference = ref *(char*)null; } else { using (FileStream fileStream = File.OpenWrite(filename)) fileStream.Write(_animatedGifRawData, 0, _animatedGifRawData.Length); } } finally { if (ptr != null) Marshal.FreeHGlobal((IntPtr)ptr); GC.KeepAlive(this); GC.KeepAlive(encoderParams); } } public void Save(Stream stream, ImageFormat format) { ArgumentNullException.ThrowIfNull(format, "format"); this.Save(stream, format.Encoder, format.Guid, null); } public unsafe void Save(Stream stream, System.Drawing.Imaging.ImageCodecInfo encoder, [Nullable(2)] System.Drawing.Imaging.EncoderParameters encoderParams) { ArgumentNullException.ThrowIfNull(stream, "stream"); ArgumentNullException.ThrowIfNull(encoder, "encoder"); global::Windows.Win32.Graphics.GdiPlus.EncoderParameters* ptr = null; if (encoderParams != null) { _animatedGifRawData = null; ptr = encoderParams.ConvertToNative(); } try { this.Save(stream, encoder.Clsid, encoder.FormatID, ptr); } finally { if (ptr != null) Marshal.FreeHGlobal((IntPtr)ptr); GC.KeepAlive(this); GC.KeepAlive(encoderParams); } } [NullableContext(2)] public unsafe void SaveAdd(System.Drawing.Imaging.EncoderParameters encoderParams) { global::Windows.Win32.Graphics.GdiPlus.EncoderParameters* ptr = null; if (encoderParams != null) ptr = encoderParams.ConvertToNative(); _animatedGifRawData = null; try { PInvokeGdiPlus.GdipSaveAdd(_nativeImage, ptr).ThrowIfFailed(); } finally { if (ptr != null) Marshal.FreeHGlobal((IntPtr)ptr); GC.KeepAlive(this); GC.KeepAlive(encoderParams); } } public unsafe void SaveAdd(Image image, [Nullable(2)] System.Drawing.Imaging.EncoderParameters encoderParams) { ArgumentNullException.ThrowIfNull(image, "image"); global::Windows.Win32.Graphics.GdiPlus.EncoderParameters* ptr = null; if (encoderParams != null) ptr = encoderParams.ConvertToNative(); _animatedGifRawData = null; try { PInvokeGdiPlus.GdipSaveAddImage(_nativeImage, image._nativeImage, ptr).ThrowIfFailed(); } finally { if (ptr != null) Marshal.FreeHGlobal((IntPtr)ptr); GC.KeepAlive(this); GC.KeepAlive(image); GC.KeepAlive(encoderParams); } } private static void ThrowIfDirectoryDoesntExist(string filename) { string directoryName = Path.GetDirectoryName(filename); if (!string.IsNullOrEmpty(directoryName) && !Directory.Exists(directoryName)) throw new DirectoryNotFoundException(System.SR.Format(System.SR.TargetDirectoryDoesNotExist, directoryName, filename)); } public RectangleF GetBounds(ref GraphicsUnit pageUnit) { RectangleF imageBounds = this.GetImageBounds(); pageUnit = GraphicsUnit.Pixel; return imageBounds; } public unsafe Image GetThumbnailImage(int thumbWidth, int thumbHeight, [Nullable(2)] GetThumbnailImageAbort callback, IntPtr callbackData) { GpImage* nativeImage = default(GpImage*); PInvokeGdiPlus.GdipGetImageThumbnail(this.Pointer(), (uint)thumbWidth, (uint)thumbHeight, &nativeImage, (IntPtr)0, null).ThrowIfFailed(); GC.KeepAlive(this); return CreateImageObject(nativeImage); } [NullableContext(0)] internal unsafe static void ValidateImage(GpImage* image) { try { PInvokeGdiPlus.GdipImageForceValidation(image).ThrowIfFailed(); } catch { PInvokeGdiPlus.GdipDisposeImage(image); throw; } } public unsafe int GetFrameCount(FrameDimension dimension) { Guid guid = dimension.Guid; uint result = default(uint); PInvokeGdiPlus.GdipImageGetFrameCount(_nativeImage, &guid, &result).ThrowIfFailed(); GC.KeepAlive(this); return (int)result; } [NullableContext(2)] public unsafe System.Drawing.Imaging.PropertyItem GetPropertyItem(int propid) { uint num = default(uint); PInvokeGdiPlus.GdipGetPropertyItemSize(_nativeImage, (uint)propid, &num).ThrowIfFailed(); if (num != 0) { BufferScope<byte> bufferScope = new BufferScope<byte>((int)num); try { fixed (byte* ptr = &bufferScope.GetPinnableReference()) { global::Windows.Win32.Graphics.GdiPlus.PropertyItem* ptr2 = (global::Windows.Win32.Graphics.GdiPlus.PropertyItem*)ptr; PInvokeGdiPlus.GdipGetPropertyItem(_nativeImage, (uint)propid, num, ptr2).ThrowIfFailed(); GC.KeepAlive(this); return System.Drawing.Imaging.PropertyItem.FromNative(ptr2); } } finally { bufferScope.Dispose(); } } return null; } public unsafe int SelectActiveFrame(FrameDimension dimension, int frameIndex) { Guid guid = dimension.Guid; PInvokeGdiPlus.GdipImageSelectActiveFrame(_nativeImage, &guid, (uint)frameIndex).ThrowIfFailed(); GC.KeepAlive(this); return 0; } public unsafe void SetPropertyItem(System.Drawing.Imaging.PropertyItem propitem) { fixed (byte* value = propitem.Value) { global::Windows.Win32.Graphics.GdiPlus.PropertyItem propertyItem = default(global::Windows.Win32.Graphics.GdiPlus.PropertyItem); propertyItem.id = (uint)propitem.Id; propertyItem.length = (uint)propitem.Len; propertyItem.type = (ushort)propitem.Type; propertyItem.value = value; global::Windows.Win32.Graphics.GdiPlus.PropertyItem propertyItem2 = propertyItem; PInvokeGdiPlus.GdipSetPropertyItem(_nativeImage, &propertyItem2).ThrowIfFailed(); GC.KeepAlive(this); } } public unsafe void RotateFlip(RotateFlipType rotateFlipType) { PInvokeGdiPlus.GdipImageRotateFlip(_nativeImage, (global::Windows.Win32.Graphics.GdiPlus.RotateFlipType)rotateFlipType).ThrowIfFailed(); GC.KeepAlive(this); } public unsafe void RemovePropertyItem(int propid) { PInvokeGdiPlus.GdipRemovePropertyItem(_nativeImage, (uint)propid).ThrowIfFailed(); GC.KeepAlive(this); } [NullableContext(2)] public unsafe System.Drawing.Imaging.EncoderParameters GetEncoderParameterList(Guid encoder) { uint num = default(uint); PInvokeGdiPlus.GdipGetEncoderParameterListSize(_nativeImage, &encoder, &num).ThrowIfFailed(); if (num != 0) { BufferScope<byte> bufferScope = new BufferScope<byte>((int)num); try { System.Drawing.Imaging.EncoderParameters result; fixed (byte* ptr = &bufferScope.GetPinnableReference()) { PInvokeGdiPlus.GdipGetEncoderParameterList(_nativeImage, &encoder, num, (global::Windows.Win32.Graphics.GdiPlus.EncoderParameters*)ptr).ThrowIfFailed(); result = System.Drawing.Imaging.EncoderParameters.ConvertFromNative((global::Windows.Win32.Graphics.GdiPlus.EncoderParameters*)ptr); GC.KeepAlive(this); } return result; } finally { bufferScope.Dispose(); } } return null; } public static Bitmap FromHbitmap(IntPtr hbitmap) { return FromHbitmap(hbitmap, IntPtr.Zero); } public unsafe static Bitmap FromHbitmap(IntPtr hbitmap, IntPtr hpalette) { GpBitmap* ptr = default(GpBitmap*); PInvokeGdiPlus.GdipCreateBitmapFromHBITMAP((HBITMAP)hbitmap, (HPALETTE)hpalette, &ptr).ThrowIfFailed(); return new Bitmap(ptr); } public static bool IsExtendedPixelFormat(System.Drawing.Imaging.PixelFormat pixfmt) { return (pixfmt & System.Drawing.Imaging.PixelFormat.Extended) != System.Drawing.Imaging.PixelFormat.Undefined; } public static bool IsCanonicalPixelFormat(System.Drawing.Imaging.PixelFormat pixfmt) { return (pixfmt & System.Drawing.Imaging.PixelFormat.Canonical) != System.Drawing.Imaging.PixelFormat.Undefined; } [NullableContext(0)] internal unsafe void SetNativeImage(GpImage* handle) { if (handle == null) throw new ArgumentException(System.SR.NativeHandle0, "handle"); _nativeImage = handle; } public static int GetPixelFormatSize(System.Drawing.Imaging.PixelFormat pixfmt) { return ((int)pixfmt >> 8) & 255; } public static bool IsAlphaPixelFormat(System.Drawing.Imaging.PixelFormat pixfmt) { return (pixfmt & System.Drawing.Imaging.PixelFormat.Alpha) != System.Drawing.Imaging.PixelFormat.Undefined; } [NullableContext(0)] [return: Nullable(1)] internal unsafe static Image CreateImageObject(GpImage* nativeImage) { global::Windows.Win32.Graphics.GdiPlus.ImageType imageType = global::Windows.Win32.Graphics.GdiPlus.ImageType.ImageTypeUnknown; PInvokeGdiPlus.GdipGetImageType(nativeImage, &imageType); switch (imageType) { case global::Windows.Win32.Graphics.GdiPlus.ImageType.ImageTypeBitmap: return new Bitmap((GpBitmap*)nativeImage); case global::Windows.Win32.Graphics.GdiPlus.ImageType.ImageTypeMetafile: return new Metafile((IntPtr)nativeImage); default: throw new ArgumentException(System.SR.InvalidImage); } } [NullableContext(2)] internal unsafe static void GetAnimatedGifRawData([Nullable(1)] Image image, string filename, Stream dataStream) { if (image.RawFormat.Equals(ImageFormat.Gif)) { bool flag = false; uint num = default(uint); PInvokeGdiPlus.GdipImageGetFrameDimensionsCount(image._nativeImage, &num).ThrowIfFailed(); if (num != 0) { Span<Guid> initialBuffer = new Span<Guid>(stackalloc Guid[16], 16); BufferScope<Guid> bufferScope = new BufferScope<Guid>(initialBuffer, (int)num); try { fixed (Guid* dimensionIDs = &bufferScope.GetPinnableReference()) { PInvokeGdiPlus.GdipImageGetFrameDimensionsList(image._nativeImage, dimensionIDs, num).ThrowIfFailed(); } Guid guid = FrameDimension.Time.Guid; for (int i = 0; i < num; i++) { if (guid == bufferScope[i]) { flag = (image.GetFrameCount(FrameDimension.Time) > 1); break; } } if (flag) try { Stream stream = null; long position = 0; if (dataStream != null) { position = dataStream.Position; dataStream.Position = 0; } try { if (dataStream == null) { if (filename == null) throw new InvalidOperationException(); stream = (dataStream = File.OpenRead(filename)); } image._animatedGifRawData = new byte[(int)dataStream.Length]; dataStream.ReadExactly(image._animatedGifRawData, 0, (int)dataStream.Length); } finally { if (stream != null) stream.Close(); else dataStream.Position = position; } } catch (Exception ex) when (((ex is UnauthorizedAccessException || ex is DirectoryNotFoundException || ex is IOException || ex is NotSupportedException || ex is ObjectDisposedException || ex is ArgumentException) ? 1 : 0) != 0) { } } finally { bufferScope.Dispose(); } } } } } }