Convert EMF/WMF files to PNG/JPG
Asked Answered
A

7

12

I am receiving an form upload with a Word docx document. I got all the parsing done successfully. I have to then display that Word document on the web.

The problem I am running into at this moment is that I have embedded EMF files (that the PIL library recognizes as WMF format), and I cannot figure how to convert them to something that can be displayed on the web (arbitrarily chosen PNG).

The code is somewhat simple:

im = PIL.Image.open(StringIO.StringIO(data))
fmt = im.format
if (fmt == 'WMF'):
  fmt = 'PNG'
  output = StringIO.StringIO()
  im.save(output, format=fmt)
  data = output.getvalue()
  output.close()
return '''<img src="data:image/{0};base64,{1}" />'''.format(fmt, base64.encodestring(data))

The error I get is:

IOError: cannot find loader for this WMF file

These Word documents come from average user that may just have cut-and-paste images from the web or insert from file.

Is there a solution for me on a linux system?

I tried to upload that document to google drive and the image is not displayed either. Maybe there are no simple solutions?

Auditor answered 31/12, 2012 at 16:30 Comment(1)
Maybe libwmf + ImageMagick?Buskus
H
9
pip install Pillow
from PIL import Image

Image.open("xxx.wmf").save("xxx.png")
Hughs answered 5/5, 2016 at 7:15 Comment(2)
This worked like a charm for me. If you have a .emz file it looks like you will need to use gzip to open the file first.Hunley
Thanks, works perfectly. Just taught this to ChatGPT as its solutions were way more complex than this one :).Handclap
L
4

I found it easier to use the Wand package for such conversion. I tried the previous suggestions without success. So here is what I did: (BTW, I wanted to convert all '.wmf' files into pdf)

import os

from wand.image import Image as wima

folder='C:/Users/PythonLover/Pictures/pics'

for oldfilename in os.listdir(folder):

    if oldfilename.endswith(".wmf"):

        with wima(filename=folder+'/'+oldfilename) as img:

            newfilename = oldfilename.split('.')[0]+'.pdf'

            newfilename = folder+'/'+newfilename

            img.format = 'pdf'

            img.save(filename=newfilename)
Lourielouse answered 5/9, 2017 at 15:48 Comment(2)
This answer worked for me (+1) although, with wand v0.4.4, the results left much to be desired. We can hope that future versions will do better.Hun
Wand use ImageMagic which don't suppoert EMF and WMF on LinuxHelmer
B
3

You need to understand what you are dealing with in order to see why what you are attempting to do is problematic. WMF files (or the more recent EMF and EMF+ formats) require Windows GDI to render the image it describes. So there is no simple solution when you are converting this format outside of Windows, since you need to replicate the GDI API.

One solution is to use the unoconv tool which relies on the UNO bindings for OpenOffice/LibreOffice. A second solution would use the pyemf module to decode the input, and then a second tool (to be done by you) would render it.

Braun answered 3/1, 2013 at 1:58 Comment(6)
The image does not display in the Word docx file if opened with LibreOffice on my Linux box.Auditor
Too bad, get a better replication of GDI then.Braun
Libgdiplus (mono-project.com/Libgdiplus, github.com/mono/libgdiplus) is the better replication of GDI you are after.Braun
I tried libgdiplus as in pastebin.com/qcgH7usU but it seems problematic. It doesn't handle every GDI call (which I expected), but then trying to save as a bmp with gdip_save_bmp_image_to_file gets into the realm of undefined behavior. I might me missing something too, but trivially changing the code to load a png image and save as a bmp works. Surprisingly, there is an online service at zamzar.com that manages to convert EMF to other formats. Given the situation, I would be surprised if they are doing this conversion outside of Windows.Braun
Thanks for your help here... but what I am trying to do is to actually get the image from within the Word document and transform it to PNG/JPEG. Also, thanks for your pastebin code, but I'm looking into a Python solution. At this point, I am just throwing "Unsupported image format".Auditor
It is the most sane decision unless you were running this exclusively under Windows. Otherwise you will have to rely on a perfect GDI replication that is always up-to-date.Braun
M
1

You may use libwmf to convert image to SVG and then pyrsvg to convert to PNG (described in another question).

I haven't found libwmf project website, but Debian (and Ubuntu) has package libwmf-bin that contains wmf2svg utility.

Malia answered 31/12, 2012 at 20:45 Comment(0)
I
0

WMF stands for Windows Metafile; EMF stands for Enhanced Metafile. These files drive Windows to display an image. Within Microsoft Office applications it is a standard format for vector images. The Metafile is managed by Microsoft and is not an open format.

Since libreoffice is an alternative to Microsoft Office in Linux environment, it would be better to have a small service where we can use libreoffice and imagemagick(install them if you cannot).

Then a language independent solution would be this:

  1. build a libreoffice container using this Dockerfile(or install libreoffice)

    FROM linuxserver/libreoffice:7.2.2

  2. start a RESTful API(or RPC API) in the container receiving an emf file and sending back a png file

  3. in the service we implement the following function:
    a. save the emf file in a path, say /mnt/b.emf
    b. convert the file by the command libreoffice --headless --convert-to png /mnt/b.emf in any language; for example, in Python we can use the snippet at the end of this answer.
    c. read the png file /mnt/b.png and send it back via the API

  4. use imagemagick to trim the white space of the resultant image

Here is the Python implementation:

from os 
from flask import Flask, jsonify, request

def emf_to_png(im):
    temp_emf_path = '/tmp/temp.emf'
    temp_png_path = '/tmp/temp.png'
    with open(temp_emf_path, 'wb') as f: 
        f.write(im)
    command = f"libreoffice --headless --convert-to png {temp_emf_path} --outdir  /tmp"
    os.system(command)
    command = f'convert {temp_png_path} -fuzz 1% -trim +repage {temp_png_path}'
    os.system(command)
    f = open(temp_png_path, 'rb')
    png_b = f.read()
    f.close()
    os.remove(temp_emf_path)
    os.remove(temp_png_path)
    return png_b

app = Flask(__name__)
@app.route("/convert/emf2png", methods=["POST"])
def start_training():
    try:
        emf = request.data
        png_b = emf_to_png(emf)
        return jsonify(code=200, message="succeed", data=png_b)
    except Exception as e:
        return jsonify(code=100, message=f"error {e}")

if __name__ == '__main__':
    app.run("0.0.0.0", port=1111)

References:

  1. https://mcmap.net/q/847838/-imagemagick-on-linux-to-convert-emf-to-png
  2. https://ask.libreoffice.org/t/convert-to-jpg-wmf-on-linux-resolution-issue/44578
Insurgency answered 27/5, 2022 at 12:33 Comment(0)
S
0

I have a similar problem, but I used bash and inkscape to convert the images to png format, I attach the small script that performs this task for me:

#!/usr/bin/bash

for file in *.emf; do
  export_name=$(echo $file | sed 's/\.emf$/.png/');
  echo inkscape $file -e $export_name
  inkscape $file -e $export_name
done

For more information, check the inkscape option:

 inkscape --help
# -e, --export-png=FILE NAME
Spindell answered 8/7, 2022 at 15:53 Comment(0)
R
0

On linux you can use inkscape to do the conversion from .emf to .png with the help of command (pip install Command)
I also tried pillow and wand before, they both only works on windows.

import command

path_emf = 'path_to_your_emf_file'
path_png = 'path_to_save_png_file'

command.run(['inkscape', '-e', path_png, path_emf])
Radioscopy answered 14/11, 2022 at 1:56 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.