I run into several problems when I try to open EPS- or SVG-Images with PIL.
Opening EPS
from PIL import Image
test = Image.open('test.eps')
ends in:
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "C:\Python27\Lib\site-packages\PIL\Image.py", line 1965, in open
return factory(fp, filename)
File "C:\Python27\Lib\site-packages\PIL\ImageFile.py", line 91, in __init__
self._open()
File "C:\Python27\Lib\site-packages\PIL\EpsImagePlugin.py", line 206, in _open
raise IOError, "bad EPS header"
IOError: bad EPS header
Also opening SVG ends in IOError: cannot identify image file.
The problem is I have to support both formats in my application. Converting to other formats is no alternative. I'm on Windows 7, Python 2.7.2 and PIL 1.1.7.
I uploaded both images: EPS and SVG.
As of today, that is July 2017, reading and converting SVG files can be easily accomplished by importing cairosvg that provides the svg2png function.
Furthermore the svglib development is on again, thus by importing svglib and reportlab, the conversion from svg to png should be easy as well. a matter of 2 calls.
There are alternatives to PIL, but alternatives to PIL are not what you want - There is no
library I know of that would transparently open a vector based drawing and treat it just as any other image, short of opening a web browser and grabbing its render.
For dealing with SVG, there is a recipe using Cairo - which also can handle a lot of other formats, if a bit more difficult to deal with than the PIL API - I think Cairo can also handle EPS - so, you can probably develop your app with pycairo - or pycairo + PIL in the worst case.
The recipe for rendering SVG's is in the answer to: Convert SVG to PNG in Python
(note that you don't have to "convert the file to PNG" - the recipe shows how you render to a cairo surface, which can be displayed, saved to a file, and so on)
Yet, Pillow supports EMF (Enhanced Windows Metafile) which is still vector graphics. I stumbled on this thread as I was searching for convenient mean to convert SVG to EMF anyway.
Your best bet is to use Inkscape to create EMF from SVG:
inkscape --file image.svg --export-emf image.emf
PIL doesn't support svg, but you could try svglib which, unfortunately, does not seem to be under active development:
https://pypi.python.org/pypi/svglib/
https://github.com/deeplook/svglib
While I believe the top answer is better, one is able to leverage Inkscape to render SVG to PNG files.
render_image_command = "inkscape --export-background-opacity=0 --export-width={} --export-type=png --export-filename {} {}"
render_image_command = render_image_command.format(
image_width_in_pixels,
path_to_png_image_to_write,
path_to_svg_image_to_read
)
Related
Can anyone help me? I'm trying to copy all the metadata from one 3D tiff image to another in python. This is very easy to do with a perl based program:
exiftool -tagsfromfile <source-file> <target-file>
But that is not an easy install to use as a dependency in my python pipeline. There are similar Py libraries that easily to read the metadata tags of a tif image:
import exifread
with open("img_w_metadata.tiff", 'rb') as f:
tags = exifread.process_file(f)
or:
import piexif
exif_data = piexif.load("img_w_metadata.tiff")
But altering that data/inserting new one is very difficult. Exifread has no documentation about it and piexif seems to only work with jpg files, giving error if you provide tif:
# Open TIFF file for writing # THIS ERASES THE IMAGE CONTENTS
with open("img_no_metadata", "wb") as f:
exif_bytes = piexif.dump(exif_data)
f.write(exif_bytes)
Error:
Traceback (most recent call last):
piexif.insert(exif_bytes, img_new) File "C:\Users\......\Python39\site-packages\piexif\_insert.py",line 39, in insert
raise InvalidImageDataError piexif._exceptions.InvalidImageDataError
The Pillow library works well with metadata but does not work with 3D images! opencv works well with 3D images but not with metadata, the Tifffile library is also erasing the second image content, hence I'm trying Exif parsers
Cheers,
Ricardo
I use uvccapture to take pictures and want to process them with the help of python and the python imaging library (PIL).
The problem is that PIL can not open those images. It throws following error message.
Traceback (most recent call last):
File "process.py", line 6, in <module>
im = Image.open(infile)
File "/usr/lib/python2.7/dist-packages/PIL/Image.py", line 1980, in open
raise IOError("cannot identify image file")
IOError: cannot identify image file
My python code looks like this:
import Image
infile = "snap.jpg"
im = Image.open(infile)
I tried to save the images in different formats before processing them. But this does not help. Also changing file permissions and owners does not help.
The only thing that helps is to open the images, for example with jpegoptim, and overwriting the old image with the optimized one. After this process, PIL can deal with these images.
What is the problem here? Are the files generated by uvccapture corrupt?
//EDIT: I also found out, that it is not possible to open the images, generated with uvccapture, with scipy. Running the command
im = scipy.misc.imread("snap.jpg")
produces the same error.
IOError: cannot identify image file
I only found a workaround to this problem. I processed the captured pic with jpegoptim and afterwords PIL could deal with the optimized image.
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])
I think this problem is not Zope-related. Nonetheless I'll explain what I'm trying to do:
I'm using a PUT_factory in Zope to upload images to the ZODB per FTP. The uploaded image is saved as a Zope Image inside a newly created container object. This works fine, but I want to resize the image if it exceeds a certain size (width and height). So I'm using the thumbnail function of PIL to resize them i.e. to 200x200. This works fine as long as the uploaded images are relatively small. I didn't check out the exact limit, but 976x1296px is still ok.
With bigger pictures I get:
Module PIL.Image, line 1559, in thumbnail
Module PIL.ImageFile, line 201, in load
IOError: image file is truncated (nn bytes not processed).
I tested a lot of jpegs from my camera. I don't think they are all truncated.
Here is my code:
if img and img.meta_type == 'Image':
pilImg = PIL.Image.open( StringIO(str(img.data)) )
elif imgData:
pilImg = PIL.Image.open( StringIO(imgData) )
pilImg.thumbnail((width, height), PIL.Image.ANTIALIAS)
As I'm using a PUT_factory, I don't have a file object, I'm using either the raw data from the factory or a previously created (Zope) Image object.
I've heard that PIL handles image data differently when a certain size is exceeded, but I don't know how to adjust my code. Or is it related to PIL's lazy loading?
I'm a little late to reply here, but I ran into a similar problem and I wanted to share my solution. First, here's a pretty typical stack trace for this problem:
Traceback (most recent call last):
...
File ..., line 2064, in ...
im.thumbnail(DEFAULT_THUMBNAIL_SIZE, Image.ANTIALIAS)
File "/Library/Python/2.7/site-packages/PIL/Image.py", line 1572, in thumbnail
self.load()
File "/Library/Python/2.7/site-packages/PIL/ImageFile.py", line 220, in load
raise IOError("image file is truncated (%d bytes not processed)" % len(b))
IOError: image file is truncated (57 bytes not processed)
If we look around line 220 (in your case line 201—perhaps you are running a slightly different version), we see that PIL is reading in blocks of the file and that it expects that the blocks are going to be of a certain size. It turns out that you can ask PIL to be tolerant of files that are truncated (missing some file from the block) by changing a setting.
Somewhere before your code block, simply add the following:
from PIL import ImageFile
ImageFile.LOAD_TRUNCATED_IMAGES = True
...and you should be good.
EDIT: It looks like this helps for the version of PIL bundled with Pillow ("pip install pillow"), but may not work for default installations of PIL
Here is what I did:
Edit LOAD_TRUNCATED_IMAGES = False line from /usr/lib/python3/dist-packages/PIL/ImageFile.py:40 to LOAD_TRUNCATED_IMAGES = True.
Editing the file requires root access though.
I encountered this error while running some pytorch which was maybe using the PIL library.
Do this fix only if you encounter this error, without directly using PIL.
Else please do
from PIL import ImageFile
ImageFile.LOAD_TRUNCATED_IMAGES = True
Best thing is that you can:
if img and img.meta_type == 'Image':
pilImg = PIL.Image.open( StringIO(str(img.data)) )
elif imgData:
pilImg = PIL.Image.open( StringIO(imgData) )
try:
pilImg.load()
except IOError:
pass # You can always log it to logger
pilImg.thumbnail((width, height), PIL.Image.ANTIALIAS)
As dumb as it seems - it will work like a miracle. If your image has missing data, it will be filled with gray (check the bottom of your image).
Note: usage of camel case in Python is discouraged and is used only in class names.
This might not be a PIL issue. It might be related to your HTTP Server setting. HTTP servers put a limit on the size of the entity body that will be accepted.
For eg, in Apache FCGI, the option FcgidMaxRequestLen determines the maximum size of file that can be uploaded.
Check that for your server - it might be the one that is limiting the upload size.
I was trapped with the same problem. However, setting ImageFile.LOAD_TRUNCATED_IMAGES = True is not suitable in my case, and I have checked that all my image files were unbroken, but big.
I read the images using cv2, and then converted it to PIL.Image to get round the problem.
img = cv2.imread(imgfile, cv2.IMREAD_GRAYSCALE)
img = Image.fromarray(img)
I had to change the tds version to 7.2 to prevent this from happening. Also works with tds version 8.0, however I had some other issues with 8.0.
When image was partly broken, OSError will be caused.
I use below code for check and save the wrong image list.
try:
img = Image.open(file_path)
img.load()
## do the work with the loaded image
except OSError as error:
print(f"{error} ({file_path})")
with open("./error_file_list.txt", "a") as error_log:
log.write(str(file_path))
I am writing a script that changes the resolution of a floating point 2K (2048x2048) tiff image to 1024x1024.
But I get the following error:
File "C:\Python26\lib\site-packages\PIL\Image.py", line 1916, in open
IOError: cannot identify image file
My Code:
import Image
im = Image.open( inPath )
im = im.resize( (1024, 1024) , Image.ANTIALIAS )
im.save( outPath )
Any Ideas?
Download My Image From This Link
Also I'm using pil 1.1.6. The pil install is x64 same as the python install (2.6.6)
Try one of these two:
open the file in binary mode,
give the full path to the file.
HTH!
EDIT after testing the OP's image:
It definitively seems like is the image having some problem. I'm on GNU/Linux and couldn't find a single program being able to handle it. Among the most informative about what the problem is have been GIMP:
and ImageMagik:
display: roadnew_disp27-dm_u0_v0_hr.tif: invalid TIFF directory; tags are not sorted in ascending order. `TIFFReadDirectory' # warning/tiff.c/TIFFWarnings/703.
display: roadnew_disp27-dm_u0_v0_hr.tif: unknown field with tag 18 (0x12) encountered. `TIFFReadDirectory' # warning/tiff.c/TIFFWarnings/703.
I did not try it myself, but googling for "python tiff" returned the pylibtiff library, which - being specifically designed for TIFF files, it might perhaps offer some more power in processing this particular ones...
HTH!