简体   繁体   中英

How to convert an SVG file to an EMF file in C#

It's definitely possible to convert an SVG to EMF, for example this website . I wonder if it's possible to achieve this conversion in C#?


Update:

I tried to read an SVG file using SVG.NET and draw it to a Graphics object, then tried export the Image as a MetaFile in .emf extension (I followed the instruction here: GDI+ / C#: How to save an image as EMF? ). The reading was done successfully and the image did get exported as .emf. However, when I opened that .emf in PowerPoint, it couldn't be un-grouped, which indicated that the drawing info of that file was actually not dumped correctly.

Update 2:

Now it does export a ungroup-able .emf, but the ungrouping shows a really poor result. I used the following code to produce the .emf:

private void OpenPictureButtonClick(object sender, EventArgs e)
{
    var openFileDialog = new OpenFileDialog();
    openFileDialog.ShowDialog();

    _svgDoc = SvgDocument.Open(openFileDialog.FileName);

    RenderSvg(_svgDoc);
}

private void SavePictureClick(object sender, EventArgs e)
{
    var saveFileDialog = new SaveFileDialog {Filter = "Enhanced Meta File | *.Emf"};
    saveFileDialog.ShowDialog();

    var path = saveFileDialog.FileName;
    var graphics = CreateGraphics();
    var img = new Metafile(path, graphics.GetHdc());
    var ig = Graphics.FromImage(img);

    _svgDoc.Draw(ig);

    ig.Dispose(); img.Dispose(); graphics.ReleaseHdc(); graphics.Dispose();
}

private void RenderSvg(SvgDocument svgDoc)
{
    svgImageBox.Image = svgDoc.Draw();
}

I had the same issue but searching had no results.
Finally I ended up with my own simple solution below. I used SVG.NET .

public static byte[] ConvertToEmf(string svgImage)
{
    string emfTempPath = Path.GetTempFileName();
    try
    {
        var svg = SvgDocument.FromSvg<SvgDocument>(svgImage);
        using (Graphics bufferGraphics = Graphics.FromHwndInternal(IntPtr.Zero))
        {
            using (var metafile = new Metafile(emfTempPath, bufferGraphics.GetHdc()))
            {
                using (Graphics graphics = Graphics.FromImage(metafile))
                {
                    svg.Draw(graphics);
                }
            }
        }

        return File.ReadAllBytes(emfTempPath);
    }
    finally
    {
        File.Delete(emfTempPath);
    }
}

At first I create a temp file. Then I use Draw(Graphics) method to save emf in it. And at last I read bytes from temp file.
Don't try to use MemoryStream for Metafile . Unfortunately, it's not working.

This is what I found to be currently the best solution. This is almost like the accepted answer and uses SVG.NET , but is capable of doing it in memory.

The important changes are to release the handle and to reset the position memory stream.

public static Stream ConvertSvgToEmf(string svgImage)
{
    using var writeStream = new MemoryStream();

    var svg = SvgDocument.FromSvg<SvgDocument>(svgImage);
    var stream = new MemoryStream();
    var sizedImage = new Bitmap((int)svg.Width.Value, (int)svg.Height.Value);
    using (var graphicsFromSizedImage = Graphics.FromImage(Image.FromHbitmap(sizedImage.GetHbitmap())))
    using (var metafile = new Metafile(stream, graphicsFromSizedImage.GetHdc(), EmfType.EmfPlusOnly)) // Specify EmfType for lesser file size
    using (var graphics = Graphics.FromImage(metafile))
    {
        svg.Draw(graphics);
        graphicsFromSizedImage.ReleaseHdc();
    }

    stream.Position = 0;

    return stream;
}

Be aware that the underlying implementation relies on System.Drawing and therefore the gdi must be accessible. On linux based OS's (or Docker images) libgdiplus must be installed.

As System.Drawing is considered to be deprecated , alternatives like Magick.NET may be better suited for your case.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM