murgatroid99
murgatroid99

Reputation: 20267

How do I open an image from the internet in PIL?

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

Answers (7)

Shanmugavel
Shanmugavel

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

mfitzp
mfitzp

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

Matt Parrilla
Matt Parrilla

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

AI Generated Response
AI Generated Response

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

jdi
jdi

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

Maksim Skurydzin
Maksim Skurydzin

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

Related Questions