Obtenir un contexte de dessin pour un WPF WriteableBitmap

Est-il possible d'obtenir un DrawingContext (ou quelque chose de similaire)WriteableBitmap? I. e. quelque chose pour vous permettre d'appel simple DrawLine/DrawRectangle / etc méthodes, plutôt que de manipuler directement les pixels bruts.

19
demandé sur Noam M 2008-09-18 02:53:25

5 réponses

j'ai trouvé la solution de sixlettervariables la plus réalisable. Cependant, il y a un "drawingContext.Close()" manquant. Selon MSDN, "un contexte de dessin doit être fermé avant que son contenu puisse être rendu". Le résultat est la fonction d'utilité suivante:

public static BitmapSource CreateBitmap(
    int width, int height, double dpi, Action<DrawingContext> render)
{
    DrawingVisual drawingVisual = new DrawingVisual();
    using (DrawingContext drawingContext = drawingVisual.RenderOpen())
    {
        render(drawingContext);
    }
    RenderTargetBitmap bitmap = new RenderTargetBitmap(
        width, height, dpi, dpi, PixelFormats.Default);
    bitmap.Render(drawingVisual);

    return bitmap;
}

ceci peut alors facilement être utilisé comme ceci:

BitmapSource image = ImageTools.CreateBitmap(
    320, 240, 96,
    drawingContext =>
    {
        drawingContext.DrawRectangle(
            Brushes.Green, null, new Rect(50, 50, 200, 100));
        drawingContext.DrawLine(
            new Pen(Brushes.White, 2), new Point(0, 0), new Point(320, 240));
    });
19
répondu Daniel Wolf 2009-11-20 11:10:33

Si vous n'avez pas l'esprit à l'aide de System.Drawing vous pourriez faire quelque chose comme:

var wb = new WriteableBitmap( width, height, dpi, dpi, 
                              PixelFormats.Pbgra32, null );
wb.Lock();
var bmp = new System.Drawing.Bitmap( wb.PixelWidth, wb.PixelHeight,
                                     wb.BackBufferStride, 
                                     PixelFormat.Format32bppPArgb, 
                                     wb.BackBuffer );

Graphics g = System.Drawing.Graphics.FromImage( bmp ); // Good old Graphics

g.DrawLine( ... ); // etc...

// ...and finally:
g.Dispose(); 
bmp.Dispose();
wb.AddDirtyRect( ... );
wb.Unlock();                    
15
répondu Danko Durbić 2012-04-17 17:50:03

je me demande la même chose, comme actuellement je fais quelque chose comme:

DrawingVisual drawingVisual = new DrawingVisual();
using (DrawingContext drawingContext = drawingVisual.RenderOpen())
{
   //
   // ... draw on the drawingContext
   //
   RenderTargetBitmap bmp = new RenderTargetBitmap(width, height, dpi, dpi, PixelFormats.Default);
   bmp.Render(drawingVisual);
   image.Source = bmp;
}

j'essaie d'utiliser le Writeablbitmap pour permettre l'accès multithread au tampon pixel, qui n'est actuellement pas autorisé avec ni un contexte de dessin ni un RenderTargetBitmap. Peut-être qu'une sorte de routine WritePixels basée sur ce que vous avez récupéré de la cible de Rendertbitmap fonctionnerait?

5
répondu user7116 2008-09-17 23:02:32

Il s'affiche le mot n'.


pour référence future, nous prévoyons d'utiliser un port de la Inscriptible Bitmap Extensions pour WPF.

pour une solution utilisant du code purement existant, n'importe laquelle des autres suggestions mentionnées ci-dessous fonctionnera.

4
répondu Emperor XLII 2012-01-04 13:42:42

Une autre façon de résoudre ce problème est d'utiliser un RenderTargetBitmap comme un magasin de soutien, comme dans le WriteableBitmap exemple. Ensuite, vous pouvez créer et émettre des commandes de dessin WPF à elle quand vous voulez. Par exemple:

// create the backing store in a constructor
var backingStore = 
      new RenderTargetBitmap(200,200,97,97,PixelFormats.Pbgra32);
myImage.Source = backingStore;

// whenever you want to update the bitmap, do:
var drawingVisual = new DrawingVisual();
var drawingContext = drawingVisual.RenderOpen();
{
    // your drawing commands go here
    drawingContext.DrawRectangle(
            Brushes.Red, new Pen(),
            new Rect(this.RenderSize));
}
Render(drawingContext);
drawingContext.Close();
backingStore.Render(drawingVisual);

Si vous voulez redessiner ce RenderTargetBitmap chaque image, vous pouvez prendre le CompositionTarget.Rendering événement, comme ceci:

CompositionTarget.Rendering += MyRenderingHandler;
1
répondu David Jeske 2017-06-08 02:23:23