通过 SharpDX 渲染 Direct2D 图像时如何使用内存流而不是文件?

发布于 2025-01-02 06:41:53 字数 4659 浏览 0 评论 0原文

设置

考虑给定的临时程序,该程序使用 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”文件,其中包含以下漂亮的图像:

Output Image

问题

太棒了,我刚刚使用 Direct2D 而不是 GDI+ 渲染了图像,据说在 ASP.NET 应用程序上下文中更受支持。另外,Direct2D 是新的热点。

假设我想编写一个函数来渲染这样的图像并将 PNG 作为 Streambyte[] 数组,在内存中执行整个渲染和编码操作,而不是写入文件系统。这是为了响应 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);

感谢您的帮助!

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:

Output 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 that IntPtr to build my DataStream?
  • 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

守望孤独 2025-01-09 06:41:53

该库的作者将此添加为一项功能

我将保留这个问题,因为我认为代码为人们提供了有用的 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.

请你别敷衍 2025-01-09 06:41:53

如果有人想在 ASP.NET 中执行此操作:

var memStream = new MemoryStream();
var wicStream = new WICStream(wicFactory, memStream);

//Encode wic bitmap
var encoder = new PngBitmapEncoder(wicFactory);
encoder.Initialize(wicStream);
var frameEncoder = new BitmapFrameEncode(encoder);
frameEncoder.Initialize();
frameEncoder.SetSize(width, height);
var format = WicPixelFormat.FormatDontCare;
frameEncoder.SetPixelFormat(ref format);
frameEncoder.WriteSource(wicBitmap);
frameEncoder.Commit();
encoder.Commit();

//Clean-up
frameEncoder.Dispose();
encoder.Dispose();
wicStream.Dispose();

imgBackdrop.ImageUrl = "data:image/png;base64," + Convert.ToBase64String(memStream.ToArray(), 0, memStream.ToArray().Length);

If anyone is looking to do this in asp.net:

var memStream = new MemoryStream();
var wicStream = new WICStream(wicFactory, memStream);

//Encode wic bitmap
var encoder = new PngBitmapEncoder(wicFactory);
encoder.Initialize(wicStream);
var frameEncoder = new BitmapFrameEncode(encoder);
frameEncoder.Initialize();
frameEncoder.SetSize(width, height);
var format = WicPixelFormat.FormatDontCare;
frameEncoder.SetPixelFormat(ref format);
frameEncoder.WriteSource(wicBitmap);
frameEncoder.Commit();
encoder.Commit();

//Clean-up
frameEncoder.Dispose();
encoder.Dispose();
wicStream.Dispose();

imgBackdrop.ImageUrl = "data:image/png;base64," + Convert.ToBase64String(memStream.ToArray(), 0, memStream.ToArray().Length);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文