memory of a dream
memory of a dream

Reputation: 1267

Saving a WPF visual element as JPEG

This thing has been driving me crazy.

I have a Visiblox chart. which I'm currently exporting as a PNG using the following code:

    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();

and I get something like this: png chart

But now I need to also need to export it as a JPEG. I thought it would be simple, just change the encoder but this is what I get: jpg chart

I've tried this: http://social.msdn.microsoft.com/Forums/vstudio/en-US/31ac62d4-399b-4f2e-a9b9-749efe7528b6/rendertargetbitmap-to-file-problem?forum=wpf

and this: http://www.grumpydev.com/2009/01/03/taking-wpf-screenshots/

and this: Get a bitmap image from a Control view

and ervey sugestion on this post: How to save image using JpegBitmapEncoder

or this one: saving WPF InkCanvas to a JPG - image is getting cropped

and everything else which crossed my mind, but the outcome is still the same.

There must be something I'm overlooking but I have no idea what it is.

Upvotes: 3

Views: 5050

Answers (2)

dkozl
dkozl

Reputation: 33364

To sum up comments this seems to be a background issue as PNG, attached to this question, has everything transparent apart from chart lines and since JPEG does not support transparency all that is transparent will be black.

Simpliest solution would be to set background of chart to some color

Upvotes: 2

Sheridan
Sheridan

Reputation: 69959

Disclaimer: I provided this answer for the System.Drawing.Image from ImageSource in Resources question and was going to vote to close this question as a duplicate of the other, but couldn't because the question author didn't accept the answer.

In WPF, every UI element extends the Visual Class which Provides rendering support in WPF. There is also a RenderTargetBitmap Class that has a Render Method that takes a Visual object as an input parameter. So you could set your ImageSource as the Source property of an Image and simply render the Image to a Bitmap image:

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);    
}

As this is well documented on the internet, I won't bother to repeat the whole story here. To find out the full story, please see the How to Render Bitmap or to Print a Visual in WPF page from the Dot NET Tricks website, which will also help you with your printing requirement.


UPDATE >>>

Ok, so most of this applies to you in just the same way, except that you'd want to use a JpegBitmapEncoder object instead. This example from the linked page shows another way to save a JPEG image:

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);

Please let me know if you have any problems.

Upvotes: -1

Related Questions