I'm trying to save a jpg image from a Flask app form. The following code works fine:
blob = request.files[canvas_key]
blob.stream.seek(0)
data = blob.stream.read()
string_io = cStringIO.StringIO(data)
string_io has type <cStringIO.StringI object at 0x10bf2bf10>.
Yet when I try: Image.open(string_io), I get this error: IOError: cannot identify image file.
Using stream.seek(0) seems to solve this problem for other people, but in my case it hasn't.
Thanks to #Mark, I changed the image type I capture from WebP to PNG.
Related
import requests
from PIL import Image
url_shoes_for_choice = [
"https://content.adidas.co.in/static/Product-CM7531/Unisex_OUTDOOR_SANDALS_CM7531_1.jpg",
"https://cdn.shopify.com/s/files/1/0080/1374/2161/products/product-image-897958210_640x.jpg?v=1571713841",
"https://cdn.chamaripashoes.com/media/catalog/product/cache/9/image/9df78eab33525d08d6e5fb8d27136e95/1/_/1_8_3.jpg",
"https://ae01.alicdn.com/kf/HTB1EyKjaI_vK1Rjy0Foq6xIxVXah.jpg_q50.jpg",
"https://www.converse.com/dw/image/v2/BCZC_PRD/on/demandware.static/-/Sites-cnv-master-catalog/default/dwb9eb8c43/images/a_107/167708C_A_107X1.jpg"
]
def img():
for url in url_shoes_for_choice:
image = requests.get(url, stream=True).raw
out = Image.open(image)
out.save('image/image.jpg', 'jpg')
if __name__=="__main__":
img()
Error:
OSError: cannot identify image file <_io.BytesIO object at 0x7fa185c52d58>
The problem is that one of the images is making issues with the byte data returned by the requests.get(url, stream=True).raw, I'm not sure but I guess the data of the 3rd image is invalid byte data so instead of getting the raw data we can just fetch the content and then by using BytesIO we can fix the byte data.
I fixed one more thing from your original code, I added numbering to your images so each can be saved with different name.
from io import BytesIO
def img():
for count, url in enumerate(url_shoes_for_choice):
image = requests.get(url, stream=True)
with BytesIO(image.content) as f:
with Image.open(f) as out:
# out.show() # See the images
out.save('image/image{}.jpg'.format(count))
(Though this works fine but I'm not sure what was the main issue. If anyone knows exactly what is the issue please comment and explain.)
I opened the first link in my browser and saved the image. It's actually a webp file.
$ file Unisex_OUTDOOR_SANDALS_CM7531_1.webp
Unisex_OUTDOOR_SANDALS_CM7531_1.webp: RIFF (little-endian) data, Web/P image, VP8 encoding, 500x500, Scaling: [none]x[none], YUV color, decoders should clamp
You explicitly tell the image library that it should expect a jpg. When you remove that parameter and let it figure it out on its own using out.save('image/image.jpg') the first image successfully downloads for me.
The first two images work this way if you make sure to save each under a different name:
def img():
i = 0
for url in url_shoes_for_choice:
i+=1
image = requests.get(url, stream=True).raw
out = Image.open(image)
out.save('image{}.jpg'.format(i))
the third is a valid jpeg file, as well as the fourth, but using the JFIF standard 1.01 which I hear the first time of. I'm pretty sure you'll have to figure out support for different such filetypes.
It is worth noting that if I download the images in chrome and open those with python, nothing fails. So chrome might be adding information to the file.
The documentation of PIL/pillow explains here that you need a new enough version for animated images, but that is not your problem.
Support for animated WebP files will only be enabled if the system
WebP library is v0.5.0 or later. You can check webp animation support
at runtime by calling features.check(“webp_anim”).
I am facing a huge problem when I'm uploading an image (.jpg or .png) via the dcc.upload component: I have to feed the image into a function that accepts either a string or PIL.Image object. In my opinion it would be better to convert it to a PIL.Image (?). So I have to convert the base64 encoded image to a PIL.Image object but I cannot get this to work. I am able to display the uploaded image in dash though. Please help!
I tried the following: (uploaded image is called upload, function for further use called function)
Using upload object itself: OSError: [Errno 63] File name too long: 'data:image/png;base64,iVB...
function(base64.b64decode(upload, 'rb')): assert isinstance(image, str) or isinstance(image, Image.Image)
function(Image.open(base64.b64decode(upload, 'rb'))): ValueError: embedded null byte
function(Image.open(BytesIO(base64.b64decode(upload, 'rb')))): OSError: cannot identify image file <_io.BytesIO object at 0x146225d10>
Using upload = base64.b64decode(upload + '===') didn't help
Using ImageFile.LOAD_TRUNCATED_IMAGES = True didn't help
But the image file can't be corrupted as I can clearly display it in the browser?
And getting a string (or path) out of it is also not a good idea I think as the image will be uploaded from the user?
Thanks!
I'm struggling to properly open a TIFF image from an instance of Python's io.BufferedReader class. I download the image from a GCS path using the below lib, but I can't open seem to open the image with traditional tools.
# returns the <_io.BufferedReader>
file = beam.io.gcp.gcsio.GcsIO().open("<GCS_PATH>", 'r')
from PIL import Image
img = Image.open(file.read()) <---- Fails with "TypeError: embedded NUL character"
img = Image.open(file.raw) <--- Fails when any operations are performed with "IOError(err)"
I am open to other libraries besides PIL.
UPDATE
The following also fails:
img = Image.open(file)
It fails with an IOError, stating tempfile.tif: Cannot read TIFF header.
Make sure you wrap both in a ContextManager so they both get closed properly.
with beam.io.gcp.gcsio.GcsIO().open(file_path, 'r') as file, Image.open(io.BytesIO(file.read())) as multi_page_tiff:
do_stuff()
I am trying to upload an image that has been converted to grayscale, like this:
blob_path = os.path.join(os.path.split(__file__)[0], 'static/img/blob-masks/1.png')
blob = Image.open(blob_path).convert('L')
buffer = StringIO()
blob.save(buffer)
upload_image(buffer.getvalue(),"foo.png")
But it just seem to upload a black square.
If I got to the command line python and run:
col = Image.open("/static/img/blob-masks/5.png")
col.convert('L')
col.save("result_bw.png")
result_bw.png is perfect. What is going wrong?
Is there a reason you can't just upload the greyscale image after you convert it? Like:
image = Image.open('static/img/blob-masks/1.png')
image.convert('L')
image.save("temp/bw.png")
upload_image("temp/bw.png")
# maybe delete the temporary file when you're done
import os
os.remove("temp/bw.png")
I'm not sure how your upload_image() function works, but when I upload using django if I do any manipulations I write a temporary file and then re-import. If I don't manipulate the image at all I can just upload it directly.
How do I take an image and turn that into binary image data?
This is what I have tried:
class get_binary_data(image_url):
#Get the image online online_image = http://www.myimg.com/test.jpg
online_image = requests.get(image_url).content
image_data = BytesIO(online_image)
However this does not seem to give me the binary image data, could someone help explain the process of getting the binary image data?
This is what I'm trying to do:
app = subprocess.Popen("externalApp",
in=subprocess.PIPE,
out=subprocess.PIPE)
app.in.write(image_data)
app.in.close()
which gives me the error:
IOError: [Errno 32] Broken pipe
You do not need to wrap the response data in a BytesIO object just to write it to a pipe. Use the response.content data directly:
class get_binary_data(image_url):
#Get the image online online_image = http://www.myimg.com/test.jpg
return requests.get(image_url).content
I used a BytesIO object in my answer to your previous question only because you wanted to load that data into a PIL Image object. It is a requirement for Image.open() that a file-like object with seek support is provided, and BytesIO does just that.
Here, however, you need a (byte)string, so just use the .contents value.