2

For an application I'm currently developing, I need to create a .emf file. I've got it working when I output the result directly to a file, but I can't get it to output into a stream, which is essential to what I'm trying to do.

This code correctly generates the file, but it's outputted directly to the harddisk.

var sizedImage = new Bitmap(103, 67);
using(var graphicsFromSizedImage = Graphics.FromImage(sizedImage))
using(var metafile = new Metafile("result.emf", graphicsFromSizedImage.GetHdc()))
using(var graphics = Graphics.FromImage(metafile))
{
    graphics.DrawStuff()
    graphicsFromSizedImage.ReleaseHdc();
}

Here's my attempt to output it to a memorystream, so I could get a byte[] from that stream:

byte[] resultingBytes;
var sizedImage = new Bitmap(103, 67);
using(var stream = new MemoryStream())
using(var graphicsFromSizedImage = Graphics.FromImage(sizedImage))
using(var metafile = new Metafile(stream, graphicsFromSizedImage.GetHdc()))
using(var graphics = Graphics.FromImage(metafile))
{
    graphics.DrawStuff()
    graphicsFromSizedImage.ReleaseHdc();
    resultingBytes = stream.GetBuffer();
}
File.WriteAllBytes("result.emf", resultingBytes);

But all this does is create an empty file. When I run through it with the debugger, I can see the stream remain empty. What am I missing here..?

Dries Geenen
  • 582
  • 5
  • 14
  • 1
    what is wrong with `graphics = Graphics.FromImage(sizedImage)` and then `sizedImage.Save("result.emf)` – Selvin Jan 27 '20 at 14:03
  • @Selvin From what I've read, that wouldn't have the correct result. – Dries Geenen Jan 27 '20 at 14:06
  • Before writing the memory stream set the position to zero. – jdweng Jan 27 '20 at 14:18
  • I've set the IntPtr as the first parameter on the contructor als follows: using (var metafile = new Metafile(graphicsFromSizedImage.GetHdc(), new Rectangle(new Point(0, 0), new Size(103, 67)))) But when I call .Save() on the metafile, I get an ArgumentNullException with the following message: Value cannot be null. Arg_ParamName_Name – Dries Geenen Jan 27 '20 at 14:19
  • 1
    this is working for me https://dotnetfiddle.net/eD5vsh – Selvin Jan 27 '20 at 14:59
  • 1
    `GetBuffer` returns the *entire* underlying buffer, not just the bytes written. Even if the code did work as intended the result surely would include extraneous data. – RamblinRose Jan 27 '20 at 15:11

1 Answers1

1

I found the answer thanks to @Selvin

It turns out, the changes are only written to the MemoryStream when the "graphics" object is disposed. So, just by adding an extra set of brances, the problem is resolved.

Here's my working code:

byte[] resultingBytes;
var sizedImage = new Bitmap(103, 67);
using(var stream = new MemoryStream())
using(var graphicsFromSizedImage = Graphics.FromImage(sizedImage))
using(var metafile = new Metafile(stream, graphicsFromSizedImage.GetHdc()))
{
    using(var graphics = Graphics.FromImage(metafile))
    {
        graphics.DrawStuff()
        graphicsFromSizedImage.ReleaseHdc();
    }
    resultingBytes = stream.ToArray();
}
File.WriteAllBytes("result.emf", resultingBytes);

Edit: As some have pointed out, stream.GetBuffer() will return the entire buffer. I changed it to stream.ToArray(), which should be better.

Dries Geenen
  • 582
  • 5
  • 14