Получить растровое изображение из представления Control

Я хотел бы "скопировать в буфер обмена", что Control из моего WPF Приложение рисует на экране. Поэтому мне нужно создать растровое изображение из моего текущего экрана управления.

Есть ли простой способ сделать это?

Заранее спасибо.

3 ответа

Решение

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

RenderTargetBitmap rtb = new RenderTargetBitmap((int)control.ActualWidth, (int)control.ActualHeight, 96, 96, PixelFormats.Pbgra32);
rtb.Render(control);

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

Вот что мы используем для создания System.Drawing.Image, который, я думаю, вы сможете поместить в буфер обмена.

PngBitmapEncoder png = new PngBitmapEncoder();
png.Frames.Add(BitmapFrame.Create(rtb));
MemoryStream stream = new MemoryStream();
png.Save(stream);
Image image = Image.FromStream(stream);

System.Drawing.Image (изображение формы) не может напрямую взаимодействовать с RenderTargetBitmap (класс WPF), поэтому мы используем MemoryStream для его преобразования.

Если элемент управления, из которого вы пытаетесь создать растровое изображение, находится внутри StackPanel это не сработает, вы просто получите пустое изображение.

У Хайме Родригеса есть хороший кусок кода, чтобы обойти это в своем блоге:

private static BitmapSource CaptureScreen(Visual target, double dpiX, double dpiY)
{
    if (target == null)
    {
        return null;
    }
    Rect bounds = VisualTreeHelper.GetDescendantBounds(target);
    RenderTargetBitmap rtb = new RenderTargetBitmap((int)(bounds.Width * dpiX / 96.0),
                                                    (int)(bounds.Height * dpiY / 96.0),
                                                    dpiX,
                                                    dpiY,
                                                    PixelFormats.Pbgra32);
    DrawingVisual dv = new DrawingVisual();
    using (DrawingContext ctx = dv.RenderOpen())
    {
        VisualBrush vb = new VisualBrush(target);
        ctx.DrawRectangle(vb, null, new Rect(new Point(), bounds.Size));
    }
    rtb.Render(dv);
    return rtb;
}

Это идет в вашем коде:(или переходите в окно.)

Не моя, а моя мешанина и гугл. Работает в .Net 5 и WPF

          public void RenderThisWindow(string fullPngPath)
    {
        Image myImage = new Image();
        
        DrawingVisual drawingVisual = new DrawingVisual();

        RenderTargetBitmap bmp = new RenderTargetBitmap((int)Width, (int)Height, 120, 96, PixelFormats.Pbgra32);
        bmp.Render(this);
        myImage.Source = bmp;

        SaveToPng(this, fullPngPath);
    }
    
    private void SaveToPng(FrameworkElement visual, string fileName)
    {
        var encoder = new PngBitmapEncoder();
        SaveUsingEncoder(visual, fileName, encoder);
    }
    
    private void SaveUsingEncoder(FrameworkElement visual, string fileName, BitmapEncoder encoder)
    {
        RenderTargetBitmap bitmap = new RenderTargetBitmap((int)visual.Width, (int)visual.Width, 96, 96, PixelFormats.Pbgra32);
        bitmap.Render(visual);
        BitmapFrame frame = BitmapFrame.Create(bitmap);
        encoder.Frames.Add(frame);

        using (var stream = File.Create(fileName))
        {
            encoder.Save(stream);
        }
    }
Другие вопросы по тегам