通过 SharpDX 渲染 Direct2D 图像时如何使用内存流而不是文件?
设置
考虑给定的临时程序,该程序使用 SharpDX(Direct* 库的托管包装器)来渲染位图并将其保存为 PNG:
namespace ConsoleApplication5
{
using System;
using System.Diagnostics;
using System.IO;
using SharpDX;
using SharpDX.Direct2D1;
using SharpDX.DirectWrite;
using SharpDX.DXGI;
using SharpDX.IO;
using SharpDX.WIC;
using AlphaMode = SharpDX.Direct2D1.AlphaMode;
using Bitmap = SharpDX.WIC.Bitmap;
using D2DPixelFormat = SharpDX.Direct2D1.PixelFormat;
using WicPixelFormat = SharpDX.WIC.PixelFormat;
class Program
{
static void Main(string[] args)
{
var width = 400;
var height = 100;
var pixelFormat = WicPixelFormat.Format32bppBGR;
var wicFactory = new ImagingFactory();
var dddFactory = new SharpDX.Direct2D1.Factory();
var dwFactory = new SharpDX.DirectWrite.Factory();
var wicBitmap = new Bitmap(
wicFactory,
width,
height,
pixelFormat,
BitmapCreateCacheOption.CacheOnLoad);
var renderTargetProperties = new RenderTargetProperties(
RenderTargetType.Default,
new D2DPixelFormat(Format.Unknown, AlphaMode.Unknown),
0,
0,
RenderTargetUsage.None,
FeatureLevel.Level_DEFAULT);
var renderTarget = new WicRenderTarget(
dddFactory,
wicBitmap,
renderTargetProperties)
{
TextAntialiasMode = TextAntialiasMode.Cleartype
};
renderTarget.BeginDraw();
var textFormat = new TextFormat(dwFactory, "Consolas", 48)
{
TextAlignment = TextAlignment.Center,
ParagraphAlignment = ParagraphAlignment.Center
};
var textBrush = new SolidColorBrush(
renderTarget,
Colors.Blue);
renderTarget.Clear(Colors.White);
renderTarget.DrawText(
"Hi, mom!",
textFormat,
new RectangleF(0, 0, width, height),
textBrush);
renderTarget.EndDraw();
var stream = new WICStream(
wicFactory,
"test.png",
NativeFileAccess.Write);
var encoder = new PngBitmapEncoder(wicFactory);
encoder.Initialize(stream);
var frameEncoder = new BitmapFrameEncode(encoder);
frameEncoder.Initialize();
frameEncoder.SetSize(width, height);
frameEncoder.PixelFormat = WicPixelFormat.FormatDontCare;
frameEncoder.WriteSource(wicBitmap);
frameEncoder.Commit();
encoder.Commit();
frameEncoder.Dispose();
encoder.Dispose();
stream.Dispose();
Process.Start(Path.GetFullPath(Path.Combine(Environment.CurrentDirectory, "test.png")));
}
}
}
运行此程序会在程序的工作目录中提供一个“test.png”文件,其中包含以下漂亮的图像:
问题
太棒了,我刚刚使用 Direct2D 而不是 GDI+ 渲染了图像,据说在 ASP.NET 应用程序上下文中更受支持。另外,Direct2D 是新的热点。
假设我想编写一个函数来渲染这样的图像并将 PNG 作为 Stream
或 byte[]
数组,在内存中执行整个渲染和编码操作,而不是写入文件系统。这是为了响应 Web 请求;将其直接流式传输到浏览器而不通过文件系统是有意义的。
在 GDI+ 中,我可以使用 MemoryStream
很容易,但是在不知道缓冲区大小的情况下,我无法弄清楚如何在 SharpDX 中使用
DataStream
来发挥我的优势:
var bufferSize = 1024 * 3; // how do I know?
var buffer = new DataStream(
bufferSize,
true,
true);
var stream = new WICStream(
wicFactory,
buffer);
- 我是否必须 P/Invoke to
CreateStreamOnHGlobal
< /a> 并使用该IntPtr
构建我的DataStream
? - 我是否缺少一些
DataStream
重载? - 有没有一种简单的方法可以预先计算保存编码的 PNG 图像所需的缓冲区?
- 或者我应该停止浏览文件系统?
感谢您的帮助!
The setup
Consider the given scratch program that uses SharpDX, a managed wrapper for Direct* libraries, to render a bitmap and save it as a PNG:
namespace ConsoleApplication5
{
using System;
using System.Diagnostics;
using System.IO;
using SharpDX;
using SharpDX.Direct2D1;
using SharpDX.DirectWrite;
using SharpDX.DXGI;
using SharpDX.IO;
using SharpDX.WIC;
using AlphaMode = SharpDX.Direct2D1.AlphaMode;
using Bitmap = SharpDX.WIC.Bitmap;
using D2DPixelFormat = SharpDX.Direct2D1.PixelFormat;
using WicPixelFormat = SharpDX.WIC.PixelFormat;
class Program
{
static void Main(string[] args)
{
var width = 400;
var height = 100;
var pixelFormat = WicPixelFormat.Format32bppBGR;
var wicFactory = new ImagingFactory();
var dddFactory = new SharpDX.Direct2D1.Factory();
var dwFactory = new SharpDX.DirectWrite.Factory();
var wicBitmap = new Bitmap(
wicFactory,
width,
height,
pixelFormat,
BitmapCreateCacheOption.CacheOnLoad);
var renderTargetProperties = new RenderTargetProperties(
RenderTargetType.Default,
new D2DPixelFormat(Format.Unknown, AlphaMode.Unknown),
0,
0,
RenderTargetUsage.None,
FeatureLevel.Level_DEFAULT);
var renderTarget = new WicRenderTarget(
dddFactory,
wicBitmap,
renderTargetProperties)
{
TextAntialiasMode = TextAntialiasMode.Cleartype
};
renderTarget.BeginDraw();
var textFormat = new TextFormat(dwFactory, "Consolas", 48)
{
TextAlignment = TextAlignment.Center,
ParagraphAlignment = ParagraphAlignment.Center
};
var textBrush = new SolidColorBrush(
renderTarget,
Colors.Blue);
renderTarget.Clear(Colors.White);
renderTarget.DrawText(
"Hi, mom!",
textFormat,
new RectangleF(0, 0, width, height),
textBrush);
renderTarget.EndDraw();
var stream = new WICStream(
wicFactory,
"test.png",
NativeFileAccess.Write);
var encoder = new PngBitmapEncoder(wicFactory);
encoder.Initialize(stream);
var frameEncoder = new BitmapFrameEncode(encoder);
frameEncoder.Initialize();
frameEncoder.SetSize(width, height);
frameEncoder.PixelFormat = WicPixelFormat.FormatDontCare;
frameEncoder.WriteSource(wicBitmap);
frameEncoder.Commit();
encoder.Commit();
frameEncoder.Dispose();
encoder.Dispose();
stream.Dispose();
Process.Start(Path.GetFullPath(Path.Combine(Environment.CurrentDirectory, "test.png")));
}
}
}
Running this program gives you a "test.png" file in the program's working directory with the following beautiful image:
The question
Awesome, I've just rendered an image using Direct2D instead of GDI+, which is supposedly more supported in the context of an ASP.NET application. Plus, Direct2D is the new hotness.
Let's say that I wanted to write a function that rendered such an image and returned the PNG as a Stream
or a byte[]
array, performing the entire rendering and encoding operation in memory instead of writing to the file system. This is for a responding to a Web request; makes sense just to stream it out straight to the browser without going through the file system.
In GDI+, I could do this with a MemoryStream
pretty easily, but I can't figure out how to use DataStream
in SharpDX to my advantage without knowing the size of the buffer:
var bufferSize = 1024 * 3; // how do I know?
var buffer = new DataStream(
bufferSize,
true,
true);
var stream = new WICStream(
wicFactory,
buffer);
- Do I have to P/Invoke to
CreateStreamOnHGlobal
and use thatIntPtr
to build myDataStream
? - Is there some overload of
DataStream
that I am missing? - Is there an easy way to pre-calculate the necessary buffer needed to hold the encoded PNG image?
- Or should I just get over going through the file system?
Thanks for any help!
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
该库的作者将此添加为一项功能。
我将保留这个问题,因为我认为代码为人们提供了有用的 Direct2D 示例。
The author of the library added this as a feature.
I'll leave the question around as I think the code provides a useful Direct2D sample for people.
如果有人想在 ASP.NET 中执行此操作:
If anyone is looking to do this in asp.net: