Bitmap
Encapsulates a GDI+ bitmap, which consists of the pixel data for a graphics image and its attributes. A Bitmap is an object used to work with images defined by pixel data.
using System.ComponentModel;
using System.Drawing.Imaging;
using System.Drawing.Imaging.Effects;
using System.IO;
using System.Runtime.CompilerServices;
using System.Runtime.Serialization;
using Windows.Win32;
using Windows.Win32.Foundation;
using Windows.Win32.Graphics.GdiPlus;
using Windows.Win32.System.Com;
using Windows.Win32.UI.WindowsAndMessaging;
namespace System.Drawing
{
[Serializable]
[NullableContext(1)]
[Nullable(0)]
[Editor("System.Drawing.Design.BitmapEditor, 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")]
[TypeForwardedFrom("System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")]
public sealed class Bitmap : Image, IPointer<GpBitmap>
{
private static readonly Color s_defaultTransparentColor = Color.LightGray;
unsafe IntPtr IPointer<GpBitmap>.Pointer {
get {
return (IntPtr)((Image)this).Pointer();
}
}
private Bitmap()
{
}
[NullableContext(0)]
internal unsafe Bitmap(GpBitmap* ptr)
{
SetNativeImage((GpImage*)ptr);
}
public Bitmap(string filename)
: this(filename, false)
{
}
public unsafe Bitmap(string filename, bool useIcm)
{
filename = Path.GetFullPath(filename);
IntPtr intPtr;
if (filename == null)
intPtr = (IntPtr)(void*)null;
else {
ref reference = ref filename.GetPinnableReference();
intPtr = (IntPtr)(&reference);
}
char* value = (char*)(long)intPtr;
GpBitmap* ptr = default(GpBitmap*);
(useIcm ? PInvokeGdiPlus.GdipCreateBitmapFromFileICM(value, &ptr) : PInvokeGdiPlus.GdipCreateBitmapFromFile(value, &ptr)).ThrowIfFailed();
ref reference = ref *(char*)null;
Image.ValidateImage((GpImage*)ptr);
SetNativeImage((GpImage*)ptr);
Image.GetAnimatedGifRawData(this, filename, null);
}
public Bitmap(Stream stream)
: this(stream, false)
{
}
public unsafe Bitmap(Stream stream, bool useIcm)
{
ArgumentNullException.ThrowIfNull(stream, "stream");
ComScope<IStream> scope = stream.ToIStream(true);
try {
GpBitmap* ptr = null;
(useIcm ? PInvokeGdiPlus.GdipCreateBitmapFromStreamICM((IStream*)ref scope, &ptr) : PInvokeGdiPlus.GdipCreateBitmapFromStream((IStream*)ref scope, &ptr)).ThrowIfFailed();
Image.ValidateImage((GpImage*)ptr);
SetNativeImage((GpImage*)ptr);
Image.GetAnimatedGifRawData(this, null, stream);
} finally {
scope.Dispose();
}
}
public Bitmap(Type type, string resource)
: this(GetResourceStream(type, resource))
{
}
private static Stream GetResourceStream(Type type, string resource)
{
ArgumentNullException.ThrowIfNull(type, "type");
ArgumentNullException.ThrowIfNull(resource, "resource");
Stream manifestResourceStream = type.Module.Assembly.GetManifestResourceStream(type, resource);
if (manifestResourceStream == null)
throw new ArgumentException(System.SR.Format(System.SR.ResourceNotFound, type, resource));
return manifestResourceStream;
}
public Bitmap(int width, int height)
: this(width, height, System.Drawing.Imaging.PixelFormat.Format32bppArgb)
{
}
public unsafe Bitmap(int width, int height, Graphics g)
{
ArgumentNullException.ThrowIfNull(g, "g");
GpBitmap* nativeImage = default(GpBitmap*);
PInvokeGdiPlus.GdipCreateBitmapFromGraphics(width, height, g.NativeGraphics, &nativeImage).ThrowIfFailed();
SetNativeImage((GpImage*)nativeImage);
GC.KeepAlive(g);
}
public unsafe Bitmap(int width, int height, int stride, System.Drawing.Imaging.PixelFormat format, IntPtr scan0)
{
GpBitmap* nativeImage = default(GpBitmap*);
PInvokeGdiPlus.GdipCreateBitmapFromScan0(width, height, stride, (int)format, (byte*)(long)scan0, &nativeImage).ThrowIfFailed();
SetNativeImage((GpImage*)nativeImage);
}
public unsafe Bitmap(int width, int height, System.Drawing.Imaging.PixelFormat format)
{
GpBitmap* nativeImage = default(GpBitmap*);
PInvokeGdiPlus.GdipCreateBitmapFromScan0(width, height, 0, (int)format, null, &nativeImage).ThrowIfFailed();
SetNativeImage((GpImage*)nativeImage);
}
public Bitmap(Image original)
: this(original, original.Width, original.Height)
{
}
public Bitmap(Image original, Size newSize)
: this(original, newSize.Width, newSize.Height)
{
}
public Bitmap(Image original, int width, int height)
: this(width, height, System.Drawing.Imaging.PixelFormat.Format32bppArgb)
{
ArgumentNullException.ThrowIfNull(original, "original");
using (Graphics graphics = Graphics.FromImage(this)) {
graphics.Clear(Color.Transparent);
graphics.DrawImage(original, 0, 0, width, height);
}
}
private Bitmap(SerializationInfo info, StreamingContext context)
: base(info, context)
{
}
public unsafe static Bitmap FromHicon(IntPtr hicon)
{
GpBitmap* ptr = default(GpBitmap*);
PInvokeGdiPlus.GdipCreateBitmapFromHICON((HICON)hicon, &ptr).ThrowIfFailed();
return new Bitmap(ptr);
}
public unsafe static Bitmap FromResource(IntPtr hinstance, string bitmapName)
{
ArgumentNullException.ThrowIfNull(bitmapName, "bitmapName");
GpBitmap* ptr = null;
IntPtr intPtr;
if (bitmapName == null)
intPtr = (IntPtr)(void*)null;
else {
ref reference = ref bitmapName.GetPinnableReference();
intPtr = (IntPtr)(&reference);
}
char* value = (char*)(long)intPtr;
PInvokeGdiPlus.GdipCreateBitmapFromResource((HINSTANCE)hinstance, value, &ptr).ThrowIfFailed();
ref reference = ref *(char*)null;
return new Bitmap(ptr);
}
[EditorBrowsable(EditorBrowsableState.Advanced)]
public IntPtr GetHbitmap()
{
return GetHbitmap(Color.LightGray);
}
[EditorBrowsable(EditorBrowsableState.Advanced)]
public IntPtr GetHbitmap(Color background)
{
try {
return this.GetHBITMAP(background);
} catch (ArgumentException) {
if (base.Width >= 32767 || base.Height >= 32767)
throw new ArgumentException(System.SR.GdiplusInvalidSize);
throw;
}
}
[EditorBrowsable(EditorBrowsableState.Advanced)]
public unsafe IntPtr GetHicon()
{
HICON value = default(HICON);
PInvokeGdiPlus.GdipCreateHICONFromBitmap(this.Pointer(), &value).ThrowIfFailed();
GC.KeepAlive(this);
return value;
}
public unsafe Bitmap Clone(RectangleF rect, System.Drawing.Imaging.PixelFormat format)
{
if (rect.Width == 0 || rect.Height == 0)
throw new ArgumentException(System.SR.Format(System.SR.GdiplusInvalidRectangle, rect.ToString()));
GpBitmap* ptr = default(GpBitmap*);
Status status = PInvokeGdiPlus.GdipCloneBitmapArea(rect.X, rect.Y, rect.Width, rect.Height, (int)format, this.Pointer(), &ptr);
if (status != 0 || ptr == null)
throw Gdip.StatusException(status);
GC.KeepAlive(this);
return new Bitmap(ptr);
}
public void MakeTransparent()
{
Color pixel = s_defaultTransparentColor;
if (base.Height > 0 && base.Width > 0)
pixel = GetPixel(0, base.Size.Height - 1);
if (pixel.A >= 255)
MakeTransparent(pixel);
}
public unsafe void MakeTransparent(Color transparentColor)
{
if (base.RawFormat.Guid == ImageFormat.Icon.Guid)
throw new InvalidOperationException(System.SR.CantMakeIconTransparent);
Size size = base.Size;
using (Bitmap bitmap = new Bitmap(size.Width, size.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb))
using (Graphics graphics = Graphics.FromImage(bitmap)) {
graphics.Clear(Color.Transparent);
Rectangle destRect = new Rectangle(0, 0, size.Width, size.Height);
using (ImageAttributes imageAttributes = new ImageAttributes()) {
imageAttributes.SetColorKey(transparentColor, transparentColor);
graphics.DrawImage(this, destRect, 0, 0, size.Width, size.Height, GraphicsUnit.Pixel, imageAttributes, null, (IntPtr)0);
}
GpBitmap* nativeImage = this.Pointer();
SetNativeImage((GpImage*)bitmap.Pointer());
bitmap.SetNativeImage((GpImage*)nativeImage);
}
}
public System.Drawing.Imaging.BitmapData LockBits(Rectangle rect, System.Drawing.Imaging.ImageLockMode flags, System.Drawing.Imaging.PixelFormat format)
{
return LockBits(rect, flags, format, new System.Drawing.Imaging.BitmapData());
}
public unsafe System.Drawing.Imaging.BitmapData LockBits(Rectangle rect, System.Drawing.Imaging.ImageLockMode flags, System.Drawing.Imaging.PixelFormat format, System.Drawing.Imaging.BitmapData bitmapData)
{
ArgumentNullException.ThrowIfNull(bitmapData, "bitmapData");
fixed (int* ptr = &bitmapData.GetPinnableReference()) {
void* source = ptr;
this.LockBits(rect, (global::Windows.Win32.Graphics.GdiPlus.ImageLockMode)flags, (global::Windows.Win32.Graphics.GdiPlus.PixelFormat)format, ref Unsafe.AsRef<global::Windows.Win32.Graphics.GdiPlus.BitmapData>(source));
}
GC.KeepAlive(this);
return bitmapData;
}
public unsafe void UnlockBits(System.Drawing.Imaging.BitmapData bitmapdata)
{
ArgumentNullException.ThrowIfNull(bitmapdata, "bitmapdata");
fixed (int* ptr = &bitmapdata.GetPinnableReference()) {
void* source = ptr;
this.UnlockBits(ref Unsafe.AsRef<global::Windows.Win32.Graphics.GdiPlus.BitmapData>(source));
}
GC.KeepAlive(this);
}
public unsafe Color GetPixel(int x, int y)
{
if (x < 0 || x >= base.Width)
throw new ArgumentOutOfRangeException("x", System.SR.ValidRangeX);
if (y < 0 || y >= base.Height)
throw new ArgumentOutOfRangeException("y", System.SR.ValidRangeY);
uint argb = default(uint);
PInvokeGdiPlus.GdipBitmapGetPixel(this.Pointer(), x, y, &argb).ThrowIfFailed();
GC.KeepAlive(this);
return Color.FromArgb((int)argb);
}
public unsafe void SetPixel(int x, int y, Color color)
{
if ((base.PixelFormat & System.Drawing.Imaging.PixelFormat.Indexed) != 0)
throw new InvalidOperationException(System.SR.GdiplusCannotSetPixelFromIndexedPixelFormat);
if (x < 0 || x >= base.Width)
throw new ArgumentOutOfRangeException("x", System.SR.ValidRangeX);
if (y < 0 || y >= base.Height)
throw new ArgumentOutOfRangeException("y", System.SR.ValidRangeY);
PInvokeGdiPlus.GdipBitmapSetPixel(this.Pointer(), x, y, (uint)color.ToArgb()).ThrowIfFailed();
GC.KeepAlive(this);
}
public unsafe void SetResolution(float xDpi, float yDpi)
{
PInvokeGdiPlus.GdipBitmapSetResolution(this.Pointer(), xDpi, yDpi).ThrowIfFailed();
GC.KeepAlive(this);
}
public unsafe Bitmap Clone(Rectangle rect, System.Drawing.Imaging.PixelFormat format)
{
if (rect.Width == 0 || rect.Height == 0)
throw new ArgumentException(System.SR.Format(System.SR.GdiplusInvalidRectangle, rect.ToString()));
GpBitmap* ptr = default(GpBitmap*);
Status status = PInvokeGdiPlus.GdipCloneBitmapAreaI(rect.X, rect.Y, rect.Width, rect.Height, (int)format, this.Pointer(), &ptr);
if (status != 0 || ptr == null)
throw Gdip.StatusException(status);
GC.KeepAlive(this);
return new Bitmap(ptr);
}
public unsafe void ApplyEffect(Effect effect, Rectangle area = default(Rectangle))
{
RECT rECT = area;
PInvokeGdiPlus.GdipBitmapApplyEffect(this.Pointer(), effect.Pointer(), (RECT*)(long)(area.IsEmpty ? ((IntPtr)(void*)null) : ((IntPtr)(&rECT))), false, null, null).ThrowIfFailed();
GC.KeepAlive(this);
GC.KeepAlive(effect);
}
[NullableContext(2)]
public unsafe void ConvertFormat(System.Drawing.Imaging.PixelFormat format, System.Drawing.Imaging.DitherType ditherType, System.Drawing.Imaging.PaletteType paletteType = System.Drawing.Imaging.PaletteType.Custom, System.Drawing.Imaging.ColorPalette palette = null, float alphaThresholdPercent = 0)
{
if (palette == null)
PInvokeGdiPlus.GdipBitmapConvertFormat(this.Pointer(), (int)format, (global::Windows.Win32.Graphics.GdiPlus.DitherType)ditherType, (global::Windows.Win32.Graphics.GdiPlus.PaletteType)paletteType, null, alphaThresholdPercent).ThrowIfFailed();
else {
BufferScope<uint> bufferScope = palette.ConvertToBuffer();
try {
fixed (uint* ptr = &bufferScope.GetPinnableReference()) {
void* palette2 = ptr;
PInvokeGdiPlus.GdipBitmapConvertFormat(this.Pointer(), (int)format, (global::Windows.Win32.Graphics.GdiPlus.DitherType)ditherType, (global::Windows.Win32.Graphics.GdiPlus.PaletteType)paletteType, (global::Windows.Win32.Graphics.GdiPlus.ColorPalette*)palette2, alphaThresholdPercent).ThrowIfFailed();
ptr = null;
}
} finally {
bufferScope.Dispose();
}
}
GC.KeepAlive(this);
}
public void ConvertFormat(System.Drawing.Imaging.PixelFormat format)
{
System.Drawing.Imaging.PixelFormat pixelFormat = base.PixelFormat;
int num = ((int)format >> 8) & 255;
int num2 = ((int)pixelFormat >> 8) & 255;
if (!format.HasFlag(System.Drawing.Imaging.PixelFormat.Indexed))
ConvertFormat(format, (num <= num2) ? System.Drawing.Imaging.DitherType.Solid : System.Drawing.Imaging.DitherType.None, System.Drawing.Imaging.PaletteType.Custom, null, 0);
else {
int num3;
switch (num) {
case 1:
num3 = 2;
break;
case 4:
num3 = 16;
break;
default:
num3 = 256;
break;
}
int num4 = num3;
bool flag = format.HasFlag(System.Drawing.Imaging.PixelFormat.Alpha);
if (flag)
num4++;
System.Drawing.Imaging.ColorPalette palette = System.Drawing.Imaging.ColorPalette.CreateOptimalPalette(num4, flag, this);
ConvertFormat(format, System.Drawing.Imaging.DitherType.ErrorDiffusion, System.Drawing.Imaging.PaletteType.Custom, palette, 0.25);
}
}
}
}