Рендеринг изображения во время выполнения в WPF - PullRequest
7 голосов
/ 26 февраля 2009

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

У меня есть приложение 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 Ответ

14 голосов
/ 26 февраля 2009

Вы правильно выводите битовый массив вывода, это просто битовый массив ввода, который вы испортили:).

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...