3

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.

Community
  • 1
  • 1
memory of a dream
  • 1,207
  • 3
  • 23
  • 32
  • 3
    did you try setting chart background to white? seems like the transparency issue. if not possible then try to place the chart in a border with background white ( or what you expect) and then render border to the image. – pushpraj Jun 11 '14 at 13:33
  • 2
    @memoryofadream I've checked PNG that you attached to this question and everything apart from chart lines is transparent and since JPEG does not support transparency all that is transparent will be black. Set background to some color – dkozl Jun 11 '14 at 13:36
  • I feel your pain, been there done that. My solution was to have a blank bitmap with the desired background on it (i.e., all blue) and render on TOP of it! It probably will not win any programmer awards, but it's ruthlessly quick. Plus with a background gradient bitmap, it looks half-way professional. – Gayot Fow Jun 11 '14 at 14:07
  • @dkozl Could it be that painfully obvious? I haven't even considered transparency. Unfortunately I won't know until next Wednesday, but I'll let you know if that is the case. I really feel stupid right now for not considering this. – memory of a dream Jun 11 '14 at 18:20
  • @dkozl it seems that you were right about setting the background. If you would provide this solution as an answer I will mark it as the official answer for this question. – memory of a dream Jun 18 '14 at 08:57
  • Sure, [answer](http://stackoverflow.com/questions/24164024/saving-a-wpf-visual-element-as-jpeg/24281367#24281367) added – dkozl Jun 18 '14 at 09:03

2 Answers2

2

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

dkozl
  • 32,814
  • 8
  • 87
  • 89
-1

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.

Community
  • 1
  • 1
Sheridan
  • 68,826
  • 24
  • 143
  • 183
  • 1
    Care to comment down voter, or will you continue to pointlessly down vote in silence? – Sheridan Jun 11 '14 at 14:48
  • I did not down vote. But I can see that you're focusing on how to generate and save an image, but not how to apply a background colour to it. The OP's images are transparent, so he needs to set the background of his visual, or to draw on to an image that's already painted. This is my own observation, which is technical. I suspect the drive-by was provinanced elsewhere however since there is no explanation and an explanation is certainly warranted. – Gayot Fow Jun 11 '14 at 15:17
  • @GayotFow, thank you for your helpful comment. I think that your observation might be correct in this case... it does appear that all the question author needs to do is to set the `Control.Background` property on their graph control and use their current code to save the JPEG again. Thanks for pointing that out, as I had missed that... we really do need to read all of the comments as well before answering. – Sheridan Jun 11 '14 at 15:28