Рендеринг изображения во время выполнения в WPF

Я отправил несколько вопросов, связанных с этой проблемой, и я начинаю полагать, что это невозможно. Вот предыстория.

У меня есть приложение ASP.NET, из которого я хочу сгенерировать изображение .png. Это изображение .png должно быть создано на основе XAML или визуального дерева WPF. Из-за этого я должен сгенерировать изображение .png в потоке STA. Все работает нормально, пока мое визуальное дерево XAML / WPF не будет включать изображение (как в System.Windows.Controls.Image). Мой файл .png создается правильно, за исключением того, что элемент Image не показывает указанное изображение. Ссылка на изображение находится по удаленному URL-адресу. Никаких ошибок или исключений не возникает.

Как создать изображение .png из некоторого визуального дерева XAML / WPF, которое включает элемент System.Windows.Controls.Image? Результирующий .png должен включать изображение, указанное в элементе Image. Я пробовал следующий код разными способами:

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

Спасибо за помощь.

Ответов (1)

Решение

Вы правильно визуализируете выходное растровое изображение, это просто входное растровое изображение, которое вы испортили :).

BitmapImage требует доступа к свойству StreamSource до тех пор, пока оно не вызовет событие DownloadCompleted, но блокам использования Dispose() MemoryStream прежде, чем у него появится шанс! Вы можете просто развернуть MemoryStream из блока using и позволить GC обрабатывать его (если вы это сделаете, я бы рекомендовал установить BitmapImage.CacheOption на BitmapCacheOption.None, чтобы он использовал поток напрямую, а не копию), но я бы используйте свойство UriSource и дождитесь события DownloadComplete перед отрисовкой.