Reputation: 20267
I would like to find the dimensions of an image on the internet. I tried using
from PIL import Image
import urllib2 as urllib
fd = urllib.urlopen("http://a/b/c")
im = Image.open(fd)
im.size
as suggested in this answer, but I get the error message
addinfourl instance has no attribute 'seek'
I checked and objects returned by urllib2.urlopen(url)
do not seem to have a seek method according to dir
.
So, what do I have to do to be able to load an image from the Internet into PIL?
Upvotes: 28
Views: 43010
Reputation: 17
Using requests library and and get output as Bytes
import requests
import io
response = requests.get("https://i.imgur.com/ExdKOOz.png")
image_bytes = io.BytesIO(response.content)
Upvotes: 1
Reputation: 25
This answer is 4 years ago, but it's still on top in Google.In Python3, we have simple solution.
from urllib.request import urlopen
img =Image.open(urlopen('http://dl.iplaypython.com/images/banner336x280.jpg'))
new_img =img.resize((300,500),Image.ANTIALIAS)
new_img.save('url.jpg','jpeg')
Upvotes: 0
Reputation: 15545
This pull-request adds support for stream-handling native to Pillow (the friendly PIL fork) and should be available from version 2.8.0. This allows the simpler opening remote files with urllib:
from PIL import Image
import urllib2
Image.open(urllib2.urlopen(url))
...or using requests:
from PIL import Image
import requests
Image.open(requests.get(url, stream=True).raw)
As mentioned by mjpieters on the PR requests does not automatically decode gzip
responses, so if you're downloading images that have been further compressed for whatever reason you must set decode_content=True
on the response object before accessing .raw
.
response = requests.get(url, stream=True)
response.raw.decode_content = True
image = Image.open(response.raw)
Upvotes: 10
Reputation: 3221
Using Python requests
:
from PIL import Image
from StringIO import StringIO
import requests
r = requests.get("http://a/b/c")
im = Image.open(StringIO(r.content))
im.size
Upvotes: 14
Reputation: 8837
You might consider using io.BytesIO
for forward compatibility.
The StringIO and cStringIO modules do not exist in Python 3.
from PIL import Image
import urllib2 as urllib
import io
fd = urllib.urlopen("http://a/b/c")
image_file = io.BytesIO(fd.read())
im = Image.open(image_file)
Upvotes: 45
Reputation: 92569
Using your same example, just use StringIO to wrap the buffer into a proper file-like object:
from PIL import Image
import urllib2 as urllib
from StringIO import StringIO
fd = urllib.urlopen("http://a/b/c")
im = Image.open(StringIO(fd.read()))
im.size
Upvotes: 8
Reputation: 10541
The urllib
documentation mentions that an object returned by urlopen
doesn't support seek
operation.
This module provides a high-level interface for fetching data across the World Wide Web. In particular, the urlopen() function is similar to the built-in function open(), but accepts Universal Resource Locators (URLs) instead of filenames. Some restrictions apply — it can only open URLs for reading, and no seek operations are available.
However, the PIL.open
function explicitly requires it.
open
Image.open(infile) => image
Image.open(infile, mode) => image
Opens and identifies the given image file. This is a lazy operation; the actual image data is not read from the file until you try to process the data (call the load method to force loading). If the mode argument is given, it must be "r".
You can use either a string (representing the filename) or a file object. In the latter case, the file object must implement read, seek, and tell methods, and be opened in binary mode.
Try using cStringIO
module that converts a string into a file-like object.
from PIL import Image
import urllib2 as urllib
import cStringIO
fd = urllib.urlopen("http://a/b/c")
image_file = cStringIO.StringIO(fd.read())
im = Image.open(image_file)
im.size
Upvotes: 2