Make and use a metafile in C#


This example shows how to draw and use a metafile. A metafile is a drawing that doesn’t just contain the pixels in an image. Instead it contains a record of the commands used to produce a drawing so you can rerun those commands later.

When the program starts, it executes the following code.

private void Form1_Load(object sender, EventArgs e)
    // Make a metafile.
    Metafile mf = MakeMetafile(100, 100, "test.emf");

    // Draw on the metafile.

    // Convert the metafile into a bitmap.
    Bitmap bm = MetafileToBitmap(mf);

    // Display in various ways.
    picCanvas1.Image = bm;  // Original size.
    picCanvas2.Image = bm;  // Stretches pixelated.
    picCanvas3.Image = mf;  // Stretches smoothly.

This code calls the MakeMetafile method (I’ll describe all of these methods shortly) to create a 100×100 pixel metafile, and then calls DrawOnMetafile to draw some shapes on the metafile. It then calls MetafileToBitmap to convert the metafile into a bitmap. It displays the bitmap on two PictureBox controls and displays the metafile itself on a third.

If you look at the picture above, you’ll see that the top PictureBox shows a nice crisp image. That’s the first PictureBox displaying the bitmap at its correct size.

The second and third PictureBox controls stretch when you resize the form. In the second the bitmap is stretched so it looks a bit fuzzy and pixelated.

The third PictureBox displays the metafile itself. When it is stretched, it uses the metafile to repeat the original drawing commands. That gives it a smooth, crisp result even when it’s resized. (In case you didn’t make the obvious connection, this is the best way to use a metafile. Simply display it in a PictureBox and let it redraw as needed.)

The following code shows the MakeMetafile method.

// Return a metafile with the indicated size.
private Metafile MakeMetafile(float width, float height,
    string filename)
    // Make a reference bitmap.
    using (Bitmap bm = new Bitmap(16, 16))
        using (Graphics gr = Graphics.FromImage(bm))
            RectangleF bounds =
                new RectangleF(0, 0, width, height);

            Metafile mf;
            if ((filename != null) && (filename.Length > 0))
                mf = new Metafile(filename, gr.GetHdc(),
                    bounds, MetafileFrameUnit.Pixel);
                mf = new Metafile(gr.GetHdc(), bounds,

            return mf;

This method creates a metafile of the specified size, optionally saving it into a file.

To create a new metafile, you need a graphics device handle. To get one, the code create a 16×16 pixel bitmap. The bitmap’s size isn’t important; the code really just needs to use it to get a graphics device handle.

Next the code creates a Graphics object associated with the bitmap. This is the object that will provide the device handle.

The code then creates a RectangleF representing the metafile’s desired size.

The code then creates the metafile. If the filename is not null or blank, it includes the filename in the metafile constructor to make it create the file. (You don’t need to save the file in a separate step.)

The code also passes the constructor the Graphics object’s HDC (handle to device context), which the constructor uses to get information about the device where the metafile will be drawn. Finally the code passes the constructor the rectangle defining the metafile’s bounds and a flag indicating that we’re measuring in pixels.

The call to the Graphics object’s GetHdc method locks the object’s device context so the code then calls its ReleaseHdc method to it can clean up the Graphics object correctly.

The method finishes by returning the metafile.

The MakeMetafile method is probably the most confusing part of the program. The following code shows the DrawOnMetafile method.

// Draw on the metafile.
private void DrawOnMetafile(Metafile mf)
    using (Graphics gr = Graphics.FromImage(mf))
        gr.SmoothingMode = SmoothingMode.AntiAlias;
        using (Pen pen = new Pen(Color.Red, 5))
            gr.DrawEllipse(pen, 5, 5, 90, 90);
        using (Brush brush = new SolidBrush(
            Color.FromArgb(255, 128, 255, 128)))
            gr.FillEllipse(brush, 5, 25, 90, 50);
        using (Brush brush = new SolidBrush(
            Color.FromArgb(128, 128, 128, 255)))
            gr.FillEllipse(brush, 25, 5, 50, 90);
        Point[] points =
            new Point(50, 5),
            new Point(94, 50),
            new Point(50, 94),
            new Point(5, 50),
        gr.DrawPolygon(Pens.Blue, points);

This method is straightforward. It simply creates a Graphics object associated with the metafile and uses it to draw some shapes just as you would if you were drawing on a bitmap or in a Paint event handler.

Finally, the following code shows the MetafileToBitmap method that converts the metafile into a bitmap.

// Draw the metafile onto a bitmap.
private Bitmap MetafileToBitmap(Metafile mf)
    Bitmap bm = new Bitmap(mf.Width, mf.Height);
    using (Graphics gr = Graphics.FromImage(bm))
        GraphicsUnit unit = GraphicsUnit.Pixel;
        RectangleF source = mf.GetBounds(ref unit);

        PointF[] dest =
            new PointF(0, 0),
            new PointF(source.Width, 0),
            new PointF(0, source.Height),
        gr.DrawImage(mf, dest, source, GraphicsUnit.Pixel);
    return bm;

This method creates a bitmap the same size as the metafile and creates an associated Graphics object. It then uses the somewhat awkward GetBounds method to get the metafile’s bounds in pixels, makes an array of points to define the destination area on the bitmap, and then draws the metafile onto the bitmap. It finishes by returning the bitmap.

The MetafileToBitmap method is mostly here to show you how to draw the metafile to a specific place on an image. For example, you could draw several metafiles and other graphics onto a single image. If you only want to display the metafile, you should just load it and set a PictureBox control’s Image property equal to the metafile, as I mentioned earlier.

Download Example   Follow me on Twitter   RSS feed   Donate

About RodStephens

Rod Stephens is a software consultant and author who has written more than 30 books and 250 magazine articles covering C#, Visual Basic, Visual Basic for Applications, Delphi, and Java.
This entry was posted in drawing, graphics and tagged , , , , , , , , , , , . Bookmark the permalink.

3 Responses to Make and use a metafile in C#

  1. Pingback: Read and draw a metafile in C# - C# HelperC# Helper

  2. Hi Rod,

    I came upon your article this week. I was wondering if there was a way to rotate an EMF/WMF to either side. I used your code as a starting point and created my own image that actually resembles a form with data on it. I want to use it upright, or rotated 90, 180, or 270 degrees. However, when I call mf.RotateFlip(RotateFlipType.Rotate90FlipNone), I get a NotImplementedException.

    Do you perhaps know of a way to rotate a WMF, while still keeping the quality? I have tried to convert it to Bitmap, PNG, etc, and then rotating the image, but the image looks terrible after that.

    • RodStephens says:

      I’ve pounded on this for a while now. Unfortunately the support for metafiles in .NET is pretty limited.

      This post on the Microsoft forums looks like it should work. It was even working for me for a while, but then it mysteriously stopped working. Perhaps it will work for you.

      The best workaround I can think of that I’m pretty sure will work would be to convert it into a bitmap and then rotate it. That should give you a crisp image as long ass you don’t later resize the bitmap.

      So, make the bitmap as large as you might ever need it to be. Then if you resize it to make it smaller, it should still look okay. If you’re going to stretch it, you might make it even bigger, perhaps twice as large as you’ll ever need it.

      You could also probably read the metafile records. You might be able to modify the metafile’s scaling parameters. Or you might be able to translate the records that you want, at least if you only want some of the simpler ones.

      You could also try loading the metafile into a WPF Image control. In theory, you should be able to use the control’s RenderTransform property to rotate it. Unfortunately I have had bad luck loading metafiles into WPF Image controls. (In fact, loading any image into that control is a bit of a hassle due to the weird way they made the Source property work.)

      Sorry I don’t have a better solution. Post a followup if you find a better solution.

Comments are closed.