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 :
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'utiliserIntPtr
pour construire monDataStream
? - 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 !