internal void CreateNativeContext() { var bmh = new BITMAPV5HEADER() { bV5Size = (uint)Marshal.SizeOf(typeof(BITMAPV5HEADER)), bV5Width = Size.Width, bV5Height = -Size.Height, bV5Planes = 1, bV5BitCount = 32, bV5Compression = BitmapCompressionMode.BI_RGB, bV5AlphaMask = ColorMask.Alpha, bV5RedMask = ColorMask.Red, bV5GreenMask = ColorMask.Green, bV5BlueMask = ColorMask.Blue }; blendFunc = new BLENDFUNCTION() { BlendOp = AC_SRC_OVER, BlendFlags = 0, SourceConstantAlpha = 255, AlphaFormat = AC_SRC_ALPHA }; screenDc = GetDC(IntPtr.Zero); memDc = CreateCompatibleDC(screenDc); native = CreateDIBSection(screenDc, ref bmh, 0, out scan0, IntPtr.Zero, 0); oldBitmap = SelectObject(memDc, native); }
internal Cursor CreateCursor(BitmapSource renderBitmap, int width, int height) { // unfortunately, this byte array will get placed on the large object heap more than likely ... byte[] pixels = GetBitmapPixels(renderBitmap, width, height); // -height specifies top-down bitmap BITMAPV5HEADER bInfo = new BITMAPV5HEADER(width, -height, 32); IntPtr ppvBits = IntPtr.Zero; BitmapHandle dibSectionHandle = null; try { dibSectionHandle = new BitmapHandle(CreateDIBSection(IntPtr.Zero, ref bInfo, DIB_RGB_COLORS, out ppvBits, IntPtr.Zero, 0)); // copy the pixels into the DIB section now ... Marshal.Copy(pixels, 0, ppvBits, pixels.Length); if (!dibSectionHandle.IsInvalid && ppvBits != IntPtr.Zero) { return CreateCursor(width, height, dibSectionHandle); } } finally { if (dibSectionHandle != null) { dibSectionHandle.Dispose(); } } return null; }
public uint GetImageSizeFromBitmapHeader(BITMAPV5HEADER bmi) { var imageSize = bmi.bV5SizeImage; if (bmi.bV5Compression == 0) { imageSize = (uint)(bmi.bV5Height * bmi.bV5Width * (bmi.bV5BitCount / 8)); } return(imageSize); }
static Bitmap CreateDrawingBitmapFromVersionOnePointer(IntPtr pointer, BITMAPV5HEADER infoHeader) { var stride = (int)(infoHeader.bV5SizeImage / infoHeader.bV5Height); var bitmap = new Bitmap( infoHeader.bV5Width, infoHeader.bV5Height, stride, infoHeader.bV5BitCount == 24 ? DrawingPixelFormat.Format24bppRgb : DrawingPixelFormat.Format32bppPArgb, new IntPtr(pointer.ToInt64() + infoHeader.bV5Size)); return(ConvertBitmapTo32Bit(bitmap)); }
private static void SetClipboardBitmap(Bitmap bitmap, byte[] pngData) { // https://stackoverflow.com/questions/15689541/win32-clipboard-and-alpha-channel-images #if !USE_V5_BITMAP_HEADER bitmap.RotateFlip(RotateFlipType.RotateNoneFlipY); // GDI+ bitmap data is flipped vertically, unflip before accessing bytes BitmapData data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); BITMAPINFOHEADER header = new BITMAPINFOHEADER(); header.biSize = Marshal.SizeOf(header); header.biWidth = bitmap.Width; header.biHeight = bitmap.Height; header.biPlanes = 1; header.biBitCount = 32; header.biCompression = (int)BitmapCompressionMode.BI_RGB; header.biSizeImage = bitmap.Width * bitmap.Height * 4; IntPtr hGlobal = Marshal.AllocHGlobal(Marshal.SizeOf(header) + header.biSizeImage); Marshal.StructureToPtr(header, hGlobal, false); memcpy(hGlobal + Marshal.SizeOf(header), data.Scan0, (uint)header.biSizeImage); SetClipboardData((uint)ClipboardType.CF_DIB, hGlobal); Marshal.FreeHGlobal(hGlobal); bitmap.UnlockBits(data); #else bitmap.RotateFlip(RotateFlipType.RotateNoneFlipY); // GDI+ bitmap data is flipped vertically, unflip before accessing bytes BitmapData data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); BITMAPV5HEADER header = new BITMAPV5HEADER(); header.bV5Size = Marshal.SizeOf(header); header.bV5Width = bitmap.Width; header.bV5Height = bitmap.Height; header.bV5Planes = 1; header.bV5BitCount = 32; header.bV5Compression = (int)BitmapCompressionMode.BI_BITFIELDS; header.bV5SizeImage = bitmap.Width * bitmap.Height * 4; header.bV5RedMask = 0x00FF0000; header.bV5GreenMask = 0x0000FF00; header.bV5BlueMask = 0x000000FF; header.bV5AlphaMask = 0xFF000000; header.bV5CSType = (uint)LogicalColorSpace.LCS_WINDOWS_COLOR_SPACE; header.bV5Intent = (uint)GamutMappingIntent.LCS_GM_IMAGES; IntPtr hGlobal = Marshal.AllocHGlobal(Marshal.SizeOf(header) + header.bV5SizeImage); Marshal.StructureToPtr(header, hGlobal, false); //Marshal.Copy(pngData, 0, hGlobal + Marshal.SizeOf(header), pngData.Length); memcpy(hGlobal + Marshal.SizeOf(header), data.Scan0, (uint)header.bV5SizeImage); SetClipboardData((uint)ClipboardType.CF_DIBV5, hGlobal); Marshal.FreeHGlobal(hGlobal); bitmap.UnlockBits(data); #endif }
const int CBM_INIT = 0x04;// /* initialize bitmap */ public static IntPtr Create32BppBitmap(Image sourceImage) { BITMAPV5HEADER bi = new BITMAPV5HEADER(); bi.bV5Size = (uint)Marshal.SizeOf(bi); bi.bV5Width = sourceImage.Width; bi.bV5Height = sourceImage.Height; bi.bV5Planes = 1; bi.bV5BitCount = 32; bi.bV5Compression = BI_BITFIELDS; // The following mask specification specifies a supported 32 BPP // alpha format for Windows XP. bi.bV5RedMask = 0x00FF0000; bi.bV5GreenMask = 0x0000FF00; bi.bV5BlueMask = 0x000000FF; bi.bV5AlphaMask = 0xFF000000; IntPtr hdc = User32.GetDC(IntPtr.Zero); IntPtr bits = IntPtr.Zero; // Create the DIB section with an alpha channel. IntPtr hBitmap = Gdi32.CreateDIBSection(hdc, bi, (uint)DIB.DIB_RGB_COLORS, out bits, IntPtr.Zero, 0); var hMemDC = Gdi32.CreateCompatibleDC(hdc); Gdi32.ReleaseDC(IntPtr.Zero, hdc); var sourceBits = ((Bitmap)sourceImage).LockBits( new Rectangle(0, 0, sourceImage.Width, sourceImage.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); var stride = sourceImage.Width * 4; for (int y = 0; y < sourceImage.Height; y++) { IntPtr DstDib = (IntPtr)(bits.ToInt32() + (y * stride)); IntPtr SrcDib = (IntPtr)(sourceBits.Scan0.ToInt32() + ((sourceImage.Height - 1 - y) * stride)); for (int x = 0; x < sourceImage.Width; x++) { Marshal.WriteInt32(DstDib, Marshal.ReadInt32(SrcDib)); DstDib = (IntPtr)(DstDib.ToInt32() + 4); SrcDib = (IntPtr)(SrcDib.ToInt32() + 4); } } return(hBitmap); }
byte[] GetImageBytesFromAllBytes(byte[] bytes, BITMAPV5HEADER bmi) { var stride = GetStrideFromBitmapHeader(bmi); var offset = bmi.bV5Size; if (bmi.bV5ClrUsed > 0) { offset += bmi.bV5ClrUsed * (uint)Marshal.SizeOf <RGBQUAD>(); } var imageSize = imageNativeApi.GetImageSizeFromBitmapHeader(bmi); var imageBytes = new byte[imageSize]; Array.Copy(bytes, offset, imageBytes, 0, imageBytes.Length); return(imageBytes); }
public static unsafe SafeProfileHandle CreateProfileFromLogicalColorSpace(BITMAPV5HEADER info) { // https://docs.microsoft.com/en-us/windows/win32/api/wingdi/ns-wingdi-logcolorspacew var lcs = new LOGCOLORSPACE { lcsCSType = ColorSpaceType.LCS_CALIBRATED_RGB, lcsVersion = 0x400, lcsSignature = 0x50534F43, // 'PSOC' lcsFilename = "\0", lcsIntent = info.bV5Intent, lcsEndpoints_1x = info.bV5Endpoints_1x, lcsEndpoints_1y = info.bV5Endpoints_1y, lcsEndpoints_1z = info.bV5Endpoints_1z, lcsEndpoints_2x = info.bV5Endpoints_2x, lcsEndpoints_2y = info.bV5Endpoints_2y, lcsEndpoints_2z = info.bV5Endpoints_2z, lcsEndpoints_3x = info.bV5Endpoints_3x, lcsEndpoints_3y = info.bV5Endpoints_3y, lcsEndpoints_3z = info.bV5Endpoints_3z, lcsGammaBlue = info.bV5GammaBlue, lcsGammaGreen = info.bV5GammaGreen, lcsGammaRed = info.bV5GammaRed, }; var success = CreateProfileFromLogColorSpace(ref lcs, out var hGlobal); if (!success) { throw new Win32Exception(); } var hsize = GlobalSize(hGlobal); var hptr = GlobalLock(hGlobal); try { return(OpenProfile((void *)hptr, (uint)hsize)); } finally { GlobalUnlock(hGlobal); GlobalFree(hGlobal); } }
private static void WriteDibV5ToStream(Stream stream, Bitmap image, byte[] imageData) { BITMAPV5HEADER bmi = new BITMAPV5HEADER { bV5Size = Marshal.SizeOf <BITMAPV5HEADER>(), bV5Width = image.Width, bV5Height = image.Height, bV5Planes = 1, bV5BitCount = 32, //bV5Compression = 3, bV5SizeImage = imageData.Length, bV5RedMask = 0x00FF0000, bV5GreenMask = 0x0000FF00, bV5BlueMask = 0x000000FF, bV5AlphaMask = 0xFF000000, bV5CSType = 0x73524742, // LCS_WINDOWS_COLOR_SPACE; //bV5CSType = 0x206E6957,// GLITCHED bV5Intent = 4, }; /*BITMAPV5HEADER bmi = new BITMAPV5HEADER(); * bmi.bV5Size = Marshal.SizeOf<BITMAPV5HEADER>(); * bmi.bV5Width = image.Width; * bmi.bV5Height = image.Height; * bmi.bV5Planes = 1; * bmi.bV5BitCount = 32; * //bmi.bV5Compression = 3; * bmi.bV5SizeImage = imageData.Length; * bmi.bV5RedMask = 0x00FF0000; * bmi.bV5GreenMask = 0x0000FF00; * bmi.bV5BlueMask = 0x000000FF; * bmi.bV5AlphaMask = 0xFF000000; * bmi.bV5CSType = 0x73524742;// LCS_WINDOWS_COLOR_SPACE; * //bmi.bV5CSType = 0x206E6957;// GLITCHED * bmi.bV5Intent = 4;*/ BinaryWriter writer = new BinaryWriter(stream); writer.WriteUnmanaged(bmi); /*writer.Write(0x000001E0); * writer.Write(0x000001E0); * writer.Write(0x00FF0000);*/ writer.Write(imageData); }
public GhostCursor(Visual visual) { BitmapSource renderBitmap = CaptureScreen(visual); BitmapSource actualCursor = CaptureCursor(); byte[] pixels = GetBitmapPixels(actualCursor, (int)actualCursor.Width, (int)actualCursor.Height); WriteableBitmap wrbmp = new WriteableBitmap(renderBitmap); wrbmp.WritePixels(new Int32Rect(0, 0, (int)actualCursor.Width, (int)actualCursor.Height), pixels, actualCursor.PixelWidth * actualCursor.Format.BitsPerPixel / 8, 0); int width = renderBitmap.PixelWidth; int height = renderBitmap.PixelHeight; int stride = width * 4; // unfortunately, this byte array will get placed on the large object heap more than likely ... pixels = GetBitmapPixels(wrbmp, width, height); // -height specifies top-down bitmap BITMAPV5HEADER bInfo = new BITMAPV5HEADER(width, -height, 32); IntPtr ppvBits = IntPtr.Zero; BitmapHandle dibSectionHandle = null; try { dibSectionHandle = new BitmapHandle(CreateDIBSection(IntPtr.Zero, ref bInfo, DIB_RGB_COLORS, out ppvBits, IntPtr.Zero, 0)); // copy the pixels into the DIB section now ... Marshal.Copy(pixels, 0, ppvBits, pixels.Length); if (!dibSectionHandle.IsInvalid && ppvBits != IntPtr.Zero) { CreateCursor(width, height, dibSectionHandle); } } finally { if (dibSectionHandle != null) { dibSectionHandle.Dispose(); } } }
byte[] HandleBitmapVersionFive(IntPtr pointer, BITMAPV5HEADER infoHeader) { using (var drawingBitmap = CreateDrawingBitmapFromVersionOnePointer(pointer, infoHeader)) { var renderTargetBitmapSource = new RenderTargetBitmap(infoHeader.bV5Width, infoHeader.bV5Height, 96, 96, PixelFormats.Pbgra32); var visual = new DrawingVisual(); var drawingContext = visual.RenderOpen(); drawingContext.DrawImage(CreateBitmapSourceFromBitmap(drawingBitmap), new Rect(0, 0, infoHeader.bV5Width, infoHeader.bV5Height)); renderTargetBitmapSource.Render(visual); return imagePersistenceService.ConvertBitmapSourceToByteArray(renderTargetBitmapSource); } }
byte[] HandleBitmapVersionFive(IntPtr pointer, BITMAPV5HEADER infoHeader) { using (var drawingBitmap = CreateDrawingBitmapFromVersionOnePointer(pointer, infoHeader)) { var renderTargetBitmapSource = new RenderTargetBitmap(infoHeader.bV5Width, infoHeader.bV5Height, 96, 96, PixelFormats.Pbgra32); var visual = new DrawingVisual(); var drawingContext = visual.RenderOpen(); drawingContext.DrawImage(CreateBitmapSourceFromBitmap(drawingBitmap), new Rect(0, 0, infoHeader.bV5Width, infoHeader.bV5Height)); renderTargetBitmapSource.Render(visual); return(imagePersistenceService.ConvertBitmapSourceToByteArray(renderTargetBitmapSource)); } }
internal void CreateNativeContext() { var bmh = new BITMAPV5HEADER() { bV5Size = (uint)Marshal.SizeOf(typeof(BITMAPV5HEADER)), bV5Width = Size.Width, bV5Height = -Size.Height, bV5Planes = 1, bV5BitCount = 32, bV5Compression = BitmapCompressionMode.BI_RGB, bV5AlphaMask = ColorMask.Alpha, bV5RedMask = ColorMask.Red, bV5GreenMask = ColorMask.Green, bV5BlueMask = ColorMask.Blue }; screenDc = GetDC(IntPtr.Zero); Skia_DC = CreateCompatibleDC(screenDc); native = CreateDIBSection(screenDc, ref bmh, 0, out scan0, IntPtr.Zero, 0); oldBitmap = SelectObject(Skia_DC, native); }
const int CBM_INIT = 0x04; // /* initialize bitmap */ /*public static IntPtr Create32BppBitmap(Image sourceImage) { * BITMAPV5HEADER bi = new BITMAPV5HEADER(); * bi.bV5Size = (uint) Marshal.SizeOf(bi); * bi.bV5Width = sourceImage.Width; * bi.bV5Height = sourceImage.Height; * bi.bV5Planes = 1; * bi.bV5BitCount = 32; * bi.bV5Compression = BI_BITFIELDS; * // The following mask specification specifies a supported 32 BPP * // alpha format for Windows XP. * bi.bV5RedMask = 0x00FF0000; * bi.bV5GreenMask = 0x0000FF00; * bi.bV5BlueMask = 0x000000FF; * bi.bV5AlphaMask = 0xFF000000; * * IntPtr hdc = User32.GetDC(IntPtr.Zero); * IntPtr bits = IntPtr.Zero; * * // Create the DIB section with an alpha channel. * IntPtr hBitmap = Gdi32.CreateDIBSection(hdc, bi, (uint) DIB.DIB_RGB_COLORS, * out bits, IntPtr.Zero, 0); * * var hMemDC = Gdi32.CreateCompatibleDC(hdc); * Gdi32.ReleaseDC(IntPtr.Zero, hdc); * * var sourceBits = ((Bitmap) sourceImage).LockBits( * new Rectangle(0, 0, sourceImage.Width, sourceImage.Height), ImageLockMode.ReadOnly, * PixelFormat.Format32bppArgb); * * var stride = sourceImage.Width*4; * for (int y = 0; y < sourceImage.Height; y++) { * IntPtr DstDib = (IntPtr) (bits.ToInt32() + (y * stride)); * IntPtr SrcDib = (IntPtr) (sourceBits.Scan0.ToInt32() + ((sourceImage.Height - 1 - y) * * stride)); * * for (int x = 0; x < sourceImage.Width; x++) { * Marshal.WriteInt32(DstDib, Marshal.ReadInt32(SrcDib)); * DstDib = (IntPtr) (DstDib.ToInt32() + 4); * SrcDib = (IntPtr) (SrcDib.ToInt32() + 4); * } * } * * return hBitmap; * }*/ public static byte[] CreatePackedDIBV5(Bitmap image) { BitmapData bmData; using (Bitmap bm32b = new Bitmap(image.Width, image.Height, PixelFormat.Format32bppArgb)) { using (Graphics g = Graphics.FromImage(bm32b)) g.DrawImage(image, new Rectangle(0, 0, bm32b.Width, bm32b.Height)); // Bitmap format has its lines reversed. bm32b.RotateFlip(RotateFlipType.Rotate180FlipX); bmData = image.LockBits(new Rectangle(0, 0, image.Width, image.Height), ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb); } uint bufferLen = (uint)(Marshal.SizeOf(typeof(BITMAPV5HEADER)) + (Marshal.SizeOf(typeof(uint)) * 3) + bmData.Height * bmData.Stride); //IntPtr hMem = GlobalAlloc(GHND | GMEM_DDESHARE, bufferLen); //IntPtr packedDIBV5 = GlobalLock(hMem); BITMAPV5HEADER bmi = new BITMAPV5HEADER(); // (BITMAPV5HEADER) Marshal.PtrToStructure(packedDIBV5, // typeof(BITMAPV5HEADER)); bmi.bV5Size = (uint)Marshal.SizeOf(typeof(BITMAPV5HEADER)); bmi.bV5Width = bmData.Width; bmi.bV5Height = bmData.Height; bmi.bV5BitCount = 32; bmi.bV5Planes = 1; bmi.bV5Compression = 0; // BI_BITFIELDS; bmi.bV5XPelsPerMeter = 0; bmi.bV5YPelsPerMeter = 0; bmi.bV5ClrUsed = 0; bmi.bV5ClrImportant = 0; bmi.bV5RedMask = 0x000000FF; bmi.bV5GreenMask = 0x0000FF00; bmi.bV5BlueMask = 0x00FF0000; bmi.bV5AlphaMask = 0xFF000000; bmi.bV5CSType = 0x206E6957; // LCS_WINDOWS_COLOR_SPACE; bmi.bV5GammaBlue = 0; bmi.bV5GammaGreen = 0; bmi.bV5GammaRed = 0; bmi.bV5ProfileData = 0; bmi.bV5ProfileSize = 0; bmi.bV5Reserved = 0; bmi.bV5Intent = 0; // LCS_GM_IMAGES; bmi.bV5SizeImage = (uint)(bmData.Height * bmData.Stride); bmi.bV5Endpoints.ciexyzBlue.ciexyzX = bmi.bV5Endpoints.ciexyzBlue.ciexyzY = bmi.bV5Endpoints.ciexyzBlue.ciexyzZ = 0; bmi.bV5Endpoints.ciexyzGreen.ciexyzX = bmi.bV5Endpoints.ciexyzGreen.ciexyzY = bmi.bV5Endpoints.ciexyzGreen.ciexyzZ = 0; bmi.bV5Endpoints.ciexyzRed.ciexyzX = bmi.bV5Endpoints.ciexyzRed.ciexyzY = bmi.bV5Endpoints.ciexyzRed.ciexyzZ = 0; //Marshal.StructureToPtr(bmi, packedDIBV5, false); BITFIELDS Masks = new BITFIELDS(); // (BITFIELDS) Marshal.PtrToStructure( //(IntPtr) (packedDIBV5.ToInt32() + bmi.bV5Size), typeof(BITFIELDS)); Masks.BlueMask = 0x000000FF; Masks.GreenMask = 0x0000FF00; Masks.RedMask = 0x00FF0000; //Marshal.StructureToPtr(Masks, (IntPtr) (packedDIBV5.ToInt32() + // bmi.bV5Size), false); //byte[] dibData = new byte[bufferLen]; byte[] imageData = new byte[bmi.bV5SizeImage]; using (MemoryStream ms = new MemoryStream()) { var writer = new BinaryWriter(ms); writer.WriteStruct(bmi); //writer.WriteStruct(Masks); Marshal.Copy(bmData.Scan0, imageData, 0, imageData.Length); writer.Write(imageData); return(ms.ToArray()); } /*long offsetBits = bmi.bV5Size + Marshal.SizeOf(typeof(uint))*3; * IntPtr bits = (IntPtr) (packedDIBV5.ToInt32() + offsetBits); * * for (int y = 0; y < bmData.Height; y++) { * IntPtr DstDib = (IntPtr) (bits.ToInt32() + (y*bmData.Stride)); * IntPtr SrcDib = (IntPtr) (bmData.Scan0.ToInt32() + ((bmData.Height - 1 - y)* * bmData.Stride)); * * for (int x = 0; x < bmData.Width; x++) { * Marshal.WriteInt32(DstDib, Marshal.ReadInt32(SrcDib)); * DstDib = (IntPtr) (DstDib.ToInt32() + 4); * SrcDib = (IntPtr) (SrcDib.ToInt32() + 4); * } * } * * // Create the DIB section with an alpha channel. * IntPtr hdc = User32.GetDC(IntPtr.Zero); * //IntPtr hdc = Gdi32.CreateCompatibleDC(IntPtr.Zero); * GCHandle handle = GCHandle.Alloc(bmi, GCHandleType.Pinned); * IntPtr hBitmap = Gdi32.CreateDIBitmap(hdc, handle.AddrOfPinnedObject(), CBM_INIT, * bits, handle.AddrOfPinnedObject(), (uint) DIB.DIB_RGB_COLORS); * bm.UnlockBits(bmData); * * GlobalUnlock(hMem); * * * return hBitmap;*/ }
internal static extern IntPtr CreateDIBSection(IntPtr hdc, [In] ref BITMAPV5HEADER pbmi, uint iUsage, out IntPtr ppvBits, IntPtr hSection, uint dwOffset);
public static byte[] WriteToBMP(ref BITMAP_WRITE_REQUEST info, byte *sourceBufferStart, BITMASKS masks, ushort nbits, uint bcwFlags) { bool skipFileHeader = (bcwFlags & BC_WRITE_SKIP_FH) > 0; bool forceV5 = (bcwFlags & BC_WRITE_V5) > 0; bool forceInfo = (bcwFlags & BC_WRITE_VINFO) > 0; if (forceV5 && forceInfo) { throw new ArgumentException("ForceV5 and ForceInfo flags can not be used at the same time."); } // NOT SUPPORTED RIGHT NOW bool iccEmbed = false; byte[] iccProfileData = new byte[0]; var hasAlpha = masks.maskAlpha != 0; if (nbits < 16 && (info.imgColorTable == null || info.imgColorTable.Length == 0)) { throw new InvalidOperationException("A indexed bitmap must have a color table / palette."); } //int dpiToPelsPM(double dpi) //{ // if (Math.Round(dpi) == 96d) return 0; // return (int)Math.Round(dpi / 0.0254d); //} uint paletteSize = info.imgColorTable == null ? 0 : (uint)info.imgColorTable.Length; var fhSize = (uint)Marshal.SizeOf <BITMAPFILEHEADER>(); var quadSize = (uint)Marshal.SizeOf <RGBQUAD>(); byte[] buffer; uint pxOffset, pxSize; // BI_BITFIELDS is not valid for 24bpp, so if the masks are not RGB we need to use a V5 header. //var nonStandard24bpp = nbits == 24 && !BitmapCorePixelFormat2.Bgr24.IsMatch(24, masks); BitmapCompressionMode compr = BitmapCompressionMode.BI_RGB; // some parsers do not respect the v5 header masks unless BI_BITFIELDS is used... // this is true of Chrome (only for 16bpp) and is also true of FireFox (16 and 32bpp) if (nbits == 16 || nbits == 32) { compr = BitmapCompressionMode.BI_BITFIELDS; } // write V5 header if embedded color profile or has alpha data if (forceV5 || hasAlpha || iccEmbed) { var v5Size = (uint)Marshal.SizeOf <BITMAPV5HEADER>(); // Typical structure: // - BITMAPFILEHEADER (Optional) // - BITMAPV5HEADER // - * Note, never write BI_BITFIELDS at the end of a V5 header, these masks are contained within the header itself // - Color Table (Optional) // - Pixel Data // - Embedded Color Profile (Optional) var fh = new BITMAPFILEHEADER { bfType = BFH_BM, }; var v5 = new BITMAPV5HEADER { bV5Size = v5Size, bV5Planes = 1, bV5BitCount = nbits, bV5Height = info.imgTopDown ? -info.imgHeight : info.imgHeight, bV5Width = info.imgWidth, bV5Compression = compr, bV5XPelsPerMeter = 0, bV5YPelsPerMeter = 0, bV5RedMask = masks.maskRed, bV5GreenMask = masks.maskGreen, bV5BlueMask = masks.maskBlue, bV5AlphaMask = masks.maskAlpha, bV5ClrImportant = paletteSize, bV5ClrUsed = paletteSize, bV5SizeImage = (uint)(info.imgStride * info.imgHeight), bV5CSType = ColorSpaceType.LCS_sRGB, bV5Intent = Bv5Intent.LCS_GM_IMAGES, }; uint offset = skipFileHeader ? 0 : fhSize; offset += v5Size; offset += paletteSize * quadSize; // fh offset points to beginning of pixel data fh.bfOffBits = pxOffset = offset; pxSize = v5.bV5SizeImage; offset += v5.bV5SizeImage; if (iccEmbed) { v5.bV5CSType = ColorSpaceType.PROFILE_EMBEDDED; v5.bV5ProfileData = offset; v5.bV5ProfileSize = (uint)iccProfileData.Length; offset += v5.bV5ProfileSize; } // fh size must be total file size fh.bfSize = offset; buffer = new byte[offset]; offset = 0; if (!skipFileHeader) { StructUtil.SerializeTo(fh, buffer, ref offset); } StructUtil.SerializeTo(v5, buffer, ref offset); if (info.imgColorTable != null) { foreach (var p in info.imgColorTable) { StructUtil.SerializeTo(p, buffer, ref offset); } } Marshal.Copy((IntPtr)sourceBufferStart, buffer, (int)offset, (int)v5.bV5SizeImage); offset += v5.bV5SizeImage; if (iccEmbed) { Buffer.BlockCopy(iccProfileData, 0, buffer, (int)offset, iccProfileData.Length); } } else { var infoSize = (uint)Marshal.SizeOf <BITMAPINFOHEADER>(); // Typical structure: // - BITMAPFILEHEADER (Optional) // - BITMAPINFOHEADER // - BI_BITFIELDS (Optional) // - Color Table (Optional) // - Pixel Data // this would be ideal, we can specify transparency in VINFO headers... but many applications incl FireFox do not support this. // if (hasAlpha) compr = BitmapCompressionMode.BI_ALPHABITFIELDS; var fh = new BITMAPFILEHEADER { bfType = BFH_BM, }; var vinfo = new BITMAPINFOHEADER { bV5Size = infoSize, bV5Planes = 1, bV5BitCount = nbits, bV5Height = info.imgTopDown ? -info.imgHeight : info.imgHeight, bV5Width = info.imgWidth, bV5Compression = compr, bV5XPelsPerMeter = 0, bV5YPelsPerMeter = 0, bV5ClrImportant = paletteSize, bV5ClrUsed = paletteSize, bV5SizeImage = (uint)(info.imgStride * info.imgHeight), }; uint offset = skipFileHeader ? 0 : fhSize; offset += infoSize; if (compr == BitmapCompressionMode.BI_BITFIELDS) { offset += sizeof(uint) * 3; } offset += paletteSize * quadSize; // fh offset points to beginning of pixel data fh.bfOffBits = pxOffset = offset; pxSize = vinfo.bV5SizeImage; offset += vinfo.bV5SizeImage; // fh size must be total file size fh.bfSize = offset; buffer = new byte[offset]; offset = 0; if (!skipFileHeader) { StructUtil.SerializeTo(fh, buffer, ref offset); } StructUtil.SerializeTo(vinfo, buffer, ref offset); if (compr == BitmapCompressionMode.BI_BITFIELDS) { Buffer.BlockCopy(masks.BITFIELDS(), 0, buffer, (int)offset, sizeof(uint) * 3); offset += sizeof(uint) * 3; } if (info.imgColorTable != null) { foreach (var p in info.imgColorTable) { StructUtil.SerializeTo(p, buffer, ref offset); } } Marshal.Copy((IntPtr)sourceBufferStart, buffer, (int)offset, (int)vinfo.bV5SizeImage); } return(buffer); }
public static extern IntPtr CreateDIBSection(IntPtr hdc, [In] ref BITMAPV5HEADER pbmi, uint pila, out IntPtr ppvBits, IntPtr hSection, uint dwOffset);
public static IntPtr CreatePackedDIBV5(Bitmap bm) { BitmapData bmData = bm.LockBits(new Rectangle(0, 0, bm.Width, bm.Height), ImageLockMode.ReadOnly, bm.PixelFormat); uint bufferLen = (uint)(Marshal.SizeOf(typeof(BITMAPV5HEADER)) + (Marshal.SizeOf(typeof(uint)) * 3) + bmData.Height * bmData.Stride); IntPtr hMem = GlobalAlloc(GHND | GMEM_DDESHARE, bufferLen); IntPtr packedDIBV5 = GlobalLock(hMem); BITMAPV5HEADER bmi = (BITMAPV5HEADER)Marshal.PtrToStructure(packedDIBV5, typeof(BITMAPV5HEADER)); bmi.bV5Size = (uint)Marshal.SizeOf(typeof(BITMAPV5HEADER)); bmi.bV5Width = bmData.Width; bmi.bV5Height = bmData.Height; bmi.bV5BitCount = 32; bmi.bV5Planes = 1; bmi.bV5Compression = BI_BITFIELDS; bmi.bV5XPelsPerMeter = 0; bmi.bV5YPelsPerMeter = 0; bmi.bV5ClrUsed = 0; bmi.bV5ClrImportant = 0; bmi.bV5BlueMask = 0x000000FF; bmi.bV5GreenMask = 0x0000FF00; bmi.bV5RedMask = 0x00FF0000; bmi.bV5AlphaMask = 0xFF000000; bmi.bV5CSType = LCS_WINDOWS_COLOR_SPACE; bmi.bV5GammaBlue = 0; bmi.bV5GammaGreen = 0; bmi.bV5GammaRed = 0; bmi.bV5ProfileData = 0; bmi.bV5ProfileSize = 0; bmi.bV5Reserved = 0; bmi.bV5Intent = LCS_GM_IMAGES; bmi.bV5SizeImage = (uint)(bmData.Height * bmData.Stride); bmi.bV5Endpoints.ciexyzBlue.ciexyzX = bmi.bV5Endpoints.ciexyzBlue.ciexyzY = bmi.bV5Endpoints.ciexyzBlue.ciexyzZ = 0; bmi.bV5Endpoints.ciexyzGreen.ciexyzX = bmi.bV5Endpoints.ciexyzGreen.ciexyzY = bmi.bV5Endpoints.ciexyzGreen.ciexyzZ = 0; bmi.bV5Endpoints.ciexyzRed.ciexyzX = bmi.bV5Endpoints.ciexyzRed.ciexyzY = bmi.bV5Endpoints.ciexyzRed.ciexyzZ = 0; Marshal.StructureToPtr(bmi, packedDIBV5, false); BITFIELDS Masks = (BITFIELDS)Marshal.PtrToStructure( (IntPtr)(packedDIBV5.ToInt32() + bmi.bV5Size), typeof(BITFIELDS)); Masks.BlueMask = 0x000000FF; Masks.GreenMask = 0x0000FF00; Masks.RedMask = 0x00FF0000; Marshal.StructureToPtr(Masks, (IntPtr)(packedDIBV5.ToInt32() + bmi.bV5Size), false); long offsetBits = bmi.bV5Size + Marshal.SizeOf(typeof(uint)) * 3; IntPtr bits = (IntPtr)(packedDIBV5.ToInt32() + offsetBits); for (int y = 0; y < bmData.Height; y++) { IntPtr DstDib = (IntPtr)(bits.ToInt32() + (y * bmData.Stride)); IntPtr SrcDib = (IntPtr)(bmData.Scan0.ToInt32() + ((bmData.Height - 1 - y) * bmData.Stride)); for (int x = 0; x < bmData.Width; x++) { Marshal.WriteInt32(DstDib, Marshal.ReadInt32(SrcDib)); DstDib = (IntPtr)(DstDib.ToInt32() + 4); SrcDib = (IntPtr)(SrcDib.ToInt32() + 4); } } // Create the DIB section with an alpha channel. IntPtr hdc = User32.GetDC(IntPtr.Zero); //IntPtr hdc = Gdi32.CreateCompatibleDC(IntPtr.Zero); GCHandle handle = GCHandle.Alloc(bmi, GCHandleType.Pinned); /*IntPtr hBitmap = Gdi32.CreateDIBSection(hdc, handle.AddrOfPinnedObject(), (uint)SharpThumbnailHandler.DIB.DIB_RGB_COLORS, * out bits, IntPtr.Zero, 0);*/ IntPtr hBitmap = Gdi32.CreateDIBitmap(hdc, handle.AddrOfPinnedObject(), CBM_INIT, bits, handle.AddrOfPinnedObject(), (uint)DIB.DIB_RGB_COLORS); bm.UnlockBits(bmData); GlobalUnlock(hMem); return(hBitmap); }
static Bitmap CreateDrawingBitmapFromVersionOnePointer(IntPtr pointer, BITMAPV5HEADER infoHeader) { var stride = (int)(infoHeader.bV5SizeImage / infoHeader.bV5Height); var bitmap = new Bitmap( infoHeader.bV5Width, infoHeader.bV5Height, stride, infoHeader.bV5BitCount == 24 ? DrawingPixelFormat.Format24bppRgb : DrawingPixelFormat.Format32bppPArgb, new IntPtr(pointer.ToInt64() + infoHeader.bV5Size)); return ConvertBitmapTo32Bit(bitmap); }
int GetStrideFromBitmapHeader(BITMAPV5HEADER bmi) { var imageSize = imageNativeApi.GetImageSizeFromBitmapHeader(bmi); return((int)(imageSize / bmi.bV5Height)); }