/// <summary>Initializes a new instance of the <see cref="BITMAPINFOHEADER"/> structure.</summary> /// <param name="width">The width.</param> /// <param name="height">The height.</param> /// <param name="bitCount">The bit count.</param> public BITMAPINFOHEADER(int width, int height, ushort bitCount = 32) : this() { biSize = Marshal.SizeOf(typeof(BITMAPINFO)); biWidth = width; biHeight = height; biPlanes = 1; biBitCount = bitCount; biCompression = BitmapCompressionMode.BI_RGB; biSizeImage = 0; // (uint)width * (uint)height * bitCount / 8; }
public BITMAPINFOHEADER(int width, int height, ushort bitCount) { biSize = (uint)Marshal.SizeOf(typeof(BITMAPINFOHEADER)); biWidth = width; biHeight = height; biPlanes = 1; biBitCount = bitCount; biCompression = BitmapCompressionMode.BI_RGB; biSizeImage = 0; biXPelsPerMeter = 0; biYPelsPerMeter = 0; biClrUsed = 0; biClrImportant = 0; }
public BITMAPINFOHEADER(int width, int height, uint sizeImg = 0, uint bSize = 40, uint clrUsed = 256, uint clrImportant = 0, BitmapCompressionMode mode = BitmapCompressionMode.BI_RGB, ushort bpp = 8, ushort planes = 1) { biSize = bSize; biWidth = width; biHeight = height; biPlanes = planes; biBitCount = bpp; biCompression = mode; biSizeImage = sizeImg; biXPelsPerMeter = 0; biYPelsPerMeter = 0; biClrUsed = clrUsed; biClrImportant = clrImportant; }
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 BITMAPINFOHEADER(int width, int height, ushort bitCount) { biSize = (uint)Marshal.SizeOf(typeof(BITMAPINFOHEADER)); biWidth = width; biHeight = height; biPlanes = 1; biBitCount = bitCount; biCompression = BitmapCompressionMode.BI_RGB; biSizeImage = 0; biXPelsPerMeter = 0; biYPelsPerMeter = 0; biClrUsed = 0; biClrImportant = 0; }