Замените GDI+ DrawImage на PInvoked GDI и прозрачные PNG's

Я создал службу изображений на C#, которая принимает изображение базового слоя (JPG), наслаивает еще один прозрачный PNG (32 бита), а затем выводит конечное изображение JPG. Я пытаюсь выжать из этой функции все до последней миллисекунды, и мой код застревает на вызове DrawImage в GDI+. Управляемый код здесь:

// 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();

Теперь я прочитал о приросте производительности, полученном при вызове GDI непосредственно через P/Invoke, и попытался заменить вызов DrawImage. Я создал модульный тест, чтобы попытаться продублировать ту же функциональность загрузки JPG, а затем наложения поверх него одного прозрачного PNG.

Ссылка: 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);

Но это не приводит к созданию многослойного изображения. Только PNG без базового JPG. Что я должен делать по-другому? Я немного не в своей тарелке, когда речь идет о прямом GDI.

6
задан Dfaussio 1 March 2012 в 19:33
поделиться