public static void ReadPixels(ref BITMAP_READ_DETAILS info, BitmapCorePixelFormat imgDestFmt, byte *sourceBufferStart, byte *destBufferStart, uint bcrFlags) { bool forcebgra32 = (bcrFlags & BC_READ_FORCE_BGRA32) > 0; bool preserveFormat = (bcrFlags & BC_READ_STRICT_PRESERVE_FORMAT) > 0; bool preserveAlpha = (bcrFlags & BC_READ_PRESERVE_INVALID_ALPHA) > 0; bool ignoreColorProfile = (bcrFlags & BC_READ_IGNORE_COLOR_PROFILE) > 0; if (preserveFormat && (info.imgSourceFmt != imgDestFmt)) { throw new NotSupportedException("StrictPreserveFormat was set while the source and/or target format is not supported."); } if (forcebgra32 && imgDestFmt != BitmapCorePixelFormat.Bgra32) { throw new InvalidOperationException("ForceBGRA32 was set but this is not supported with the source pixel format."); } if (imgDestFmt == null) { throw new ArgumentNullException(nameof(imgDestFmt)); } var compr = info.compression; if (compr == BitmapCompressionMode.BI_JPEG || compr == BitmapCompressionMode.BI_PNG) { throw new NotSupportedException("BI_JPEG and BI_PNG passthrough compression is not supported."); } else if (compr == BitmapCompressionMode.BI_RLE4 || compr == BitmapCompressionMode.BI_RLE8 || compr == BitmapCompressionMode.OS2_RLE24) { if (imgDestFmt != BitmapCorePixelFormat.Bgra32) { throw new NotSupportedException("RLE only supports being translated to Bgra32"); } BitmapCorePixelReader.ReadRLE_32(ref info, sourceBufferStart, destBufferStart); } else if (compr == BitmapCompressionMode.OS2_HUFFMAN1D) { BitmapCorePixelReader.ReadHuffmanG31D(ref info, sourceBufferStart, destBufferStart); } else if (info.imgSourceFmt == imgDestFmt && info.cTrueAlpha == imgDestFmt.HasAlpha) { // if the source is a known/supported/standard format, we can basically just copy the buffer straight over with no further processing if (info.imgTopDown) { var size = info.imgStride * info.imgHeight; Buffer.MemoryCopy(sourceBufferStart, destBufferStart, size, size); } else { uint stride = info.imgStride; int y, height = info.imgHeight, h = height; while (--h >= 0) { y = height - h - 1; byte *sourceln = sourceBufferStart + (y * stride); byte *destln = destBufferStart + (h * stride); Buffer.MemoryCopy(sourceln, destln, stride, stride); } } } else if (info.bbp <= 8) { if (imgDestFmt != BitmapCorePixelFormat.Bgra32) { throw new NotSupportedException("RLE only supports being translated to Bgra32"); } BitmapCorePixelReader.ReadIndexedTo32(ref info, sourceBufferStart, destBufferStart); } else if (info.bbp > 8) { BitmapCorePixelReader.ConvertChannelBGRA(ref info, imgDestFmt, sourceBufferStart, destBufferStart, preserveAlpha); } else { throw new NotSupportedException("Pixel format / compression not supported"); } // translate pixels to sRGB via embedded color profile if (!ignoreColorProfile && info.colorProfile != null && !info.colorProfile.IsInvalid && !imgDestFmt.IsIndexed && imgDestFmt.MscmsFormat.HasValue) { try { uint stride = StructUtil.CalcStride(imgDestFmt.BitsPerPixel, info.imgWidth); mscms.TransformPixelsTo_sRGB(info.colorProfile, imgDestFmt.MscmsFormat.Value, destBufferStart, info.imgWidth, info.imgHeight, stride, info.colorProfileIntent); } catch { // ignore color transformation errors } } }
public static byte[] WriteToBMP(ref BITMAP_WRITE_REQUEST info, byte *sourceBufferStart, BitmapCorePixelFormat fmt, uint bcwFlags) { return(WriteToBMP(ref info, sourceBufferStart, fmt.Masks, fmt.BitsPerPixel, bcwFlags)); }
public static void ConvertChannelBGRA(ref BITMAP_READ_DETAILS info, BitmapCorePixelFormat convertToFmt, byte *sourceBufferStart, byte *destBufferStart, bool preserveFakeAlpha) { var nbits = info.bbp; var width = info.imgWidth; var height = info.imgHeight; var upside_down = info.imgTopDown; var hasAlphaChannel = info.cTrueAlpha; var maskR = info.cMasks.maskRed; var maskG = info.cMasks.maskGreen; var maskB = info.cMasks.maskBlue; var maskA = info.cMasks.maskAlpha; int shiftR = 0, shiftG = 0, shiftB = 0, shiftA = 0; uint maxR = 0, maxG = 0, maxB = 0, maxA = 0; uint multR = 0, multG = 0, multB = 0, multA = 0; if (maskR != 0) { shiftR = StructUtil.CalcShift(maskR); maxR = maskR >> shiftR; multR = (uint)(Math.Ceiling(255d / maxR * 65536 * 256)); // bitshift << 24 } if (maskG != 0) { shiftG = StructUtil.CalcShift(maskG); maxG = maskG >> shiftG; multG = (uint)(Math.Ceiling(255d / maxG * 65536 * 256)); } if (maskB != 0) { shiftB = StructUtil.CalcShift(maskB); maxB = maskB >> shiftB; multB = (uint)(Math.Ceiling(255d / maxB * 65536 * 256)); } if (maskA != 0) { shiftA = StructUtil.CalcShift(maskA); maxA = maskA >> shiftA; multA = (uint)(Math.Ceiling(255d / maxA * 65536 * 256)); // bitshift << 24 } var write = convertToFmt.Write; uint source_stride = StructUtil.CalcStride(nbits, width); uint dest_stride = StructUtil.CalcStride(convertToFmt.BitsPerPixel, width); restartLoop: byte b, r, g, a; uint i32; byte *source, dest; int y, w, h = height, nbytes = (nbits / 8); if (hasAlphaChannel) { while (--h >= 0) { y = height - h - 1; dest = destBufferStart + ((upside_down ? y : h) * dest_stride); source = sourceBufferStart + (y * source_stride); w = width; while (--w >= 0) { i32 = *(uint *)source; b = (byte)((((i32 & maskB) >> shiftB) * multB) >> 24); g = (byte)((((i32 & maskG) >> shiftG) * multG) >> 24); r = (byte)((((i32 & maskR) >> shiftR) * multR) >> 24); a = (byte)((((i32 & maskA) >> shiftA) * multA) >> 24); dest = write(dest, b, g, r, a); source += nbytes; } } } else if (maskA != 0 && preserveFakeAlpha) // hasAlpha = false, and maskA != 0 - we might have _fake_ alpha.. need to check for it { while (--h >= 0) { y = height - h - 1; dest = destBufferStart + ((upside_down ? y : h) * dest_stride); source = sourceBufferStart + (y * source_stride); w = width; while (--w >= 0) { i32 = *(uint *)source; b = (byte)((((i32 & maskB) >> shiftB) * multB) >> 24); g = (byte)((((i32 & maskG) >> shiftG) * multG) >> 24); r = (byte)((((i32 & maskR) >> shiftR) * multR) >> 24); a = (byte)((((i32 & maskA) >> shiftA) * multA) >> 24); if (a != 0) { // this BMP should not have an alpha channel, but windows likes doing this and we need to detect it hasAlphaChannel = true; goto restartLoop; } dest = write(dest, b, g, r, 0xFF); source += nbytes; } } } else // simple bmp, no transparency { while (--h >= 0) { y = height - h - 1; dest = destBufferStart + ((upside_down ? y : h) * dest_stride); source = sourceBufferStart + (y * source_stride); w = width; while (--w >= 0) { i32 = *(uint *)source; b = (byte)((((i32 & maskB) >> shiftB) * multB) >> 24); g = (byte)((((i32 & maskG) >> shiftG) * multG) >> 24); r = (byte)((((i32 & maskR) >> shiftR) * multR) >> 24); dest = write(dest, b, g, r, 0xFF); source += nbytes; } } } }
public PxMap(PixelFormat wpf, BitmapCorePixelFormat core) { wpfFmt = wpf; coreFmt = core; }
public unsafe static BitmapSource Read(ref BITMAP_READ_DETAILS info, byte *pixels, uint bcrFlags) { // we do this parsing here since BitmapCore has no references to PresentationCore if (info.compression == BitmapCompressionMode.BI_PNG) { var stream = new PointerStream(pixels, info.imgDataSize); var png = new PngBitmapDecoder(stream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad); return(png.Frames[0]); } else if (info.compression == BitmapCompressionMode.BI_JPEG) { var stream = new PointerStream(pixels, info.imgDataSize); var jpg = new JpegBitmapDecoder(stream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad); return(jpg.Frames[0]); } PixelFormat wpfFmt = PixelFormats.Bgra32; BitmapCorePixelFormat coreFmt = BitmapCorePixelFormat.Bgra32; bool forceBgra32 = (bcrFlags & BitmapCore.BC_READ_FORCE_BGRA32) > 0; if (!forceBgra32 && info.imgSourceFmt != null) { var origFmt = info.imgSourceFmt; var pxarr = Formats.Where(m => m.coreFmt == origFmt).ToArray(); if (pxarr.Length > 0) { var px = pxarr.First(); wpfFmt = px.wpfFmt; coreFmt = px.coreFmt; } } BitmapPalette palette = null; if (info.imgColorTable.Length > 0) { var clrs = info.imgColorTable.Select(c => Color.FromRgb(c.rgbRed, c.rgbGreen, c.rgbBlue)); if (info.imgColorTable.Length > 256) // wpf throws on oversized palettes { clrs = clrs.Take(256); } palette = new BitmapPalette(clrs.ToList()); } var bitmap = new WriteableBitmap( info.imgWidth, info.imgHeight, info.dpiX, info.dpiY, wpfFmt, palette); var buf = (byte *)bitmap.BackBuffer; bitmap.Lock(); BitmapCore.ReadPixels(ref info, coreFmt, pixels, buf, bcrFlags); bitmap.AddDirtyRect(new System.Windows.Int32Rect(0, 0, info.imgWidth, info.imgHeight)); bitmap.Unlock(); bitmap.Freeze(); // dispose back buffer return(bitmap); }
/// <inheritdoc/> public override unsafe Bitmap Read(byte *data, int dataLength, BitmapReaderFlags rFlags) { uint bcrFlags = (uint)rFlags; BITMAP_READ_DETAILS info; BitmapCore.ReadHeader(data, dataLength, out info, bcrFlags); byte *pixels = data + info.imgDataOffset; // we do this parsing here since BitmapCore has no references to System.Drawing if (info.compression == BitmapCompressionMode.BI_PNG || info.compression == BitmapCompressionMode.BI_JPEG) { return(new Bitmap(new PointerStream(pixels, info.imgDataSize))); } // defaults PixelFormat gdiFmt = PixelFormat.Format32bppArgb; BitmapCorePixelFormat coreFmt = BitmapCorePixelFormat.Bgra32; var formatbgra32 = (rFlags & BitmapReaderFlags.ForceFormatBGRA32) > 0; if (!formatbgra32 && info.imgSourceFmt != null) { var origFmt = info.imgSourceFmt; if (origFmt == BitmapCorePixelFormat.Rgb24) { // we need BitmapCore to reverse the pixel order for GDI coreFmt = BitmapCorePixelFormat.Bgr24; gdiFmt = PixelFormat.Format24bppRgb; } else { var pxarr = Formats.Where(f => f.coreFmt == origFmt).ToArray(); if (pxarr.Length > 0) { var px = pxarr.First(); gdiFmt = px.gdiFmt; coreFmt = px.coreFmt; } } } Bitmap bitmap = new Bitmap(info.imgWidth, info.imgHeight, gdiFmt); var dlock = bitmap.LockBits(new Rectangle(0, 0, info.imgWidth, info.imgHeight), ImageLockMode.ReadWrite, gdiFmt); var buf = (byte *)dlock.Scan0; BitmapCore.ReadPixels(ref info, coreFmt, pixels, buf, bcrFlags); bitmap.UnlockBits(dlock); // update bitmap color palette var gdipPalette = bitmap.Palette; if (info.imgColorTable != null && gdipPalette?.Entries != null && gdipPalette.Entries.Length > 0) { for (int i = 0; i < info.imgColorTable.Length && i < gdipPalette.Entries.Length; i++) { var quad = info.imgColorTable[i]; gdipPalette.Entries[i] = Color.FromArgb(0xFF, quad.rgbRed, quad.rgbGreen, quad.rgbBlue); } bitmap.Palette = gdipPalette; } return(bitmap); }
public PxMap(PixelFormat gdi, BitmapCorePixelFormat core) { gdiFmt = gdi; coreFmt = core; }