Beispiel #1
0
        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);
                }
            }
        }
Beispiel #2
0
        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);
                }
            }
        }
Beispiel #3
0
        /// <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");
            }
        }
Beispiel #4
0
        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);
        }
    }
}
Beispiel #5
0
        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!
        }