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?

mkrieger1
  • 19,194
  • 5
  • 54
  • 65
Danosaure
  • 3,578
  • 4
  • 26
  • 41

7 Answers7

7
pip install Pillow
from PIL import Image

Image.open("xxx.wmf").save("xxx.png")
mkrieger1
  • 19,194
  • 5
  • 54
  • 65
zhaozhi
  • 1,491
  • 1
  • 16
  • 19
  • 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. – Studybuffalo Jul 31 '17 at 17:35
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)
John1024
  • 109,961
  • 14
  • 137
  • 171
Kass
  • 41
  • 1
  • 1
    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. – John1024 Jan 31 '18 at 02:49
2

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.

mmgp
  • 18,901
  • 3
  • 53
  • 80
  • The image does not display in the Word docx file if opened with LibreOffice on my Linux box. – Danosaure Jan 03 '13 at 15:26
  • Too bad, get a better replication of GDI then. – mmgp Jan 03 '13 at 15:26
  • 1
    Libgdiplus (http://www.mono-project.com/Libgdiplus, https://github.com/mono/libgdiplus) is the better replication of GDI you are after. – mmgp Jan 03 '13 at 16:24
  • I tried libgdiplus as in http://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 http://www.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. – mmgp Jan 03 '13 at 18:20
  • 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". – Danosaure Feb 07 '13 at 07:42
  • 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. – mmgp Feb 12 '13 at 19:09
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.

Community
  • 1
  • 1
Michał Zieliński
  • 1,345
  • 11
  • 13
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://stackoverflow.com/a/28749719/3552975
  2. https://ask.libreoffice.org/t/convert-to-jpg-wmf-on-linux-resolution-issue/44578
Lerner Zhang
  • 6,184
  • 2
  • 49
  • 66
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
fitorec
  • 4,257
  • 2
  • 24
  • 18
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])
yufeng
  • 1