2014-12-10 11 views
22

non mi aspettavoCome eseguire correttamente il rendering di bitmap di grandi dimensioni in WPF?

RenderTargetBitmap.Render(visual) 

per avere un qualsiasi brano effetti collaterali modifica dei dati bitmap in sé. Sembra che non sia vero. Non riesco a ripeterlo più di 60 volte prima che alcuni brutti artefatti di rendering inizino a succedere.

Come eseguire correttamente il rendering di molti sprite in WPF? Di seguito è riportato il codice per riprodurre il problema.

ho generare sprite in questo modo:

BitmapSource Sprite() 
    { 
     var bitmap = new RenderTargetBitmap(
      500, 500, 
      96, 96, 
      PixelFormats.Default); 

     var visual = new DrawingVisual(); 
     var rect = new Rect(
        new Size(
         bitmap.Width, 
         bitmap.Height)); 

     using (DrawingContext context = visual.RenderOpen()) 
      context.DrawLine(
       new Pen(Brushes.Red, 100), 
       rect.TopLeft, 
       rect.BottomRight); 

     bitmap.Render(visual); 
     bitmap.Freeze(); 
     return bitmap; 
    } 

Ecco la tela di rendere molti di loro:

public BitmapSource Canvas 
    { 
     get 
     { 
      var bitmap = new RenderTargetBitmap(
       1980, 1080, 
       96, 96, 
       PixelFormats.Default); 

      var tiles = 70; 
      for (int i = 0; i < tiles; i++) 
      { 
       var visual = new DrawingVisual(); 
       var rect = new Rect(
        bitmap.Width/tiles * i, 
        0, 
        bitmap.Width/tiles, 
        bitmap.Height); 

       using (DrawingContext context = visual.RenderOpen()) 
        context.DrawImage(Sprite(), rect); 

       bitmap.Render(visual); 
      } 

      bitmap.Freeze(); 
      return bitmap; 
     } 
    } 

posso vedere questa immagine strana pur essendo i dati legati alla proprietà della tela ...

enter image description here

+0

Perché non si esegue il rendering di quelle 70 tessere in un singolo DrawingVisual e quindi si chiama bitmap.Render una sola volta? Dovresti semplicemente spostare il ciclo 'for' nel blocco' using (DrawingContext ...) '. È inoltre possibile salvare completamente RenderTargetBitmap "interni" disegnando le linee direttamente sul DrawingContext "esterno". – Clemens

+0

Non riesco a rendere i riquadri direttamente, poiché significa che per una singola visuale mantenere i riferimenti a 70 bitmap o più allo stesso tempo. A corto di memoria. Sfortunatamente, ho bisogno di RenderTargetBitmaps "interni" perché Tiles sta inserendo dati raster per la mia applicazione. –

+0

1) Non riesco a riprodurre il problema, anche con 'tiles = 2000'. 2) Posso riprodurre l'eccezione out-of-memory quando si mantengono tutti i riferimenti agli sprite in una singola Visual, ma con circa 855 riquadri anziché 70. Che tipo di hardware grafico stai usando? – dbc

risposta

4

Ecco un esempio per noi Ing InteropBitmap:

public InteropBitmapHelper(ColorSpace colorSpace, int bpp, int width, int height, uint byteCount) 
     { 
      _currentColorSpace = colorSpace; 
      _pixelFormat = GetPixelFormat(colorSpace, bpp); 

      if (_pixelFormat == PixelFormats.Rgb24 || _pixelFormat == PixelFormats.Rgb48 || _pixelFormat == PixelFormats.Bgr32 || 
       _pixelFormat == PixelFormats.Bgr24 || _pixelFormat == PixelFormats.Bgr565 || 
       _pixelFormat == PixelFormats.Gray16 || _pixelFormat == PixelFormats.Gray8) 
      { 
       int strideWidth = (width % 4 == 0) ? width : width - width % 4 + 4; 
       if (byteCount != strideWidth * height * (_pixelFormat.BitsPerPixel/8)) 
       { 
        strideWidth = width; 
       } 
       _stride = strideWidth * _pixelFormat.BitsPerPixel/8; 

       _byteCount = (uint)((_stride) * height * ((short)bpp).NumberOfBytes()); 

       ColorFileMapping = CreateFileMapping(new IntPtr(-1), IntPtr.Zero, 0x04, 0, _byteCount, null); 

       if (ColorFileMapping == IntPtr.Zero) 
       { 
        var res=GetLastError(); 
        IPDevLoggerWrapper.Error("Could not generate InteropBitmap "+res); 
        return; 
       } 
       ViewerImageData = MapViewOfFile(ColorFileMapping, 0xF001F, 0, 0, _byteCount); 
       InteropBitmap = Imaging.CreateBitmapSourceFromMemorySection(ColorFileMapping, 
                      width, 
                      height, 
                      _pixelFormat, 
                      _stride, 
                      0) as InteropBitmap; 
      } 
      else 
      { 
       LoggerWrapper.Error("The image format is not supported"); 
       return; 
      } 
     } 

Ecco come lo collego al XAML.

<Canvas  
    x:Name="content" 
    Width="{Binding ElementName=MainImage, Path=ActualWidth}" 
    Height="{Binding ElementName=MainImage, Path=ActualHeight}" 
    Background="Transparent" 
    MouseEnter="ImageMouseEnter" 
    MouseLeave="ImageMouseLeave" 
    RenderTransformOrigin ="0.5,0.5"> 
    <Image x:Name="MainImage" Source="{Binding Source}" RenderOptions.BitmapScalingMode="{Binding ViewerRenderingMode }"/> 

Per favore fatemi sapere se avete bisogno di maggiori informazioni.

+2

In realtà non ho immagini persistenti di dimensioni ragionevoli. Ho bisogno di combinare più sprite ad alta risoluzione (rappresentati da WriteableBitmap) in un'unica BitmapSource a bassa risoluzione. I miei folletti sono davvero enormi quindi devono essere generati solo uno alla volta. Il problema riguarda il rendering degli sprite sul singolo RenderTargetBitmap (Canvas) più piccolo per combinarli; in pratica non funziona correttamente a partire da .NET 4.0.Microsoft ha detto che sembra un bug e gli sviluppatori del team di prodotto assegnati per risolverlo. –

Problemi correlati