Danosaure
Danosaure

Reputation: 3655

Convert EMF/WMF files to PNG/JPG

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?

Upvotes: 12

Views: 24435

Answers (7)

zhaozhi
zhaozhi

Reputation: 1581

pip install Pillow
from PIL import Image

Image.open("xxx.wmf").save("xxx.png")

Upvotes: 9

yufeng
yufeng

Reputation: 1

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])

Upvotes: 0

fitorec
fitorec

Reputation: 4765

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

Upvotes: 0

Lerner Zhang
Lerner Zhang

Reputation: 7130

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

Upvotes: 0

Kass
Kass

Reputation: 41

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)

Upvotes: 4

mmgp
mmgp

Reputation: 19221

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.

Upvotes: 4

Michał Zieliński
Michał Zieliński

Reputation: 1345

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.

Upvotes: 1

Related Questions