Как получить размер изображения с использованием стандартного класса Python (без использования внешней библиотеки)?
Я использую Python 2.5. И используя стандартные классы из Python, я хочу определить размер изображения файла.
Я слышал PIL (Библиотека изображений Python), но для этого требуется установка.
Как я могу получить размер изображения без использования какой-либо внешней библиотеки, просто используя собственные модули Python 2.5?
Примечание. Я хочу поддерживать общие форматы изображений, особенно JPG и PNG.
Ответы
Ответ 1
Здесь находится python 3 script, который возвращает кортеж, содержащий высоту и ширину изображения для .png,.gif и .jpeg без использования каких-либо внешних библиотек (то есть то, что упомянуто выше Kurt McKee). Должно быть относительно легко перенести его на Python 2.
import struct
import imghdr
def get_image_size(fname):
'''Determine the image type of fhandle and return its size.
from draco'''
with open(fname, 'rb') as fhandle:
head = fhandle.read(24)
if len(head) != 24:
return
if imghdr.what(fname) == 'png':
check = struct.unpack('>i', head[4:8])[0]
if check != 0x0d0a1a0a:
return
width, height = struct.unpack('>ii', head[16:24])
elif imghdr.what(fname) == 'gif':
width, height = struct.unpack('<HH', head[6:10])
elif imghdr.what(fname) == 'jpeg':
try:
fhandle.seek(0) # Read 0xff next
size = 2
ftype = 0
while not 0xc0 <= ftype <= 0xcf:
fhandle.seek(size, 1)
byte = fhandle.read(1)
while ord(byte) == 0xff:
byte = fhandle.read(1)
ftype = ord(byte)
size = struct.unpack('>H', fhandle.read(2))[0] - 2
# We are at a SOFn block
fhandle.seek(1, 1) # Skip `precision' byte.
height, width = struct.unpack('>HH', fhandle.read(4))
except Exception: #IGNORE:W0703
return
else:
return
return width, height
Ответ 2
Ответ Kurts должен быть слегка изменен, чтобы работать для меня.
Сначала, на ubuntu: sudo apt-get install python-imaging
Тогда:
from PIL import Image
im=Image.open(filepath)
im.size # (width,height) tuple
Подробнее см. справочник.
Ответ 3
В то время как можно вызвать open(filename, 'rb')
и проверить заголовки двоичных образов для измерений, представляется гораздо более полезным установить PIL и тратить время на создание отличного нового программного обеспечения! Вы получаете большую поддержку формата файла и надежность, получаемую от широкого использования. Из документации PIL, похоже, что код, который вам нужно будет выполнить, будет:
from PIL import Image
im = Image.open('filename.png')
print 'width: %d - height: %d' % im.size # returns (width, height) tuple
Что касается написания кода самостоятельно, я не знаю о модуле в стандартной библиотеке Python, который будет делать то, что вы хотите. Вы должны будете open()
изображение в двоичном режиме и начать его декодирование самостоятельно. Вы можете прочитать о форматах по адресу:
Ответ 4
Здесь можно получить размеры файла png без необходимости использования стороннего модуля. Из http://coreygoldberg.blogspot.com/2013/01/python-verify-png-file-and-get-image.html
import struct
def get_image_info(data):
if is_png(data):
w, h = struct.unpack('>LL', data[16:24])
width = int(w)
height = int(h)
else:
raise Exception('not a png image')
return width, height
def is_png(data):
return (data[:8] == '\211PNG\r\n\032\n'and (data[12:16] == 'IHDR'))
if __name__ == '__main__':
with open('foo.png', 'rb') as f:
data = f.read()
print is_png(data)
print get_image_info(data)
Когда вы запустите это, он вернется:
True
(x, y)
И еще один пример, который включает в себя обработку JPEG файлов:
http://markasread.net/post/17551554979/get-image-size-info-using-pure-python-code
Ответ 5
Если у вас установлен ImageMagick, вы можете использовать " идентификацию ". Например, вы можете назвать это так:
path = "//folder/image.jpg"
dim = subprocess.Popen(["identify","-format","\"%w,%h\"",path], stdout=subprocess.PIPE).communicate()[0]
(width, height) = [ int(x) for x in re.sub('[\t\r\n"]', '', dim).split(',') ]
Ответ 6
Относительно Фред Фантастический ответ:
Не каждый маркер JPEG между C0
- CF
является маркером SOF
; Я исключил DHT (C4
), DNL (C8
) и ЦАП (CC
). Обратите внимание, что я не изучал, возможно ли даже разобрать любые кадры, кроме C0
и C2
таким образом. Тем не менее, другие, кажется, довольно редки (я лично не встречал других, кроме C0
и C2
).
В любом случае, это решает проблему, упомянутую в комментариях Маланди с помощью Bangles.jpg
(DHT ошибочно анализируется как SOF).
Другая проблема, упомянутая в 1431588037-WgsI3vK.jpg
, связана с тем, что imghdr
может обнаруживать заголовки APP0 (EXIF) и APP1 (JFIF).
Это можно устранить, добавив более слабый тест в imghdr (например, просто FFD8
или, возможно, FFD8FF
?)) или что-то гораздо более сложное (возможно, даже проверка данных). С более сложным подходом я обнаружил проблемы только с: APP14 (FFEE
) (Adobe); первый маркер - DQT (FFDB
); и APP2 и проблемы со встроенными ICC_PROFILEs.
Пересмотренный код ниже также слегка изменил вызов imghdr.what()
:
import struct
import imghdr
def test_jpeg(h, f):
# SOI APP2 + ICC_PROFILE
if h[0:4] == '\xff\xd8\xff\xe2' and h[6:17] == b'ICC_PROFILE':
print "A"
return 'jpeg'
# SOI APP14 + Adobe
if h[0:4] == '\xff\xd8\xff\xee' and h[6:11] == b'Adobe':
return 'jpeg'
# SOI DQT
if h[0:4] == '\xff\xd8\xff\xdb':
return 'jpeg'
imghdr.tests.append(test_jpeg)
def get_image_size(fname):
'''Determine the image type of fhandle and return its size.
from draco'''
with open(fname, 'rb') as fhandle:
head = fhandle.read(24)
if len(head) != 24:
return
what = imghdr.what(None, head)
if what == 'png':
check = struct.unpack('>i', head[4:8])[0]
if check != 0x0d0a1a0a:
return
width, height = struct.unpack('>ii', head[16:24])
elif what == 'gif':
width, height = struct.unpack('<HH', head[6:10])
elif what == 'jpeg':
try:
fhandle.seek(0) # Read 0xff next
size = 2
ftype = 0
while not 0xc0 <= ftype <= 0xcf or ftype in (0xc4, 0xc8, 0xcc):
fhandle.seek(size, 1)
byte = fhandle.read(1)
while ord(byte) == 0xff:
byte = fhandle.read(1)
ftype = ord(byte)
size = struct.unpack('>H', fhandle.read(2))[0] - 2
# We are at a SOFn block
fhandle.seek(1, 1) # Skip `precision' byte.
height, width = struct.unpack('>HH', fhandle.read(4))
except Exception: #IGNORE:W0703
return
else:
return
return width, height
Примечание. Создан полный ответ вместо комментария, поскольку мне еще не разрешено.
Ответ 7
Этот код выполняет две вещи:
Хорошо, когда в googling я больше интересовался более поздним.
Задача состояла в том, чтобы вырезать файл jpg из потока данных. Поскольку я не нашел способа использовать образ Pythons ', чтобы получить EOF, поэтому jpg-File я составил это.
Интересные вещи/изменения/примечания в этом примере:
-
расширение обычного класса файлов Python с помощью метода uInt16
делая исходный код более читабельным и поддерживаемым.
Размещаясь с помощью struct.unpack(), вы быстро заставляете код выглядеть уродливым.
-
Заменено чтение над "интересами" областей/фрагментов с помощью поиска
-
Если вы просто хотите получить размеры
вы можете удалить строку:
hasChunk = ord(byte) not in range( 0xD0, 0xDA) + [0x00]
- > , так как это приобретает значение только при чтении фрагмента данных изображения
и комментарий в
#break
чтобы остановить чтение, как только будет обнаружено измерение.
... но улыбаюсь, что я говорю - ты Кодер;)
import struct
import io,os
class myFile(file):
def byte( self ):
return file.read( self, 1);
def uInt16( self ):
tmp = file.read( self, 2)
return struct.unpack( ">H", tmp )[0];
jpeg = myFile('grafx_ui.s00_\\08521678_Unknown.jpg', 'rb')
try:
height = -1
width = -1
EOI = -1
type_check = jpeg.read(2)
if type_check != b'\xff\xd8':
print("Not a JPG")
else:
byte = jpeg.byte()
while byte != b"":
while byte != b'\xff': byte = jpeg.byte()
while byte == b'\xff': byte = jpeg.byte()
# FF D8 SOI Start of Image
# FF D0..7 RST DRI Define Restart Interval inside CompressedData
# FF 00 Masked FF inside CompressedData
# FF D9 EOI End of Image
# http://en.wikipedia.org/wiki/JPEG#Syntax_and_structure
hasChunk = ord(byte) not in range( 0xD0, 0xDA) + [0x00]
if hasChunk:
ChunkSize = jpeg.uInt16() - 2
ChunkOffset = jpeg.tell()
Next_ChunkOffset = ChunkOffset + ChunkSize
# Find bytes \xFF \xC0..C3 That marks the Start of Frame
if (byte >= b'\xC0' and byte <= b'\xC3'):
# Found SOF1..3 data chunk - Read it and quit
jpeg.seek(1, os.SEEK_CUR)
h = jpeg.uInt16()
w = jpeg.uInt16()
#break
elif (byte == b'\xD9'):
# Found End of Image
EOI = jpeg.tell()
break
else:
# Seek to next data chunk
print "Pos: %.4x %x" % (jpeg.tell(), ChunkSize)
if hasChunk:
jpeg.seek(Next_ChunkOffset)
byte = jpeg.byte()
width = int(w)
height = int(h)
print("Width: %s, Height: %s JpgFileDataSize: %x" % (width, height, EOI))
finally:
jpeg.close()
Ответ 8
Нашел приятное решение в другом сообщении Stackoverflow (используя только стандартные библиотеки +, работающие с jpg): ответ JohnTESlade
И еще одно решение (быстрый способ) для тех, кто может позволить запустить команду файл "в python, запустите:
import os
info = os.popen("file foo.jpg").read()
print info
Выход
foo.jpg: JPEG image data...density 28x28, segment length 16, baseline, precision 8, 352x198, frames 3
Все, что вам нужно сделать, это форматирование вывода для захвата размеров. 352x198 в моем случае.
Ответ 9
Это зависит от вывода файла, который, я не уверен, стандартизирован во всех системах. Некоторые JPEG не сообщают размер изображения
import subprocess, re
image_size = list(map(int, re.findall('(\d+)x(\d+)', subprocess.getoutput("file" + filename))[-1]))
Ответ 10
Поскольку изображение хранится в массиве, просто используйте
height = len(img)
width = len(img[0])
Ответ 11
Наткнулся на этот, но вы можете получить его, используя следующее, пока вы импортируете numpy.
import numpy as np
[y, x] = np.shape(img[:,:,0])
Это работает, потому что вы игнорируете все, кроме одного цвета, а затем изображение просто 2D, поэтому форма говорит вам, как это делается. Еще новичок в Python, но выглядит как простой способ сделать это.