m33n
m33n

Reputation: 1751

Read image from URL and keep it in memory

I am using Python and requests library. I just want to download an image to a numpy array for example and there are multiple questions where you can find different combinations (using opencv, PIL, requests, urllib...)

None of them work for my case. I basically receive this error when I try to download the image:

cannot identify image file <_io.BytesIO object at 0x7f6a9734da98>

A simple example of my code can be:

import requests
from PIL import Image

response = requests.get(url, stream=True)
response.raw.decode_content = True
image = Image.open(response.raw)
image.show()

The main this that is driving me crazy is that, if I download the image to a file (using urllib), the whole process runs without any problem!

import urllib
urllib.request.urlretrieve(garment.url, os.path.join(download_folder, garment.get_path()))

What can I be doing wrong?

EDIT:

My mistake was finally related with URL formation and not with requests or PIL library. My previous code example should work perfectly if the URL is correct.

Upvotes: 3

Views: 4304

Answers (1)

ndpu
ndpu

Reputation: 22561

I think you are using data from requests.raw object somehow before save them in Image but requests response raw object is not seekable, you can read from it only once:

>>> response.raw.seekable()
False

First open is ok:

>>> response.raw.tell()
0
>>> image = Image.open(response.raw)

Second open throws error (stream position is on the end of file already):

>>> response.raw.tell()
695  # this file length https://docs.python.org/3/_static/py.png

>>> image = Image.open(response.raw)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/usr/lib/python3/dist-packages/PIL/Image.py", line 2295, in open
    % (filename if filename else fp))
OSError: cannot identify image file <_io.BytesIO object at 0x7f11850074c0>

You should save data from requests response in file-like object (or file of course) if you want to use them several times:

import io
image_data = io.BytesIO(response.raw.read())

Now you can read image stream and rewind it as many times as needed:

>>> image_data.seekable()
True

image = Image.open(image_data)
image1 = Image.open(image_data)

Upvotes: 5

Related Questions