Получите размер изображения, не загрузив его в Python

Как я могу получить размеры изображения, не загружая его? Это вообще возможно? У меня есть список URL изображений, и я хочу назначить ему ширину и размер.

Я знаю, что есть способ сделать это локально (Как проверить размеры всех изображений в каталоге, используя python?), Но я не хочу загружать все изображения.

Редактировать:

После ред. предложения, я редактировал код. Я придумал этот код. Не уверен, что погода загружает весь файл или только часть (как я хотел).

Ответы

Ответ 1

Это основано на ответе ed, смешанном с другими вещами, которые я нашел в Интернете. Я столкнулся с тем же вопросом, что и grotos с .read(24). Загрузите getimageinfo.py из здесь и скачайте ReSeekFile.py из здесь.

import urllib2
imgdata = urllib2.urlopen(href)
image_type,width,height = getimageinfo.getImageInfo(imgdata)

Измените getimageinfo как таковой...

import ReseekFile

def getImageInfo(datastream):
    datastream = ReseekFile.ReseekFile(datastream)
    data = str(datastream.read(30))

#Skipping to jpeg

# handle JPEGs
elif (size >= 2) and data.startswith('\377\330'):
    content_type = 'image/jpeg'
    datastream.seek(0)
    datastream.read(2)
    b = datastream.read(1)
    try:
        while (b and ord(b) != 0xDA):
            while (ord(b) != 0xFF): b = datastream.read(1)
            while (ord(b) == 0xFF): b = datastream.read(1)
            if (ord(b) >= 0xC0 and ord(b) <= 0xC3):
                datastream.read(3)
                h, w = struct.unpack(">HH", datastream.read(4))
                break
            else:
                datastream.read(int(struct.unpack(">H", datastream.read(2))[0])-2)
            b = datastream.read(1)
        width = int(w)
        height = int(h)
    except struct.error:
        pass
    except ValueError:
        pass

Ответ 2

Я нашел решение на этом сайте, чтобы хорошо работать:

import urllib
import ImageFile

def getsizes(uri):
    # get file size *and* image size (None if not known)
    file = urllib.urlopen(uri)
    size = file.headers.get("content-length")
    if size: size = int(size)
    p = ImageFile.Parser()
    while 1:
        data = file.read(1024)
        if not data:
            break
        p.feed(data)
        if p.image:
            return size, p.image.size
            break
    file.close()
    return size, None

print getsizes("http://www.pythonware.com/images/small-yoyo.gif")
# (10965, (179, 188))

Ответ 3

Если вы хотите загрузить первые 24 байта каждого файла, то эта функция (упомянутая в ответе johnteslade на вопрос, который вы упомянули) будет определять размеры.

Это, вероятно, наименьшая загрузка, необходимая для работы, которую вы хотите.

import urllib2
start = urllib2.urlopen(image_url).read(24)

Изменить (1):

В случае файлов JPEG это, кажется, нужно больше байтов. Вы можете отредактировать функцию так, чтобы вместо чтения StringIO.StringIO (данные) она вместо этого считывала дескриптор файла из urlopen. Тогда он будет читать ровно столько изображения, сколько ему нужно, чтобы узнать ширину и высоту.

Ответ 4

Это всего лишь Python 3+ адаптация более раннего ответа здесь.

import urllib
from PIL import ImageFile

def getsizes(uri):
    # get file size *and* image size (None if not known)
    file = urllib.request.urlopen(uri)
    size = file.headers.get("content-length")
    if size: 
        size = int(size)
    p = ImageFile.Parser()
    while True:
        data = file.read(1024)
        if not data:
            break
        p.feed(data)
        if p.image:
            return size, p.image.size
            break
    file.close()
    return(size, None)

Ответ 5

Так как getimageinfo.py, упомянутый выше, не работает в Python3. Вместо него используется подушка.

Подушка может быть найдена в pypi или установлена ​​с помощью pip: pip install pillow.

from io import BytesIO
from PIL import Image
import requests
hrefs = ['https://farm4.staticflickr.com/3894/15008518202_b016d7d289_m.jpg','https://farm4.staticflickr.com/3920/15008465772_383e697089_m.jpg','https://farm4.staticflickr.com/3902/14985871946_86abb8c56f_m.jpg']
RANGE = 5000
for href in hrefs:
    req  = requests.get(href,headers={'User-Agent':'Mozilla5.0(Google spider)','Range':'bytes=0-{}'.format(RANGE)})
    im = Image.open(BytesIO(req.content))

    print(im.size)

Ответ 6

Невозможно сделать это напрямую, но для этого есть обходной путь. Если файлы присутствуют на сервере, затем реализуйте конечную точку API, которая принимает имя изображения в качестве аргумента и возвращает размер.

Но если файлы находятся на другом сервере, у вас нет другого пути, кроме как загрузить файлы.

Ответ 7

К сожалению, я не могу комментировать, так что это как ответ:

Используйте запрос get с заголовком

"Range": "bytes=0-30"

А затем просто используйте

http://code.google.com/p/bfg-pages/source/browse/trunk/pages/getimageinfo.py

Если вы используете python-запросы, просто

r = requests.get(image_url, headers={
    "Range": "bytes=0-30"
})
image_info = get_image_info(r.content)

Это исправление ed. отвечать и не имеет каких-либо других зависимостей (например, ReSeekFile.py).

Ответ 8

У меня исправлено "getimageInfo.py", работайте с Python 3.4+, попробуйте, просто отлично!

import io
import struct
import urllib.request as urllib2

def getImageInfo(data):
    data = data
    size = len(data)
    #print(size)
    height = -1
    width = -1
    content_type = ''

    # handle GIFs
    if (size >= 10) and data[:6] in (b'GIF87a', b'GIF89a'):
        # Check to see if content_type is correct
        content_type = 'image/gif'
        w, h = struct.unpack(b"<HH", data[6:10])
        width = int(w)
        height = int(h)

    # See PNG 2. Edition spec (http://www.w3.org/TR/PNG/)
    # Bytes 0-7 are below, 4-byte chunk length, then 'IHDR'
    # and finally the 4-byte width, height
    elif ((size >= 24) and data.startswith(b'\211PNG\r\n\032\n')
          and (data[12:16] == b'IHDR')):
        content_type = 'image/png'
        w, h = struct.unpack(b">LL", data[16:24])
        width = int(w)
        height = int(h)

    # Maybe this is for an older PNG version.
    elif (size >= 16) and data.startswith(b'\211PNG\r\n\032\n'):
        # Check to see if we have the right content type
        content_type = 'image/png'
        w, h = struct.unpack(b">LL", data[8:16])
        width = int(w)
        height = int(h)

    # handle JPEGs
    elif (size >= 2) and data.startswith(b'\377\330'):
        content_type = 'image/jpeg'
        jpeg = io.BytesIO(data)
        jpeg.read(2)
        b = jpeg.read(1)
        try:
            while (b and ord(b) != 0xDA):
                while (ord(b) != 0xFF): b = jpeg.read(1)
                while (ord(b) == 0xFF): b = jpeg.read(1)
                if (ord(b) >= 0xC0 and ord(b) <= 0xC3):
                    jpeg.read(3)
                    h, w = struct.unpack(b">HH", jpeg.read(4))
                    break
                else:
                    jpeg.read(int(struct.unpack(b">H", jpeg.read(2))[0])-2)
                b = jpeg.read(1)
            width = int(w)
            height = int(h)
        except struct.error:
            pass
        except ValueError:
            pass

    return content_type, width, height



#from PIL import Image
#import requests
#hrefs = ['http://farm4.staticflickr.com/3894/15008518202_b016d7d289_m.jpg','https://farm4.staticflickr.com/3920/15008465772_383e697089_m.jpg','https://farm4.staticflickr.com/3902/14985871946_86abb8c56f_m.jpg']
#RANGE = 5000
#for href in hrefs:
    #req  = requests.get(href,headers={'User-Agent':'Mozilla5.0(Google spider)','Range':'bytes=0-{}'.format(RANGE)})
    #im = getImageInfo(req.content)

    #print(im)
req = urllib2.Request("http://vn-sharing.net/forum/images/smilies/onion/ngai.gif", headers={"Range": "5000"})
r = urllib2.urlopen(req)
#f = open("D:\\Pictures\\1.jpg", "rb")
print(getImageInfo(r.read()))
# Output: >> ('image/gif', 50, 50)
#print(getImageInfo(f.read()))

Исходный код: http://code.google.com/p/bfg-pages/source/browse/trunk/pages/getimageinfo.py