C# 将WPF可视元素另存为JPEG

C# 将WPF可视元素另存为JPEG,c#,wpf,encoding,visiblox,C#,Wpf,Encoding,Visiblox,这件事快把我逼疯了 我有一张Visiblox图表。我目前正在使用以下代码将其导出为PNG: var chart = this.CalibrationChartVisibility == Visibility.Visible ? this.calibrationChart : this.residualChart; var transform = chart.LayoutTransform; chart.LayoutTransform = null; var

这件事快把我逼疯了

我有一张Visiblox图表。我目前正在使用以下代码将其导出为PNG:

    var chart = this.CalibrationChartVisibility == Visibility.Visible ? this.calibrationChart : this.residualChart;


    var transform = chart.LayoutTransform;
    chart.LayoutTransform = null;

    var width = (int)chart.ActualWidth;
    var height = (int)chart.ActualHeight;

    var rtb = new RenderTargetBitmap(width, height, 96, 96, PixelFormats.Pbgra32);
    rtb.Render(chart);

    var encoder = new PngBitmapEncoder();
    encoder.Frames.Add(BitmapFrame.Create(rtb));

    var stream = new MemoryStream();

    encoder.Save(stream);
    stream.Position = 0;

    chart.LayoutTransform = transform;
    return stream.ToArray();
我得到了这样的结果:

但现在我还需要将其导出为JPEG格式。我认为这很简单,只需更改编码器,但这是我得到的:

我试过这个:

这是:

这是:

以及ervey sugestion在这篇文章中:

或者这个:

还有我脑海中闪过的一切,但结果还是一样

一定有什么我忽略了,但我不知道是什么

免责声明:我提供了这个问题的答案,并打算投票结束这个问题,作为另一个问题的副本,但不能,因为问题作者没有接受答案

在WPF中,每个UI元素都扩展了在WPF中提供呈现支持的。还有一个具有将
可视对象作为输入参数的。因此,您可以将
ImageSource
设置为
Image
Source
属性,只需将
图像
渲染为
位图
图像:

Image yourImageObject = new Image();
yourImageObject.Source = yourImageSource;

RenderTargetBitmap renderTargetBitmap = 
    new RenderTargetBitmap(width, height, 96, 96, PixelFormats.Default);
renderTargetBitmap.Render(yourImageObject);

// Save to .png file
PngBitmapEncoder pngBitmapEncoder = new PngBitmapEncoder();    
pngBitmapEncoder.Frames.Add(BitmapFrame.Create(renderTargetBitmap));    
using (Stream stream = File.Create(filepath))    
{    
    pngBitmapEncoder.Save(stream);    
}
由于这在互联网上有很好的记录,我不想在这里重复整个故事。要了解完整的故事,请参阅Dot NET Tricks网站的页面,这也将帮助您满足打印要求


更新>>>

好的,除了你想用一个对象来代替之外,这大部分都以同样的方式应用于你。链接页面中的此示例显示了保存JPEG图像的另一种方法:

int width = 128;
int height = width;
int stride = width / 8;
byte[] pixels = new byte[height * stride];

// Define the image palette
BitmapPalette myPalette = BitmapPalettes.Halftone256;

// Creates a new empty image with the pre-defined palette
BitmapSource image = BitmapSource.Create(
    width,
    height,
    96,
    96,
    PixelFormats.Indexed1,
    myPalette,
    pixels,
    stride);

FileStream stream = new FileStream("new.jpg", FileMode.Create);
JpegBitmapEncoder encoder = new JpegBitmapEncoder();
TextBlock myTextBlock = new TextBlock();
myTextBlock.Text = "Codec Author is: " + encoder.CodecInfo.Author.ToString();
encoder.FlipHorizontal = true;
encoder.FlipVertical = false;
encoder.QualityLevel = 30;
encoder.Rotation = Rotation.Rotate90;
encoder.Frames.Add(BitmapFrame.Create(image));
encoder.Save(stream);

如果您有任何问题,请告诉我。

总结评论,这似乎是一个背景问题,因为此问题附带的PNG具有除图表线之外的所有透明内容,并且由于JPEG不支持透明,因此所有透明内容都将为黑色


最简单的解决方案是将图表背景设置为某种颜色

您是否尝试将图表背景设置为白色?似乎是透明度问题。如果不可能,请尝试将图表放置在背景为白色(或您期望的颜色)的边框中,然后将边框渲染到图像。@memoryofadream我已经检查了您附加到这个问题的PNG,除了图表线之外的所有内容都是透明的,因为JPEG不支持透明,所以所有透明的内容都将是黑色的。把背景调成一些颜色我感觉到了你的痛苦,已经做到了。我的解决方案是有一个空白位图,上面有所需的背景(即全蓝色),并在上面渲染!它可能不会赢得任何程序员奖项,但它的速度非常快。再加上背景渐变位图,它看起来有点专业了。@dkozl这会是如此明显吗?我甚至没有考虑过透明度。不幸的是,我要到下周三才能知道,但如果是这样的话,我会告诉你的。我现在真的觉得自己很愚蠢,因为我没有考虑这个问题。@dkozl看来你设置背景的想法是对的。如果您愿意提供此解决方案作为答案,我会将其标记为此问题的正式答案。是否要对投票人发表评论,或者您会继续毫无意义地沉默地否决投票?我没有否决投票。但我可以看出,您关注的是如何生成和保存图像,而不是如何对其应用背景色。OP的图像是透明的,所以他需要设置视觉背景,或者在已经绘制的图像上绘制。这是我自己的观察,这是技术性的。不过,我怀疑该驾车经过是在其他地方提供的,因为没有任何解释,而且肯定有理由作出解释。@GayotFow,感谢您的有益评论。我认为你的观察在这种情况下可能是正确的。。。似乎作者需要做的所有问题都是在其图形控件上设置
Control.Background
属性,然后使用当前代码再次保存JPEG。谢谢你指出这一点,因为我错过了。。。在回答之前,我们确实需要阅读所有的评论。