如何在WPF中保存控件的非模糊高质量图像?

ny6fqffe  于 2023-10-22  发布在  其他
关注(0)|答案(2)|浏览(123)

我正在使用DrawingContext来绘制图像。然后将结果渲染为RenderTargetBitmap。图像在屏幕上清晰锐利,但保存时变得模糊。即使在100%扩展的情况下,问题仍然存在。有趣的是,如果图像宽度小于2000px,则可以导出。但随着宽度的增加,导出的图像变得越来越模糊。
下面是我的代码(Sample project

private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            BitmapImage bitmap = new BitmapImage();
            bitmap.BeginInit();
            bitmap.UriSource = new Uri(@"image-full-hd.png");
            bitmap.EndInit();
            img1.Source = bitmap;

            img1.Width = bitmap.Width;
            img1.Height= bitmap.Height;
        }

        private void btnExport_Click(object sender, RoutedEventArgs e)
        {
            var result = CaptureSnapshot(img1);
            Clipboard.SetImage(result);
        }

        public BitmapSource CaptureSnapshot(UIElement source)
        {
            var dpi = VisualTreeHelper.GetDpi(source);
            double dpiX = dpi.DpiScaleX, dpiY = dpi.DpiScaleY;

            double newImageWidth = source.RenderSize.Width * dpiX;
            double newImageHeight = source.RenderSize.Height * dpiY;

            RenderTargetBitmap renderTarget = new RenderTargetBitmap((int)newImageWidth, (int)newImageHeight, 96, 96, PixelFormats.Pbgra32);

            DrawingVisual visual = new DrawingVisual();

            using (DrawingContext context = visual.RenderOpen())
            {
                VisualBrush sourceBrush1 = new VisualBrush(source)
                {
                    Stretch = Stretch.None
                };

                context.DrawRectangle(sourceBrush1, null, new Rect(source.RenderSize));
            }

            System.Windows.Size s1size = new System.Windows.Size(newImageWidth, newImageHeight);
            source.Measure(s1size); 
            source.Arrange(new Rect(s1size));

            RenderOptions.SetEdgeMode(renderTarget, EdgeMode.Unspecified);
            RenderOptions.SetBitmapScalingMode(renderTarget, BitmapScalingMode.HighQuality);
            renderTarget.Render(visual);

            return renderTarget;
        }

应用窗口

从3400px宽的导出图像剪辑

tsm1rwdh

tsm1rwdh1#

如果源UIElement已经被渲染--并且您正在使用它的RenderSize来计算位图的大小--则不需要另一个布局过程,因此Measure和Arrange调用似乎是不必要的。
为了创建缩放原始图像的未模糊DrawingVisual输出,当source参数是Image时,可以直接将Image元素的ImageSource绘制到Visual中。仅当source不是图像时才使用VisualBrush。

public static BitmapSource CaptureSnapshot(UIElement source)
{
    var dpi = VisualTreeHelper.GetDpi(source);
    var width = source.RenderSize.Width * dpi.DpiScaleX;
    var height = source.RenderSize.Height * dpi.DpiScaleY;
    var rect = new Rect(0, 0, width, height);
    var bitmap = new RenderTargetBitmap((int)width, (int)height, 96, 96, PixelFormats.Pbgra32);
    var visual = new DrawingVisual();

    using (var context = visual.RenderOpen())
    {
        if (source is Image image)
        {
            context.DrawImage(image.Source, rect);
        }
        else
        {
            context.DrawRectangle(new VisualBrush(source), null, rect);
        }
    }

    bitmap.Render(visual);
    return bitmap;
}
rkttyhzu

rkttyhzu2#

是否需要使用DrawingVisualDrawingContextVisualBrush?因为如果没有,您可以直接将UIElement传递给RenderTargetBitmap.Render()。我克隆了你的示例项目,并将CaptureSnapshot改为:

public BitmapSource CaptureSnapshot(UIElement source)
{
    var dpi = VisualTreeHelper.GetDpi(source);
    var width = source.RenderSize.Width * dpi.DpiScaleX;
    var height = source.RenderSize.Height * dpi.DpiScaleY;

    var bitmap = new RenderTargetBitmap((int)width, (int)height,
        dpi.PixelsPerInchX, dpi.PixelsPerInchY, PixelFormats.Pbgra32);

    Size s1size = new Size(width, height);
    source.Measure(s1size);
    source.Arrange(new Rect(s1size));

    bitmap.Render(source);

    return bitmap;
}

并且项目中的两个示例图像的结果都不会显示模糊。

编辑

由于需要使用Visual,我又做了一些搜索,发现了this thread。你可以使用BitmapCacheBrush,将SnapsToDevicePixels设置为true,它应该可以在没有模糊的情况下工作:

using (var context = visual.RenderOpen())
{
    var vb = new BitmapCacheBrush(source)
    {
        BitmapCache = new BitmapCache { SnapsToDevicePixels = true}
    };
    context.DrawRectangle(vb, null, new Rect(0, 0, width, height));
}

相关问题