6 votes

Comment utiliser un flux de mémoire au lieu de fichiers lors du rendu d'images Direct2D via SharpDX ?

La mise en place

Considérons le programme scratch donné qui utilise SharpDX une enveloppe gérée pour les bibliothèques Direct*, pour effectuer le rendu d'une image bitmap et l'enregistrer au format 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")));
        }
    }
}

En exécutant ce programme, vous obtenez un fichier "test.png" dans le répertoire de travail du programme, avec la belle image suivante :

Output Image

La question

Génial, je viens de rendre une image en utilisant Direct2D au lieu de GDI+, qui est censé être plus soutenu dans le contexte d'une application ASP.NET. De plus, Direct2D est la nouvelle tendance.

Supposons que je veuille écrire une fonction qui rende une telle image et renvoie le PNG sous la forme d'un fichier Stream ou un byte[] ce qui permet d'effectuer l'ensemble de l'opération de rendu et d'encodage en mémoire au lieu d'écrire dans le système de fichiers. Il s'agit d'une réponse à une requête Web ; il est logique de l'envoyer directement au navigateur sans passer par le système de fichiers.

Dans GDI+, je pouvais le faire avec un fichier MemoryStream assez facilement, mais je n'arrive pas à comprendre comment utiliser la fonction DataStream dans SharpDX à mon avantage sans connaître la taille de la mémoire tampon :

        var bufferSize = 1024 * 3; // how do I know?
        var buffer = new DataStream(
            bufferSize,
            true,
            true);
        var stream = new WICStream(
            wicFactory,
            buffer);
  • Dois-je faire appel à P/Invoke pour CreateStreamOnHGlobal et l'utiliser IntPtr pour construire mon DataStream ?
  • Y a-t-il une surcharge de DataStream qui m'échappe ?
  • Existe-t-il un moyen simple de précalculer la mémoire tampon nécessaire pour contenir l'image PNG encodée ?
  • Ou dois-je me passer de passer par le système de fichiers ?

Merci de votre aide !

4voto

Nicholas Piasecki Points 13681

L'auteur de la bibliothèque ajout d'une fonctionnalité .

Je vais laisser la question en suspens car je pense que le code fournit un échantillon Direct2D utile pour les gens.

3voto

Family Points 544

Si quelqu'un cherche à faire cela en 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);

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X