- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我用 C# 创建了一个图像服务,它采用基础层图像 (JPG),再分层一层更透明的 PNG(32 位),然后输出最终的 JPG 图像。我试图从这个函数中挤出最后一毫秒,但我的代码在 GDI+ 中的 DrawImage 调用处遇到瓶颈。此处的托管代码:
// 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。
引用号: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);
但这无法产生分层图像。只是没有基本 JPG 的 PNG。我应该采取什么不同的做法?当谈到直接 GDI 时,我有点格格不入。
最佳答案
我最终使用了SharpDX访问 WIC 和 Direct2d API。至少可以说,结果令人印象深刻。当使用 Direct2d 进行合成时,我发现性能比 GDI+ 提高了 400-500%。
我还尝试了 GDI+ 和任务并行库,将图像分成四个象限,并在每个核心中进行合成工作。结果并不像使用 SharpDX 那样显着。
这是我最终使用的代码。对“renderSettings”的引用只是一个配置对象。根据需要与 renderLayer 图像列表一起替换。
/* 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;
}
关于gdi+ - 将 GDI+ DrawImage 替换为 PInvoked GDI 和透明 PNG,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7690546/
这是我尝试在 C# 中使用的头文件签名和 C 代码: __declspec(dllexport) emxArray_real_T *emxCreateWrapper_real_T(real_T *da
我的项目在 .NET Frame work 3.5 中运行成功且没有错误。但是,当我将它定位到 .NET Frame work 4 时。我得到了错误: “对 PInvoke 函数的调用使堆栈不平衡。这
我在非托管 DLL 中有一个非常简单的函数,但我没有从它获得正确的返回值。 我可以确认通用 PInvoke 机制正在使用我的 C DLL 中的一个函数: /* Return an integer */
使用 PInvoke 时可能会发生哪些异常,或者所有错误均由方法返回值处理,并且由开发人员检查并在需要时引发异常? 最佳答案 对于 P/Invoke,可以肯定地说您需要处理两种类型的错误。 P/Inv
我正在尝试为 modbusm.dll (win-tech.com/html/mbusocx.htm) 创建一个包装器 C# 文件,为此我使用 dumpbin 输出。 文件 modbusm.dll 的转
我正在尝试使用 PInvoke 绑定(bind)此 C 函数。 bool GuiTextBox(Rectangle bounds, char *text, int textSize, bool edi
我目前正在尝试通过 C# pinvoke 使用 SendMessage 从子窗口获取一些文本。但是,我之前对窗口句柄进行硬核化的尝试失败了,因为该值在应用程序启动时发生了变化。有没有办法可靠地获取这个
这个问题不太可能帮助任何 future 的访问者;它只与一个小的地理区域、一个特定的时间点或一个非常狭窄的情况有关,这些情况并不普遍适用于互联网的全局受众。为了帮助使这个问题更广泛地适用,visit
考虑以下 C 函数: void get_lib_version(const char **ver_string); 如何使用 PInvoke 正确编码它?文档说它返回一个指向静态字符串的指针。我认为这
我有个问题,很奇怪。当我在 PInvoke 中使用下一个结构时,它正在工作,但是当我将它更改为类时,它不起作用。 我的 C#: [StructLayout(LayoutKind.Sequential)
我在 C++ 原生 dll 中有以下函数,我想在 C# 应用程序中使用它。 DWORD __cdecl Foo( LPCTSTR Input,
似乎有多种方法可以做到这一点,但我尝试过的示例对我不起作用。 我在某处读到,使用不安全指针是获得需要指针的更复杂结构的方法。 (对不起,我没能再次找到来源) 我最近的尝试看起来像这样: unsafe
我正在尝试在 C++ 中创建一个简单的 dll,并使用 PInvoke 从 C# 中调用它。我想传入一个字节数组,对其进行一些操作,然后发回另一个字节数组。我想我会传入框架和大小,然后创建一个非托管的
我正在尝试使用 P/Invoke 从 C# 调用 C++ 函数。 [DllImport(PATH)] public static extern int PQunescapeByteaWrapper(
我正在尝试使用 GetFileInformationByHandle 函数获取 FILE_ID_BOTH_DIR_INFO。调用后我的所有值都设置为零。 我收到 win32 错误消息: ERROR_B
我有以下 C 代码: const BYTE* Items[3]; Items[0] = item1; Items[1] = item2; Items[2] = item3; int result =
这个问题不太可能帮助任何 future 的访问者;它只与一个小的地理区域、一个特定的时间点或一个非常狭窄的情况相关,这些情况并不普遍适用于互联网的全局受众。为了帮助使这个问题更广泛地适用,visit
我有以下 PInvoke:(C 到 C#) [DllImport("chess_api.dll", CallingConvention = CallingConvention.Cdecl)] stat
我正在尝试在 C# 项目中使用 C DLL。 我在 C 中有一个函数: extern __declspec(dllexport) void InitBoard(sPiece board[8][8]);
我如何在 C# 中使用这个 dll 函数?我尝试了以下但出现错误。“外部组件抛出异常。” 我第一次用 C# 和 Delphi 做这个 PInvoke 的东西。 function HTTPGET(loc
我是一名优秀的程序员,十分优秀!