2009-02-26 51 views
7

He publicado varias preguntas relacionadas con este problema que estoy teniendo y estoy empezando a creer que esto no se puede hacer. Aquí está la historia de fondo.Rendering una imagen en tiempo de ejecución en WPF

Tengo una aplicación ASP.NET de la cual quiero generar una imagen .png. Esta imagen .png debe construirse desde XAML o un árbol visual de WPF. Debido a esto, debo generar la imagen .png en un hilo STA. Todo funciona bien hasta que mi árbol visual XAML/WPF incluye una imagen (como en System.Windows.Controls.Image). Mi archivo .png se genera correctamente, excepto que el elemento Imagen no muestra la imagen a la que se hace referencia. La imagen a la que se hace referencia está ubicada en una URL remota. No se arrojan errores o excepciones.

¿Cómo creo una imagen .png de algún árbol visual XAML/WPF que incluya un elemento System.Windows.Controls.Image? El .png resultante debe incluir la imagen a la que se hace referencia en el elemento Imagen. He intentado el siguiente código de varias formas:

string address = "http://imgtops.sourceforge.net/bakeoff/o-png24.png"; 

WebClient webClient = new WebClient(); 
byte[] imageContent = webClient.DownloadData(address); 

Image image = new Image(); 
using (MemoryStream memoryStream = new MemoryStream(imageContent)) 
{ 
    BitmapImage imageSource = new BitmapImage(); 
    imageSource.BeginInit(); 
    imageSource.StreamSource = memoryStream; 
    imageSource.EndInit(); 
    image.Source = imageSource; 
} 

// Set the size 
image.Height = 200; 
image.Width = 300; 

// Position the Image within a Canvas 
image.SetValue(Canvas.TopProperty, 1.0); 
image.SetValue(Canvas.LeftProperty, 1.0); 

Canvas canvas = new Canvas(); 
canvas.Height = 200; 
canvas.Width = 300; 
canvas.Background = new SolidColorBrush(Colors.Purple); 
canvas.Children.Add(image); 

// Create the area 
Size availableSize = new Size(300, 200); 
frameworkElement.Measure(availableSize); 
frameworkElement.Arrange(new Rect(availableSize)); 

// Convert the WPF representation to a PNG file    
BitmapSource bitmap = RenderToBitmap(frameworkElement); 
PngBitmapEncoder encoder = new PngBitmapEncoder(); 
encoder.Frames.Add(BitmapFrame.Create(bitmap)); 

// Generate the .png 
FileStream fileStream = new FileStream(filename, FileMode.Create); 
encoder.Save(fileStream); 


public BitmapSource RenderToBitmap(FrameworkElement target) 
{ 
    int actualWidth = 300; 
    int actualHeight = 200; 

    Rect boundary = VisualTreeHelper.GetDescendantBounds(target); 
    RenderTargetBitmap renderBitmap = new RenderTargetBitmap(actualWidth, actualHeight, 96, 96, PixelFormats.Pbgra32); 

    DrawingVisual drawingVisual = new DrawingVisual(); 
    using (DrawingContext context = drawingVisual.RenderOpen()) 
    { 
    VisualBrush visualBrush = new VisualBrush(target); 
    context.DrawRectangle(visualBrush, null, new Rect(new Point(), boundary.Size)); 
    } 

    renderBitmap.Render(drawingVisual); 
    return renderBitmap; 
} 

Gracias por su ayuda.

+1

Me encanta cuando encuentro la respuesta a mi pregunta sin tener que preguntar, gracias por encontrarse con la misma pregunta que tuve y ayudarme a resolver mis problemas. –

Respuesta

14

Está representando el mapa de bits de salida correctamente, es solo el mapa de bits de entrada que está modificando :).

BitmapImage requiere acceso a la propiedad StreamSource hasta que se active el evento DownloadCompleted, pero el bloque 'using' Dispose() s de MemoryStream antes de que tenga una oportunidad. Simplemente podría desenvolver el MemoryStream del bloque de uso y dejar que el GC lo maneje (si lo hace, le recomendaría configurar el BitmapImage.CacheOption en BitmapCacheOption.None, por lo que usa el flujo directamente, en lugar de una copia), pero yo lo haría use la propiedad UriSource y espere el evento DownloadComplete antes de renderizar.

+1

¡Muchas gracias! Esto resolvió totalmente mi problema. Me estaba volviendo loco. – user70192

+0

¡perfecto! gracias por proporcionar esta respuesta! –

Cuestiones relacionadas