【问题标题】:Saving a WPF visual element as JPEG将 WPF 视觉元素另存为 JPEG
【发布时间】:2014-06-18 17:03:15
【问题描述】:

这件事让我发疯了。

我有一个 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。我认为这很简单,只需更改编码器,但这就是我得到的:

我试过这个: http://social.msdn.microsoft.com/Forums/vstudio/en-US/31ac62d4-399b-4f2e-a9b9-749efe7528b6/rendertargetbitmap-to-file-problem?forum=wpf

还有这个: http://www.grumpydev.com/2009/01/03/taking-wpf-screenshots/

还有这个: Get a bitmap image from a Control view

和 ervey 对这篇文章的建议: How to save image using JpegBitmapEncoder

或者这个: saving WPF InkCanvas to a JPG - image is getting cropped

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

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

【问题讨论】:

  • 您是否尝试将图表背景设置为白色?似乎是透明度问题。如果不可能,请尝试将图表放置在背景为白色(或您所期望的)的边框中,然后为图像渲染边框。
  • @memoryofadream 我已经检查了您附加到这个问题的 PNG,除了图表线之外的所有内容都是透明的,并且由于 JPEG 不支持透明度,所有透明的都是黑色的。将背景设置为某种颜色
  • 我感受到了你的痛苦,在那里做过。我的解决方案是有一个带有所需背景的空白位图(即全蓝色)并在其顶部渲染!它可能不会赢得任何程序员奖项,但它的速度非常快。加上背景渐变位图,看起来半专业。
  • @dkozl 有这么明显的痛苦吗?我什至没有考虑透明度。不幸的是,我要到下周三才能知道,但如果是这样的话,我会告诉你的。我现在真的觉得自己很愚蠢,没有考虑到这一点。
  • @dkozl 看来您设置背景是对的。如果您将此解决方案作为答案提供,我会将其标记为该问题的官方答案。

标签: c# wpf encoding visiblox


【解决方案1】:

总结 cmets 这似乎是一个背景问题,因为附加到这个问题的 PNG,除了图表线之外的所有内容都是透明的,并且由于 JPEG 不支持透明度,所有透明的都是黑色的。

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

【讨论】:

    【解决方案2】:

    免责声明:我为System.Drawing.Image from ImageSource in Resources 问题提供了这个答案,并打算投票结束这个问题作为另一个问题的副本,但因为问题作者不接受答案而不能。

    在 WPF 中,每个 UI 元素都扩展了 Visual Class在 WPF 中提供了呈现支持。还有一个RenderTargetBitmap Class 有一个Render Method,它将Visual 对象作为输入参数。因此,您可以将您的 ImageSource 设置为 ImageSource 属性,然后简单地将 Image 渲染为 Bitmap 图像:

    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 网站上的 How to Render Bitmap or to Print a Visual in WPF 页面,该页面也将帮助您满足您的打印要求。


    更新>>>

    好的,所以大部分内容都以相同的方式适用于您,只是您想使用JpegBitmapEncoder 对象。链接页面中的此示例显示了另一种保存 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);
    

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

    【讨论】:

    • 关心否决选民,还是会继续默默地毫无意义地否决投票?
    • 我没有投反对票。但我可以看到您关注的是如何生成和保存图像,而不是如何为其应用背景颜色。 OP 的图像是透明的,所以他需要设置他的视觉背景,或者在已经绘制的图像上绘图。这是我自己的观察,是技术性的。我怀疑开车经过是在其他地方发生的,但是因为没有解释,而且解释肯定是有道理的。
    • @GayotFow,感谢您的有用评论。我认为您的观察在这种情况下可能是正确的......看来作者需要做的所有问题就是在他们的图形控件上设置Control.Background 属性并使用他们当前的代码再次保存JPEG。感谢您指出这一点,因为我错过了......我们确实需要在回答之前阅读所有的 cmets。
    猜你喜欢
    • 1970-01-01
    • 2013-04-01
    • 1970-01-01
    • 2010-11-22
    • 2010-09-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多