How to open a simple image using streams in Pillow-Python - python

from PIL import Image
image = Image.open("image.jpg")
file_path = io.BytesIO();
image.save(file_path,'JPEG');
image2 = Image.open(file_path.getvalue());
I get this error TypeError: embedded NUL character on the last statement Image.open on running the program
What is the correct way to open a file from streams?

http://effbot.org/imagingbook/introduction.htm#more-on-reading-images
from PIL import Image
import StringIO
buffer = StringIO.StringIO()
buffer.write(open('image.jpeg', 'rb').read())
buffer.seek(0)
image = Image.open(buffer)
print image
# <PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=800x600 at 0x7FE2EEE2B098>
# if we try open again
image = Image.open(buffer)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python2.7/dist-packages/PIL/Image.py", line 2028, in open
raise IOError("cannot identify image file")
IOError: cannot identify image file
Make sure you call buff.seek(0) before reading any StringIO objects. Otherwise you'll be reading from the end of the buffer, which will look like an empty file and is likely causing the error you're seeing.

Using BytesIO is much more simple, it took me a while to figure out. This allows you to read and write to zip files for example.
from PIL import Image
from io import BytesIO
# bytes of a simple 2x2 gif file
gif_bytes = b'\x47\x49\x46\x38\x39\x61\x02\x00\x02\x00\x80\x00\x00\x00\xFF\xFF\xFF\x21\xF9\x04\x00\x00\x00\x00\x00\x2C\x00\x00\x00\x00\x02\x00\x02\x00\x00\x02\x03\x44\x02\x05\x00\x3B'
gif_bytes_io = BytesIO() # or io.BytesIO()
# store the gif bytes to the IO and open as image
gif_bytes_io.write(gif_bytes)
image = Image.open(gif_bytes_io)
# optional proof of concept:
# image.show()
# save as png through a stream
png_bytes_io = BytesIO() # or io.BytesIO()
image.save(png_bytes_io, format='PNG')
print(png_bytes_io.getvalue()) # outputs the byte stream of the png

Related

Error loading base64 image: PIL.UnidentifiedImageError: cannot identify image file <_io.BytesIO

I have a string base64 image that need to convert so then I can read it as image to analyze with pytesseract:
import base64
import io
from PIL import Image
import pytesseract
import sys
base64_string = "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAUDBAQEAwUEBAQFBQUGBwwIBwcHBw8LCwkMEQ8SEhEPERETFh....."
img_data = base64.b64decode(base64_string)
img = Image.open(io.BytesIO(img_data)) # <== ERROR LINE
text = pytesseract.image_to_string(img, config='--psm 6')
print(text)
gives the error:
Traceback (most recent call last):
File "D:\aa\xampp\htdocs\xbanca\aa.py", line 14, in <module>
img = Image.open(io.BytesIO(img_data))
File "D:\python3.10.10\lib\site-packages\PIL\Image.py", line 3283, in open
raise UnidentifiedImageError(msg)
PIL.UnidentifiedImageError: cannot identify image file <_io.BytesIO object at 0x000001A076F673D0>
I tried using numpy and request libraries but all have the same result.. and the base64 example image is working ok in any another converter.
That's a very common misunderstanding.
The string
base64_string = "data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAUDBAQEAwUEBAQFBQUGBwwIBwcHBw8LCwkMEQ8SEhEPERETFh....."
is not a Base64 string, but a DataURL
URLs prefixed with the data: scheme, allow content creators to embed small files inline in documents
that contains a Base64 string.
The Base64 string starts directly after 'base64,'. Therefore you need to cut off the 'data:image/jpeg;base64,' part.
e.g.:
b64 = base64_string.split(",")[1]
after that you can decode the data:
img_data = base64.b64decode(b64)
I modified the code from the question and used the base64 of the following small JPEG image which I base64 encoded on https://www.base64encode.org/:
and got the expected text output:
1 Answer

PIL open image from base64 failed

I'm trying to convert a base64 string to image and get the following error.
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/usr/lib/python2.7/dist-packages/PIL/Image.py", line 2288, in open
% (filename if filename else fp))
IOError: cannot identify image file <cStringIO.StringI object at 0x7fe6d9e88828>
There is no prefix like data:image/png;base64. I get the base64 string from an image and try to convert it back to an image. Here is my code.
# -*- coding: utf-8 -*-
import requests
import base64
from PIL import Image
from cStringIO import StringIO
import zipfile
r = requests.get('https://www.google.com/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png', stream=False)
img = Image.open(StringIO(r.content))
b64str = base64.b64encode(img.tobytes())
data = base64.b64decode(b64str)
newimg = Image.open(StringIO(data))
And I get the error above. Can anyone help? Thanks!
You open .PNG file from the web and get the RAW image, which is RGB values, then encode that into base64 and back, which still gives you RAW RGB values which cannot be read by Image.open() because these are not an image file (jpg, png, etc), but RAW RGB values.
The most reasonable would be:
newImg = data # that's it
Or if you want to make an Image:
newImg = Image.frombytes(img.mode, img.size, data)
and get mode and size from the original image.

Storing image from StringIO to a file creates a distorted image

I stored an image to StringIO from PIL. When I store it to a file from stringIO, it doesn't produce the original image.
Code:
from PIL import Image
from cStringIO import StringIO
buff=StringIO()
img = Image.open("test.jpg")
img.save(buff,format='JPEG')
#img=img.crop((1,1,100,100))
buff.seek(0)
#Produces a distorted image
with open("vv.jpg", "w") as handle:
handle.write(buff.read())
Original Image is below
Output image is below
What is wrong with the above code
You need to use BytesIO and not StringIO.
Also the destination file has to be opened in binary mode using "wb"
Here is code that works (cStringIO is replaced with io)
from PIL import Image
from io import BytesIO
buff=BytesIO()
img = Image.open('test.jpg')
img.save(buff,format='JPEG')
#img=img.crop((1,1,100,100))
buff.seek(0)
#Produces a distorted image
with open('vv.jpg', "wb") as handle:
handle.write(buff.read())

PIL: can't save the jpg pasted with a png

I'm trying to paste a png on a jpg. Here is the code:
#!/usr/bin/env python3
from PIL import Image
from PIL import ImageDraw
im = Image.open("existing.jpg")
logo = Image.open("python-32.png")
back = Image.new('RGBA', im.size)
back.paste(im)
poly = Image.new('RGBA', (512,512))
pdraw = ImageDraw.Draw(poly)
pdraw.polygon([(128,128),(384,384),(128,384),(384,128)],
fill=(255,255,255,127),outline=(255,255,255,255))
back.paste(poly, (0,0), mask=poly)
back.paste(logo, (im.size[0]-logo.size[0], im.size[1]-logo.size[1]), mask=logo)
back.show()
When I execute the code above, I can see that a PNG image is shown with a random name like tmpc8rb455z.PNG.
I also try to save it with the format jpg but failed. Meaning that when I add back.save('res.jpg', 'JPEG') and execute it, I get such an error:
Traceback (most recent call last):
File "test.py", line 32, in <module>
back.save('res.jpg', 'JPEG')
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/PIL/Image.py", line 1893, in save
save_handler(self, fp, filename)
File "/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/PIL/JpegImagePlugin.py", line 604, in _save
raise IOError("cannot write mode %s as JPEG" % im.mode)
OSError: cannot write mode RGBA as JPEG
Then I try to save it as PNG:
back.save('res.png')
It works but the size of res.png is 5 times larger than existing.jpg. I can not accept such a huge image.
You're attempting to save an RGBA image in the JPEG format, which does not support transparency (A in RGBA stands for Alpha channel).
It works when you save it as a PNG, because that format supports transparency, but the file size tends to be larger because PNG doesn't compress image data as much as JPEG.
If you want to save PIL images as JPEG, you will need to first convert it to RGB, if transparency isn't important to you. This can be done as follows:
im = im.convert("RGB")

How to read image from StringIO into PIL in python

How to read image from StringIO into PIL in python? I will have a stringIO object. How to I read from it with a image in it? I cant event have ot read a image from a file. Wow!
from StringIO import StringIO
from PIL import Image
image_file = StringIO(open("test.gif",'rb').readlines())
im = Image.open(image_file)
print im.format, "%dx%d" % im.size, im.mode
Traceback (most recent call last):
File "/home/ubuntu/workspace/receipt/imap_poller.py", line 22, in <module>
im = Image.open(image_file)
File "/usr/local/lib/python2.7/dist-packages/Pillow-2.3.1-py2.7-linux-x86_64.egg/PIL/Image.py", line 2028, in open
raise IOError("cannot identify image file")
IOError: cannot identify image file
Don't use readlines(), it returns a list of strings which is not what you want. To retrieve the bytes from the file, use read() function instead.
Your example worked out of the box with read() and a JPG file on my PC:
# Python 2.x
>>>from StringIO import StringIO
# Python 3.x
>>>from io import StringIO
>>>from PIL import Image
>>>image_file = StringIO(open("test.jpg",'rb').read())
>>>im = Image.open(image_file)
>>>print im.size, im.mode
(2121, 3508) RGB

Categories

Resources