diff --git a/PInvoke/Gdi32/GdiObjExtensions.cs b/PInvoke/Gdi32/GdiObjExtensions.cs index ffeaaba8..133631cd 100644 --- a/PInvoke/Gdi32/GdiObjExtensions.cs +++ b/PInvoke/Gdi32/GdiObjExtensions.cs @@ -1,6 +1,7 @@ using System; using System.Drawing; using System.Drawing.Drawing2D; +using System.Runtime.InteropServices; using Vanara.Extensions; using Vanara.InteropServices; using static Vanara.PInvoke.Gdi32; @@ -54,6 +55,26 @@ namespace Vanara.PInvoke } } + /// Determines whether the bitmap is a bottom-up DIB. + /// The handle of the bitmap to assess. + /// if the specified bitmap is a bottom-up DIB; otherwise, . + public static bool IsBottomUpDIB(this in HBITMAP hbmp) + { + var dibSz = Marshal.SizeOf(typeof(DIBSECTION)); + using var mem = GetObject(hbmp, dibSz); + return mem.Size == dibSz && mem.ToStructure().dsBmih.biHeight > 0; + } + + /// Determines whether the bitmap is a bottom-up DIB. + /// The handle of the bitmap to assess. + /// if the specified bitmap is a bottom-up DIB; otherwise, . + public static bool IsDIB(this in HBITMAP hbmp) + { + var dibSz = Marshal.SizeOf(typeof(DIBSECTION)); + using var mem = GetObject(hbmp, dibSz); + return mem.Size == dibSz; + } + /// Creates a from an preserving transparency, if possible. /// The HBITMAP value. /// The Bitmap instance. If is a NULL handle, is returned. @@ -63,37 +84,27 @@ namespace Vanara.PInvoke if (hbmp.IsNull) return null; try { - var dibsection = GetObject(hbmp); + var dib = GetObject(hbmp); + // If hbmp doesn't have ARGB, then just use Gdi+ - if (dibsection.dsBm.bmBitsPixel != 32) return Image.FromHbitmap((IntPtr)hbmp); - // Create resulting bitmap of same size with transparency and lock in memory - var bitmap = new Bitmap(dibsection.dsBm.bmWidth, dibsection.dsBm.bmHeight, System.Drawing.Imaging.PixelFormat.Format32bppArgb); - var bmpData = bitmap.LockBits(new Rectangle(Point.Empty, bitmap.Size), System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppArgb); - // Grab arrays to both DIB and result - using var mstr = new SafeNativeArray(dibsection.dsBm.bmBits, (int)dibsection.dsBmih.biSizeImage, false); - using var bstr = new SafeNativeArray(bmpData.Scan0, (int)dibsection.dsBmih.biSizeImage, false); - // Copy all semi-transparent bits - for (int i = 0; i < mstr.Count; i++) - { - var rgbquad = mstr[i]; - // If pixel is 100% transparent, skip pixel - if (rgbquad.rgbReserved != 0) - bstr[i] = rgbquad; - } - bitmap.UnlockBits(bmpData); + if (dib.dsBm.bmBitsPixel != 32) throw new Exception(); + + // Create resulting bitmap from DIB info + var bitmap = new Bitmap(dib.dsBmih.biWidth, dib.dsBmih.biHeight, dib.dsBm.bmWidthBytes, System.Drawing.Imaging.PixelFormat.Format32bppArgb, dib.dsBm.bmBits); + + // Hack to determine and fix if upside-down + //var lkBits = bitmap.LockBits(new System.Drawing.Rectangle(Point.Empty, bitmap.Size), System.Drawing.Imaging.ImageLockMode.ReadWrite, bitmap.PixelFormat); + //var stride = lkBits.Stride; + //bitmap.UnlockBits(lkBits); + //if (stride > 0) + // bitmap.RotateFlip(RotateFlipType.Rotate180FlipNone); + return bitmap; } - catch - { - return Image.FromHbitmap((IntPtr)hbmp); - } + catch { } + return Image.FromHbitmap((IntPtr)hbmp); } - /// Creates a from an preserving transparency, if possible. - /// The SafeHBITMAP value. - /// The Bitmap instance. If is a NULL handle, is returned. - public static Bitmap ToBitmap(this SafeHBITMAP hbmp) => ((HBITMAP)hbmp).ToBitmap(); - #if !NET20 && !NETSTANDARD2_0 && !NETCOREAPP2_0 && !NETCOREAPP2_1 /// Creates a from an preserving transparency, if possible. /// The HBITMAP value.