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?
Thanks.
EDIT:
To my defense, I tried to upload that document to google drive and the image is not displayed either. Maybe there are no simple solutions?
pip install Pillow
from PIL import Image
Image.open("xxx.wmf").save("xxx.png")
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)
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.
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.
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:
build a libreoffice container using this Dockerfile(or install libreoffice)
FROM linuxserver/libreoffice:7.2.2
start a RESTful API(or RPC API) in the container receiving an emf file and sending back a png file
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
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:
https://stackoverflow.com/a/28749719/3552975
https://ask.libreoffice.org/t/convert-to-jpg-wmf-on-linux-resolution-issue/44578
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
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])
Related
I'm a beginner in python and I'm trying to send someone my small python program together with a picture that'll display when the code is run.
I tried to first convert the image to a binary file thinking that I'd be able to paste it in the source code but I'm not sure if that's even possible as I failed to successfully do it.
You can base64-encode your JPEG/PNG image which will make it into a regular (non-binary string) like this:
base64 -w0 IMAGE.JPG
Then you want to get the result into a Python variable, so repeat the command but copy the output to your clipboard:
base64 -w0 IMAGE.JPG | xclip -selection clipboard # Linux
base64 -w0 IMAGE.JPG | pbcopy # macOS
Now start Python and make a variable called img and paste the clipboard into it:
img = 'PASTE'
It will look like this:
img = '/9j/4AAQSk...' # if your image was JPEG
img = 'iVBORw0KGg...' # if your image was PNG
Now do some imports:
from PIL import Image
import base64
import io
# Make PIL Image from base64 string
pilImage = Image.open(io.BytesIO(base64.b64decode(img)))
Now you can do what you like with your image:
# Print its description and size
print(pilImage)
<PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=200x100>
# Save it to local disk
pilImage.save('result.jpg')
You can save a picture in byte format inside a variable in your program. You can then convert the bytes back into a file-like object using the BytesIO function of the io module and plot that object using the Image module from the Pillow library.
import io
import PIL.Image
with open("filename.png", "rb") as file:
img_binary = file.read()
img = PIL.Image.open(io.BytesIO(img_binary))
img.show()
To save the binary data inside your program without having to read from the source file you need to encode it with something like base64, use print() and then simply copy the output into a new variable and remove the file reading operation from your code.
That would look like this:
img_encoded = base64.encodebytes(img_binary)
print(img_binary)
img_encoded = " " # paste the output from the console into the variable
the output will be very long, especially if you are using a big image. I only used a very small png for testing.
This is how the program should look like at the end:
import io
import base64
import PIL.Image
# with open("filename.png", "rb") as file:
# img_binary = file.read()
# img_encoded = base64.encodebytes(img_binary)
img_encoded = b'iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABX[...]'
img = PIL.Image.open(io.BytesIO(base64.decodebytes(img_encoded)))
img.show()
You could perhaps have your Python program download the image from a site where you upload files such as Google Drive, Mega, or Imgur. That way, you can always access and view the image easily without the need of running the program or for example converting the binary back into the image in the method you mentioned.
Otherwise, you could always store the image as bytes in a variable and have your program read this variable. I'm assuming that you really wish to do it this way as it would be easier to distribute as there is only one file that needs to be downloaded and run.
Or you could take a look at pyinstaller which is made for python programs to be easily distributed across machines without the need to install Python by packaging it as an executable (.exe) file! That way you can include the image file together by embedding it into the program. There are plenty of tutorials for pyinstaller you could google up. Note: Include the '--onefile' in your parameters when running pyinstaller as this will package the executable into a single file that the person you're sending it to can easily open whoever it may be-- granted the executable file can run on the user's operating system. :)
Problem:
I want to import all ".pgm" files from several folders and store them as ".png".
For this I use the following lines of code:
from glob import glob
files=glob('yaleB*/*.pgm')
print 'number of files is',len(files)
count=0
for f in files:
new_f=f[:-3]+'png'
!convert $f $new_f
count += 1
if count % 100==0:
print count,f,new_f
Unfortunately, I always get this error: "command not found: convert"
Is there a simple fix for this?
My assumption is, that this is an "old" command (Jupyter Notebook where I took this code from is from 2014..)
you can try using os and pillow
import os
from PIL import Image
for file in os.listdir():
filename, extension = os.path.splitext(file)
if extension == ".pgm":
new_file = "{}.png".format(filename)
with Image.open(file) as im:
im.save(new_file)
The exclamation mark (!) means it is an external command, and convert is part of the ImageMagick package.
So you would need to install ImageMagick for it to work. Note that if you install v7 or newer, the command would become:
!magick INPUT.PGM OUTPUT.PNG
However, if you want to convert all PGM files in the current directory to PNG files, you don't even need a loop, you can do them all in one go with:
magick mogrify -format png *.pgm
Yet more caveats... there is no real need from a Python point of view to convert PGM files to PNG, since OpenCV, PIL/Pillow, wand and scikit-image can all read PGM files anyway. So can GIMP, feh, eog, Photoshop.
I've downloaded a bunch of .krn files, and I'd like to convert them into images - either pngs or jpgs - using music21. I've tried this:
When I do this:
from music21 import *
op = krnfile
s = converter.parse(op)
s.show()
I see a great image file in the Jupyter Notebook I'm using, but when I try to save that file programatically like this:
s.write(fp = 'outputfile.png', fmt = 'png')
It says:
Music21ObjectException: cannot support showing in this format yet: png
Which seems a little weird since it obviously manages to make an image for display in the notebook.
It looks like maybe I could use LilypondConverter.createPNG(fileName=None) from this, but is installing Lilypond required? I already have MuseScore2 installed, which opens when I call s.show().
Thanks a lot!
Alex
Install musescore on your computer, re-run python -m music21.configure to help it find it and then do:
from music21 import *
op = 'krnfile.krn'
s = converter.parse(op)
fp = s.write('musicxml.png')
# or just s.show('musicxml.png') to test that it works.
If it's a multi-page file, fp will be the path to the first page. It will end in -1 or -01 or -001 etc. You can read through the directory to find other files with the same name until there are no more to get all the images.
If you use n.show('lily.png'), it should create a temporary png file somewhere. Try to use it and an image may open.
Sorry i don't know much yet, I hope it helps.
I am trying to add simple text to a mp4 file. I have the mp4 file and I am using moviepy to add the text clip, however, I am continually running into errors.
My code:
import moviepy.editor as mpy
video_name='Test.mp4'
video = mpy.VideoFileClip('test_movie.mp4')
text = mpy.TextClip("Test", font="Arial", fontsize=40, color='white')
text = text.set_position('upper left').set_duration(video.duration)
test = mpy.CompositeVideoClip([video, text])
test.write_videofile('{}.mp4'.format(video_name))
And here is the error:
IOError: MoviePy Error: creation of None failed because of the following error:
convert: delegate library support not built-in '/Library/Fonts//Arial.ttf' (Freetype) # warning/annotate.c/RenderFreetype/1847.
convert: no decode delegate for this image format `PNG' # error/constitute.c/ReadImage/512.
convert: no images defined `PNG32:/var/folders/l3/m81nh88n57s9ck30_fqd09cmcfj06p/T/tmp06GxjE.png' # error/convert.c/ConvertImageCommand/3275.
.
.This error can be due to the fact that ImageMagick is not installed on your computer, or (for Windows users) that you didn't specify the path to the ImageMagick binary in file conf.py, or that the path you specified is incorrect
ImageMagick is installed on my system and I have been through a few threads on here but nothing has pointed me in the right direction. My font library is not empty and I do not know what it is having this issue. Any help would be greatly appreciated. I am on a Mac and using Spyder for a GUI.
Try to install ImageMagick from their website.
If the problem still there, find the moviepy/config_defaults.py and after the last line add:
IMAGEMAGICK_BINARY = "C:\\Program Files\\ImageMagick_VERSION\\convert.exe
I am new to python. I want to do some image analysis using the python on Raspberry Pi.
I am streaming images using motion to a folder. In that folder, I want to find the latest image at any point of time. Then I would like to apply my image analysis command on that one image and export the results to a text file. I have achieved most parts of it. But struck at one small bit.
import subprocess
import os
import glob
newest = max(glob.iglob('*.[p][n][g]'), key=os.path.getctime)
print(newest)
cmd = "sudo ./deepbelief lena.png > try5.txt"
proc = subprocess.Popen(cmd, shell=True)
In the above deepbelief is my image analysis program. Now the problem is how can I feed my newest image as input to the command ./deepbelief.
Also, if possible, can I save newest image as an png file for later use?
Many thanks in advance!
You can use string formatting:
cmd = "sudo ./deepbelief {} > try5.txt".format(newest)
The {} will be whatever the value of newest is, so for example if newest is foo.png, you're command will be "sudo ./deepbelief foo.png > try5.txt" and so on..