用PInvoked GDI和透明PNG替换GDI + DrawImage

编程入门 行业动态 更新时间:2024-10-27 13:30:58
本文介绍了用PInvoked GDI和透明PNG替换GDI + DrawImage的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧! 问题描述

我已经在C#中创建了一个图像服务,该服务获取一个基本图层图像(JPG),再层叠一个更透明的PNG(32位),然后输出最终的JPG图像.我试图从此函数中每隔一毫秒压缩一次,而我的代码在GDI +中的DrawImage调用上遇到了瓶颈.托管代码在这里:

I've created an image service in C# which takes a base layer image (JPG), layers one more more transparent PNG's (32 bit), and then outputs a final JPG image. I'm trying to squeeze every last millisecond out of this function and my code is bottlenecking at the DrawImage call in GDI+. Managed code here:

// Load base image and create graphics Image image = LoadImage(renderSettings.RenderedImageDirectory + baseLayer); Graphics graphics = Graphics.FromImage(image); graphics.CompositingQuality = System.Drawing.Drawing2D.CompositingQuality.HighQuality; graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic; graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality; graphics.PixelOffsetMode = System.Drawing.Drawing2D.PixelOffsetMode.HighSpeed; // Draw additional layers to final image for (int i = 1; i < renderLayers.Count; i++) { // SLOW -- LoadImage just a utility method that returns an Image from disk or cache graphics.DrawImage(LoadImage(renderSettings.RenderedImageDirectory + renderLayers[i]), 0, 0, image.Width, image.Height); } if (graphics != null) graphics.Dispose();

现在,我了解了通过P/Invoke直接调用GDI所获得的性能提升,并尝试替换DrawImage调用.我创建了一个单元测试,以尝试复制相同的功能,即加载JPG,然后在其顶部分层一个透明的PNG.

Now, I read about the performance gains obtained by calling GDI directly by P/Invoke and made an attempt at replacing the DrawImage call. I created a unit test to try to duplicate the same functionality of loading a JPG and then layering one transparent PNG on top of it.

引用: http: //social.msdn.microsoft/Forums/zh-CN/winforms/thread/29582142-0068-40dd-bd99-4b3883a76350

Bitmap sourceImage = new Bitmap("c:\\base.jpg"); Bitmap overlayImage = new Bitmap("c:\\layer1.png"); // NOTE: ImageHelper is a utility class containing all the P/Invoke stuff // Get source image in memory Graphics sourceImageGraphics = Graphics.FromImage(sourceImage); IntPtr sourceImageHDC = sourceImageGraphics.GetHdc(); IntPtr sourceImageCDC = ImageHelper.CreateCompatibleDC(sourceImageHDC); IntPtr sourceImageHandle = sourceImage.GetHbitmap(); ImageHelper.SelectObject(sourceImageCDC, sourceImageHandle); // Get overlay image in memory Graphics overlayImageGraphics = Graphics.FromImage(overlayImage); IntPtr overlayImageHDC = overlayImageGraphics.GetHdc(); IntPtr overlayImageCDC = ImageHelper.CreateCompatibleDC(overlayImageHDC); IntPtr overlayImageHandle = overlayImage.GetHbitmap(); ImageHelper.SelectObject(overlayImageCDC, overlayImageHandle); ImageHelper.BitBlt(sourceImageHDC, 0, 0, sourceImage.Width, sourceImage.Height, overlayImageCDC, 0, 0, ImageHelper.TernaryRasterOperations.SRCAND); ImageHelper.AlphaBlend(sourceImageHDC, 0, 0, sourceImage.Width, sourceImage.Height, overlayImageCDC, 0, 0, sourceImage.Width, sourceImage.Height, new ImageHelper.BLENDFUNCTION(ImageHelper.AC_SRC_OVER, 0, 0xff, ImageHelper.AC_SRC_ALPHA)); // Release source Image memory. ImageHelper.DeleteDC(sourceImageCDC); ImageHelper.DeleteObject(sourceImageHandle); sourceImageGraphics.ReleaseHdc(sourceImageHDC); sourceImageGraphics.Dispose(); // Release overlay Image memory. ImageHelper.DeleteDC(overlayImageCDC); ImageHelper.DeleteObject(overlayImageHandle); overlayImageGraphics.ReleaseHdc(overlayImageHDC); overlayImageGraphics.Dispose(); // Save to jpg sourceImage.Save("c:\\output.jpg", ImageFormat.Jpeg);

但是,这无法生成分层图像.只是没有基本JPG的PNG.我应该怎么做?参加直GDI比赛时,我还差一点.

But this fails to produce a layered image. Just the PNG without the base JPG. What should I be doing differently? I'm a little out of my league when in comes to straight GDI.

推荐答案

我最终使用了 SharpDX 访问WIC和Direct2d API.至少可以说,结果令人印象深刻.与Direct2d集成时,我发现性能比GDI +提高了400-500%.

I ended up using SharpDX to access both the WIC and Direct2d API's. The results are impressive to say the least. When compositing with Direct2d I'm seeing increased performance as much as 400-500% over GDI+.

我还尝试了GDI +和Task Parallel Library将图像分解为四个数量,并在每个核心中进行了合成工作.结果并不像使用SharpDX那样重要.

I also tried GDI+ and the Task Parallel Library to break up images into four quandrants and do compositing work in each core. The results weren't nearly as signficant as using SharpDX.

这是我最终使用的代码.对"renderSettings"的引用只是一个配置对象.根据需要替换renderLayer图像列表.

Here's the code I ended up using. The reference to "renderSettings" is just a configuration object. Substitute as needed along with the renderLayer image list.

/* SharpDX */ using SharpDX; using SharpDX.Direct2D1; using SharpDX.DirectWrite; using SharpDX.DXGI; using SharpDX.IO; using SharpDX.WIC; using AlphaMode = SharpDX.Direct2D1.AlphaMode; using WicBitmap = SharpDX.WIC.Bitmap; using D2DPixelFormat = SharpDX.Direct2D1.PixelFormat; using WicPixelFormat = SharpDX.WIC.PixelFormat; using Rectangle = System.Drawing.Rectangle; using Bitmap = System.Drawing.Bitmap; public Image FlattenImageDirect2d() { List<string> renderLayers = new List<string>() { "image1.jpg", "image1.png", "image2.png", "image3.png", "image4.png", "image5.png", "image6.png", "image7.png" }; // Base image string baseLayer = renderLayers[0]; // Create WIC and D2D factories var wicFactory = new ImagingFactory(); var ddFactory = new SharpDX.Direct2D1.Factory(); // Get image size using WIC int baseWidth, baseHeight; using (var wicStream = new WICStream(wicFactory, renderDirectory + baseLayer, NativeFileAccess.Read)) { var jpegDecoder = new JpegBitmapDecoder(wicFactory); jpegDecoder.Initialize(wicStream, DecodeOptions.CacheOnDemand); var frame = jpegDecoder.GetFrame(0); baseWidth = frame.Size.Width; baseHeight = frame.Size.Height; frame.Dispose(); jpegDecoder.Dispose(); } // Resize image? bool resizeImage = (baseWidth != renderSettings.RenderWidth) || (baseHeight != renderSettings.RenderHeight); // Bitmaps and render target settings var wicBitmap = new WicBitmap(wicFactory, renderSettings.RenderWidth, renderSettings.RenderHeight, SharpDX.WIC.PixelFormat.Format32bppBGR, BitmapCreateCacheOption.CacheOnLoad); var renderTargetProperties = new RenderTargetProperties(RenderTargetType.Default, new D2DPixelFormat(Format.Unknown, AlphaMode.Unknown), 0, 0, RenderTargetUsage.None, FeatureLevel.Level_DEFAULT); var wicRenderTarget = new WicRenderTarget(ddFactory, wicBitmap, renderTargetProperties); // Create bitmap render target used to draw all images to SharpDX.Direct2D1.BitmapRenderTarget bitmapRenderTarget = new SharpDX.Direct2D1.BitmapRenderTarget(wicRenderTarget, CompatibleRenderTargetOptions.None, new D2DPixelFormat(Format.Unknown, AlphaMode.Premultiplied)); // Draw render layers for (int i = 0; i < renderLayers.Count; i++) { // First layer is always a jpeg, all other subsequent layers are png's ImageFormat imageFormat = (i == 0) ? ImageFormat.Jpeg : ImageFormat.Png; using (SharpDX.WIC.BitmapSource bitmapSource = LoadWicBitmap(wicFactory, renderDirectory + renderLayers[i], imageFormat, resizeImage, renderSettings.RenderWidth, renderSettings.RenderHeight)) { // Convert WIC pixel format to D2D1 format var formatConverter = new FormatConverter(wicFactory); formatConverter.Initialize(bitmapSource, SharpDX.WIC.PixelFormat.Format32bppPBGRA, BitmapDitherType.None, null, 0f, BitmapPaletteType.MedianCut); // Create direct 2d bitmap from wic bitmap SharpDX.Direct2D1.Bitmap direct2DBitmap = SharpDX.Direct2D1.Bitmap.FromWicBitmap(bitmapRenderTarget, formatConverter); // Draw direct2d image to bitmap render target wicRenderTarget.BeginDraw(); wicRenderTarget.DrawBitmap(direct2DBitmap, 1.0f, SharpDX.Direct2D1.BitmapInterpolationMode.Linear); wicRenderTarget.EndDraw(); // Clean up formatConverter.Dispose(); direct2DBitmap.Dispose(); } } // Final image data byte[] imageData; // Create streams to write output to. using (var memoryStream = new MemoryStream()) { using (var wicStream = new WICStream(wicFactory, memoryStream)) { // Encode wic bitmap var encoder = new JpegBitmapEncoder(wicFactory); encoder.Initialize(wicStream); var frameEncoder = new BitmapFrameEncode(encoder); frameEncoder.Initialize(); frameEncoder.SetSize(renderSettings.RenderWidth, renderSettings.RenderHeight); frameEncoder.PixelFormat = WicPixelFormat.FormatDontCare; frameEncoder.WriteSource(wicBitmap); frameEncoder.Commit(); encoder.Commit(); // Set image data memoryStream.Position = 0; imageData = memoryStream.ToArray(); // Clean up frameEncoder.Dispose(); encoder.Dispose(); wicBitmap.Dispose(); wicRenderTarget.Dispose(); bitmapRenderTarget.Dispose(); ddFactory.Dispose(); wicFactory.Dispose(); frameEncoder = null; encoder = null; wicBitmap = null; wicRenderTarget = null; bitmapRenderTarget = null; ddFactory = null; wicFactory = null; } } return Image.FromStream(new MemoryStream(imageData)); } private BitmapSource LoadWicBitmap(ImagingFactory wicFactory, string path, ImageFormat imageFormat, bool resize, int resizeWidth = 0, int resizeHeight = 0) { PngBitmapDecoder pngDecoder; JpegBitmapDecoder jpegDecoder; BitmapFrameDecode bitmapFrameDecode; var stream = new WICStream(wicFactory, path, NativeFileAccess.Read); // Load the appropriate decoder if (imageFormat == ImageFormat.Jpeg) { jpegDecoder = new JpegBitmapDecoder(wicFactory); jpegDecoder.Initialize(stream, DecodeOptions.CacheOnLoad); bitmapFrameDecode = jpegDecoder.GetFrame(0); jpegDecoder.Dispose(); } else { pngDecoder = new PngBitmapDecoder(wicFactory); pngDecoder.Initialize(stream, DecodeOptions.CacheOnDemand); bitmapFrameDecode = pngDecoder.GetFrame(0); pngDecoder.Dispose(); } // Clean up stream.Dispose(); // Resize if necessary if (resize) { // Prepare scaler var scaler = new BitmapScaler(wicFactory); scaler.Initialize(bitmapFrameDecode, resizeWidth, resizeHeight, SharpDX.WIC.BitmapInterpolationMode.Fant); return (BitmapSource)scaler; } return (BitmapSource)bitmapFrameDecode; }

更多推荐

用PInvoked GDI和透明PNG替换GDI + DrawImage

本文发布于:2023-07-26 19:06:06,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1217919.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:透明   GDI   PInvoked   PNG   DrawImage

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!