I created an image service in C # that takes an image at a basic level (JPG), overlays another more transparent PNG (32 bit), and then displays the final image in JPG format. I am trying to squeeze every last millisecond from this function, and my code is the bottleneck when calling DrawImage 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();
Now I read about the performance gained by calling GDI directly to P / Invoke, and tried to replace the DrawImage call. I created a unit test to try to duplicate the same JPG loading functions, and then overlay one transparent PNG on top of it.
Link: http://social.msdn.microsoft.com/Forums/en-US/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);
But this does not create a layered image. Just PNG without base jpg. What should I do differently? I'm a bit out of my league when it comes straight to GDI.