使用给定的DPI将DrawingVisual保存到图像文件

时间:2019-05-27 18:58:54

标签: c# .net wpf

我有一个WPF应用程序,我想将Canvas保存到具有正确DPI值的文件中。画布大小是实际的物理大小,例如。 20x10厘米,在300 DPI下,所以是2362x1181。

我用DrawingVisual绘制图像和形状,然后创建一个RenderTargetBitmap。 rtb的大小是Canvas的大小。 dpiX和dpiY为96。只有使用96 DPI才能获得正确的图像分辨率。当我将其设置为300时,画布将变为高档,并裁剪为2362x1181。因此,这不是很好。我试图通过dpi系数修改画布的宽度和高度值,但也没有用。

在RenderTargetBitmap之后,我使用BitmapEncoder,BitmapFrame和BinaryWriter。请参见下面的代码。效果很好,但是图像DPI值为96。我已经阅读了很多有关读取DPI,使用SetResolution保存图像的主题,但是我不想降低质量,我不想读取文件并重新保存它,我不想更改像素的宽度/高度等。

我真的只是想保存带有给定DPI的DrawingVisual。我可以为“ X Resolution”(uint = 282)和“ Y Resoulution”(uint = 283)写EXIF数据,但这并没有影响Image DPI设置,例如。 Photoshop将读取96,而不是300。

BitmapEncoder encoder = new JpegBitmapEncoder();
BitmapFrame bFrame = BitmapFrame.Create(rtb, null, meta, icc);
encoder.Frames.Add(bFrame);

using (var stream = new MemoryStream())
{
encoder.Save(stream);
byte[] imageData = stream.ToArray();
using (FileStream fs = new FileStream(path, ...)
{
BinaryWriter bw = new BinaryWriter(fs);
bw.Write(imageData);
bw.Close();
}
}

3 个答案:

答案 0 :(得分:0)

以下方法将UIElement保存为具有指定DPI值的JPEG文件:

public static void SaveElement(UIElement element, double dpi, string path)
{
    var visual = new DrawingVisual();
    var width = element.RenderSize.Width;
    var height = element.RenderSize.Height;

    using (var context = visual.RenderOpen())
    {
        context.DrawRectangle(new VisualBrush(element), null,
            new Rect(0, 0, width, height));
    }

    var bitmap = new RenderTargetBitmap(
        (int)(width * dpi / 96), (int)(height * dpi / 96),
        dpi, dpi, PixelFormats.Default);
    bitmap.Render(visual);

    var encocer = new JpegBitmapEncoder();
    encocer.Frames.Add(BitmapFrame.Create(bitmap));

    using (var stream = File.OpenWrite(path))
    {
        encocer.Save(stream);
    }
}

或者,将DPI缩放比例应用于DrawingVisual:

public static void SaveElement(UIElement element, double dpi, string path)
{
    var visual = new DrawingVisual();
    var width = element.RenderSize.Width;
    var height = element.RenderSize.Height;

    using (var context = visual.RenderOpen())
    {
        context.DrawRectangle(new VisualBrush(element), null,
            new Rect(0, 0, width / dpi * 96, height / dpi * 96));
    }

    var bitmap = new RenderTargetBitmap(
        (int)width, (int)height, dpi, dpi, PixelFormats.Default);
    bitmap.Render(visual);

    var encocer = new JpegBitmapEncoder();
    encocer.Frames.Add(BitmapFrame.Create(bitmap));

    using (var stream = File.OpenWrite(path))
    {
        encocer.Save(stream);
    }
}

答案 1 :(得分:0)

我尝试将DPI缩放应用于DrawingVisual,但产生的图像质量较差。 :(同样,我尝试将画布设置为756x378(96 DPI大小),然后将RenderTargetBitmap设置为2362x1181和300 DPI,但是这也会产生较低的图像质量。因此,看起来无论是缩小还是放大,然后缩小还是缩小都不是最佳解决方案。DrawingVisual必须使用最终的渲染尺寸。

答案 2 :(得分:0)

毕竟,解决方案似乎是Bitmap SetResolution。我测试了它,看起来像不影响JpegBitmapEncoder()之后的图像质量!并且图像分辨率保持不变,保留元数据,只有DPI会改变!

帮助了此文档:https://docs.microsoft.com/en-us/dotnet/framework/winforms/advanced/how-to-set-jpeg-compression-level

克莱门斯,还是谢谢您的帮助!

set encoding=utf-8