Domanda

C'è un modo per ottenere un DrawingContext (o qualcosa di simile) per a WriteableBitmap?Cioè.qualcosa che ti permetta di chiamare semplice DrawLine/DrawRectangle/etc tipi di metodi, invece di manipolare direttamente i pixel grezzi.

È stato utile?

Soluzione 4

Sembra la parola è no.


Per riferimento futuro, prevediamo di utilizzare una porta di Estensioni bitmap scrivibili per WPF.

Per una soluzione che utilizza codice puramente esistente, funzionerà qualsiasi altro suggerimento menzionato di seguito.

Altri suggerimenti

Ho trovato la soluzione di sixlettervariables quella più praticabile.Tuttavia, manca un "drawingContext.Close()".Secondo MSDN, "Un DrawingContext deve essere chiuso prima che il suo contenuto possa essere visualizzato".Il risultato è la seguente funzione di utilità:

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;
}

Questo può quindi essere facilmente utilizzato in questo modo:

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));
    });

Se non ti dispiace usare System.Drawing potresti fare qualcosa del tipo:

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();                    

Mi chiedo la stessa cosa, dato che attualmente faccio qualcosa del tipo:

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;
}

Sto cercando di utilizzare WriteableBitmap per consentire l'accesso multithread al buffer pixel, che attualmente non è consentito né con DrawingContext né con RenderTargetBitmap.Forse una sorta di routine WritePixels basata su ciò che hai recuperato da RenderTargetBitmap funzionerebbe?

Un modo diverso per risolvere questo problema è utilizzare a RenderTargetBitmap come negozio di supporto, proprio come in WriteableBitmap esempio.Quindi puoi creare ed inviare comandi di disegno WPF ogni volta che vuoi.Per esempio:

// 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);

Se vuoi ridisegnarlo RenderTargetBitmap ogni fotogramma, puoi catturare il CompositionTarget.Rendering evento, in questo modo:

CompositionTarget.Rendering += MyRenderingHandler;
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top