public static Bitmap FromWic(IWICBitmapSource source) { Guid format; //Get the WIC pixel format source.GetPixelFormat(out format); //Get the matching GDI format PixelFormat gdiFormat = ConversionUtils.GetPixelFormat(format); //If it's not GDI-supported format, convert it to one. IWICComponentFactory factory = null; IWICFormatConverter converter = null; try { if (gdiFormat == PixelFormat.Undefined) { factory = (IWICComponentFactory) new WICImagingFactory(); converter = factory.CreateFormatConverter(); converter.Initialize(source, Consts.GUID_WICPixelFormat32bppBGRA, WICBitmapDitherType.WICBitmapDitherTypeNone, null, 0.9f, WICBitmapPaletteType.WICBitmapPaletteTypeCustom); gdiFormat = PixelFormat.Format32bppArgb; } IWICBitmapSource data = converter != null ? converter : source; //Get the dimensions of the WIC bitmap uint w, h; data.GetSize(out w, out h); Bitmap b = new Bitmap((int)w, (int)h, gdiFormat); BitmapData bd = b.LockBits(new Rectangle(0, 0, (int)w, (int)h), ImageLockMode.WriteOnly, b.PixelFormat); try { long result = CopyPixels(data, IntPtr.Zero, (uint)bd.Stride, (uint)(bd.Stride * bd.Height), bd.Scan0); if (result == 0x80070057) { throw new ArgumentException(); } if (result < 0) { throw new Exception("HRESULT " + result); } return(b); } finally { b.UnlockBits(bd); } } finally { if (converter != null) { Marshal.ReleaseComObject(converter); } if (factory != null) { Marshal.ReleaseComObject(factory); } } }
public static IWICBitmap ToWic(IWICComponentFactory factory, Bitmap bit) { Guid pixelFormat = ConversionUtils.FromPixelFormat(bit.PixelFormat); if (pixelFormat == Guid.Empty) { throw new NotSupportedException("PixelFormat " + bit.PixelFormat.ToString() + " not supported."); } BitmapData bd = bit.LockBits(new Rectangle(0, 0, bit.Width, bit.Height), ImageLockMode.ReadOnly, bit.PixelFormat); IWICBitmap b = null; IWICPalette p = null; try { //Create WIC bitmap directly from unmanaged memory long result = CreateBitmapFromMemory(factory, (uint)bit.Width, (uint)bit.Height, ref pixelFormat, (uint)bd.Stride, (uint)(bd.Stride * bd.Height), bd.Scan0, out b); //b = factory.CreateBitmapFromMemory((uint)bit.Width, (uint)bit.Height, ConversionUtils.FromPixelFormat(bit.PixelFormat), (uint)bd.Stride, (uint)(bd.Stride * bd.Height), bd.Scan0); if (result == 0x80070057) { throw new ArgumentException(); } if (result < 0) { throw new Exception("HRESULT " + result); } //Copy the bitmap palette if it exists var sPalette = bit.Palette; if (sPalette.Entries.Length > 0) { p = factory.CreatePalette(); uint[] colors = new uint[sPalette.Entries.Length]; for (int i = 0; i < sPalette.Entries.Length; i++) { colors[i] = (uint)(((sPalette.Entries[i].A << 24) | (sPalette.Entries[i].R << 16) | (sPalette.Entries[i].G << 8) | sPalette.Entries[i].B) & 0xffffffffL); } p.InitializeCustom(colors, (uint)colors.Length); b.SetPalette(p); } return(b); } finally { bit.UnlockBits(bd); if (p != null) { Marshal.ReleaseComObject(p); } } }
/// <summary> /// Adds padding to a bitmap, optionally cropping it at the same time. /// </summary> /// <param name="s"></param> /// <param name="left"></param> /// <param name="top"></param> /// <param name="right"></param> /// <param name="bottom"></param> /// <param name="bgcolor"></param> /// <param name="crop"></param> public WicBitmapPadder(IWICBitmapSource s, int left, int top, int right, int bottom, byte[] bgcolor, WICRect crop) { this.s = s; this.left = left; this.right = right; this.bottom = bottom; this.top = top; this.bgcolor = bgcolor; this.crop = crop; Guid pf; s.GetPixelFormat(out pf); if (bgcolor.Length != ConversionUtils.BytesPerPixel(pf)) { throw new ArgumentException("bgcolor length must match the format bytes per pixel"); } }
public static byte[] ConvertColor(Color color, Guid pixelFormat) { if (pixelFormat == Consts.GUID_WICPixelFormat24bppBGR) { return new byte[] { color.B, color.G, color.R } } ; if (pixelFormat == Consts.GUID_WICPixelFormat24bppRGB) { return new byte[] { color.R, color.G, color.B } } ; if (pixelFormat == Consts.GUID_WICPixelFormat32bppBGR || pixelFormat == Consts.GUID_WICPixelFormat32bppBGRA || pixelFormat == Consts.GUID_WICPixelFormat32bppPBGRA) { return new byte[] { color.B, color.G, color.R, color.A } } ; if (pixelFormat == Consts.GUID_WICPixelFormat32bppPRGBA || pixelFormat == Consts.GUID_WICPixelFormat32bppRGBA) { return new byte[] { color.R, color.G, color.B, color.A } } ; if (pixelFormat == Consts.GUID_WICPixelFormat8bppGray) { return new byte[] { (byte)Math.Min(0, Math.Max(255, (float)color.B * 0.081f + (float)color.G * 0.419f + (float)color.R * 0.5f)) } } ; byte[] data = new byte[ConversionUtils.BytesPerPixel(pixelFormat)]; return(data); } } }
public void CopyPixels(WICRect prc, uint destStride, uint destBufferSize, [Out] [MarshalAs(UnmanagedType.LPArray, SizeParamIndex = 2)] byte[] destBuffer) { //Get normal size of source rect uint sw, sh; s.GetSize(out sw, out sh); //Get normal (uncropped size) of this bitmap. Includes source cropping uint fullWidth, fullHeight; this.GetSize(out fullWidth, out fullHeight); //Copy or generate source crop rectangle. WICRect crop = this.crop == null ? new WICRect { X = 0, Y = 0, Width = (int)sw, Height = (int)sh }: new WICRect { X = this.crop.X, Y = this.crop.Y, Width = this.crop.Width, Height = this.crop.Height }; //Copy padding values so we can modify them based on the dest crop area. int left = this.left; int top = this.top; int right = this.right; int bottom = this.bottom; int w = prc != null ? prc.Width : (int)fullWidth; int h = prc != null ? prc.Height : (int)fullHeight; //Adjust padding based on what they're asking to crop off if (prc != null) { left -= prc.X; top -= prc.Y; right -= (int)(fullWidth - prc.X - prc.Width); bottom -= (int)(fullHeight - prc.Y - prc.Height); } //Now, adjust negative padding to crop from the source bitmap. We should end up with only positive padding. if (left < 0) { crop.X += left * -1; crop.Width += left; left = 0; } if (top < 0) { crop.Y += top * -1; crop.Height += top; top = 0; } if (right < 0) { crop.Width += right; right = 0; } if (bottom < 0) { crop.Height += bottom; bottom = 0; } //Now, if we don't have to add any padding (say the caller ended up cropping it all off), just pass the request on. if (left == 0 && top == 0 && right == 0 && bottom == 0) { s.CopyPixels(crop, destStride, destBufferSize, destBuffer); return; } //Ah, looks like we still have to do padding. //Get pixel format Guid format; s.GetPixelFormat(out format); //Calculate buffer and stride for source data uint bpp = (uint)ConversionUtils.BytesPerPixel(format); //Round up to nearest byte. uint srcStride = (((bpp * (uint)Math.Max(0, crop.Width)) + 4 - 1) / 4) * 4; //Round up to nearest 4-byte alignment uint sbufferSize = srcStride * (uint)Math.Max(0, crop.Height); //Allocate for source data byte[] sbuffer = new byte[sbufferSize]; //Decode and store the source data if (sbufferSize > 0) { s.CopyPixels(crop, srcStride, sbufferSize, sbuffer); } //Ok, now it's time to start work. //Manually build a padding stride for left, top/bottom, and right, then use Array.Copy to do it more efficiently. //Favor doing complete row - don't let left/right overlap with top/bottom. if (left > 0 && h > (top + bottom)) { //Cache manually built array for speed if (cachedLeftPadding == null) { cachedLeftPadding = new byte[left * bpp]; for (int i = 0; i < left; i++) { Array.Copy(bgcolor, 0, cachedLeftPadding, i * bpp, bpp); } } //Then copy it down for (int j = 0; j < h - top - bottom; j++) { Array.Copy(cachedLeftPadding, 0, destBuffer, (destStride * (j + top)), left * bpp); } } if (right > 0 && h > (top + bottom)) { //Cache manually built array for speed if (cachedRightPadding == null) { cachedRightPadding = new byte[right * bpp]; for (int i = 0; i < right; i++) { Array.Copy(bgcolor, 0, cachedRightPadding, i * bpp, bpp); } } //Then copy it down for (int j = 0; j < h - top - bottom; j++) { Array.Copy(cachedRightPadding, 0, destBuffer, (destStride * (j + top)) + (left + crop.Width) * bpp, right * bpp); } } if (top > 0 || bottom > 0) { //Cache manually built array for speed if (cachedRowPadding == null) { cachedRowPadding = new byte[(crop.Width + left + right) * bpp]; for (int i = 0; i < crop.Width + left + right; i++) { Array.Copy(bgcolor, 0, cachedRowPadding, i * bpp, bpp); } } //Copy it down for both top and bottom if (top > 0) { for (int j = 0; j < Math.Min(h, top); j++) { Array.Copy(cachedRowPadding, 0, destBuffer, (destStride * j), (crop.Width + left + right) * bpp); } } if (bottom > 0) { for (int j = 0; j < Math.Min(h, bottom); j++) //If the manual row was at the bottom, don't copy it again. { Array.Copy(cachedRowPadding, 0, destBuffer, (destStride * (j + top + Math.Max(0, crop.Height))), (crop.Width + left + right) * bpp); } } } //Now, copy the image data. If we didn't use left or right padding we can copy the whole thing at once. if (sbufferSize > 0) { if (srcStride == destStride) { Array.Copy(sbuffer, 0, destBuffer, top * destStride, sbuffer.Length); } else { //Otherwise, one row at a time for (int j = 0; j < crop.Height; j++) { Array.Copy(sbuffer, j * srcStride, destBuffer, (left * bpp) + (top + j) * destStride, crop.Width * bpp); } } } //We're done! }