Using WPF on a DLL to create Images Dynamically (instead of GDI+)

后端 未结 1 1514
天命终不由人
天命终不由人 2020-12-30 18:01

I need to generate an image dynamically, and after I read the tutorial here I realize i can use all the controls and layouts from WPF to generate my rendering, and then save

相关标签:
1条回答
  • 2020-12-30 18:44

    That example has a good start but I've found it's got a lot of unneeded junk along with it. The main thing is that you don't need to have a separate WPF project.

    Here's what to do:

    • Reference PresentationCore, PresentationFramework and WindowsBase in your web project.
    • Create a Canvas and other WPF objects programmatically in an STA thread.
    • Call a few special methods on them to make sure they update outside of the context of a WPF app.
    • Render them to an image with RenderTargetBitmap.
    • Shut down the thread's dispatcher.
    • Set the mime type and output the image with ASP.NET.

    To make this more efficient you could re-use the same thread rather than creating a new one for each image. In that case you would only need to clean up the dispatcher when you shut down the thread.

    Here's the full working code I have:

    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();
            }
        }
    }
    
    0 讨论(0)
提交回复
热议问题