Использование WPF в DLL для динамического создания изображений (вместо GDI+)

StackOverflow https://stackoverflow.com/questions/818544

  •  03-07-2019
  •  | 
  •  

Вопрос

Мне нужно динамически генерировать изображение, и после того, как я прочитаю руководство здесь Я понимаю, что могу использовать все элементы управления и макеты WPF для создания рендеринга, а затем сохранить его в формате JPG.Идея состоит в том, чтобы использовать его вместо GDI+, что довольно примитивно.

Вопрос в том, как мне создать обычный файл dll, который будет программно генерировать холст WPF, чтобы затем я мог добавить к нему элементы управления, а затем вывести их в файл изображения.Имейте в виду, что он будет использоваться приложением ASP.NET.

Есть идеи у кого-нибудь?

Это было полезно?

Решение

Этот пример имеет хорошее начало, но я обнаружил, что в нем много ненужного мусора.Главное, что вам не нужно иметь отдельный WPF-проект.

Вот что делать:

  • Используйте PresentationCore, PresentationFramework и WindowsBase в своем веб-проекте.
  • Создайте Canvas и другие объекты WPF программно в потоке STA.
  • Вызовите для них несколько специальных методов, чтобы убедиться, что они обновляются вне контекста приложения WPF.
  • Преобразуйте их в изображение с помощью RenderTargetBitmap.
  • Завершите работу диспетчера потока.
  • Установите тип mime и выведите изображение с помощью ASP.NET.

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

Вот полный рабочий код, который у меня есть:

using System;
using System.Web;
using System.Threading;
using System.IO;
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Controls;
using System.Windows.Documents;

public partial class _Default : System.Web.UI.Page
{
    private byte[] imageBuffer;

    public void Page_Load(object sender, EventArgs e)
    {
        this.RenderImage();

        Response.Clear();
        Response.ContentType = @"image/png";
        Response.BufferOutput = true;
        Response.BinaryWrite(this.imageBuffer);
        Response.Flush();
    }

    public void RenderImage()
    {
        Thread worker = new Thread(new ThreadStart(this.RenderImageWorker));
        worker.SetApartmentState(ApartmentState.STA);
        worker.Name = "RenderImageWorker";
        worker.Start();
        worker.Join();
    }

    public void RenderImageWorker()
    {
        Canvas imageCanvas = new Canvas { Width = 600, Height = 200, Background = Brushes.Azure };

        TextBlock tb = new TextBlock();
        tb.Width = (double)400;
        //tb.Height = (double)200;
        tb.TextAlignment = TextAlignment.Center;
        tb.Inlines.Add(new Run("This is "));
        tb.Inlines.Add(new Bold(new Run("bold")));
        tb.Inlines.Add(new Run(" text."));
        tb.FontSize = 30;
        tb.Foreground = Brushes.Blue;

        imageCanvas.Children.Add(tb);

        // Update layout
        imageCanvas.Measure(new Size(imageCanvas.Width, imageCanvas.Height));
        imageCanvas.Arrange(new Rect(new Size(imageCanvas.Width, imageCanvas.Height)));

        RenderTargetBitmap bitmapRenderer = new RenderTargetBitmap((int)imageCanvas.ActualWidth, (int)imageCanvas.ActualHeight, 96, 96, PixelFormats.Pbgra32);
        bitmapRenderer.Render(imageCanvas);

        PngBitmapEncoder png = new PngBitmapEncoder();
        png.Frames.Add(BitmapFrame.Create(bitmapRenderer));

        using (MemoryStream memoryStream = new MemoryStream())
        {
            png.Save(memoryStream);
            this.imageBuffer = memoryStream.ToArray();
        }

        if (bitmapRenderer.Dispatcher.Thread.IsAlive)
        {
            bitmapRenderer.Dispatcher.InvokeShutdown();
        }
    }
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top