我正在使用 Python 2.5。并使用 Python 中的标准类,我想确定文件的图像大小。
我听说过 PIL(Python 图像库),但它需要安装才能工作。
我如何在不使用任何外部库的情况下仅使用 Python 2.5 自己的模块来获得图像的大小?
注意我想支持常见的图像格式,尤其是 JPG 和 PNG。
我正在使用 Python 2.5。并使用 Python 中的标准类,我想确定文件的图像大小。
我听说过 PIL(Python 图像库),但它需要安装才能工作。
我如何在不使用任何外部库的情况下仅使用 Python 2.5 自己的模块来获得图像的大小?
注意我想支持常见的图像格式,尤其是 JPG 和 PNG。
这是一个 python 3 脚本,它返回一个元组,其中包含 .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
Kurts 的回答需要稍作修改才能为我工作。
首先,在 ubuntu 上:sudo apt-get install python-imaging
然后:
from PIL import Image
im=Image.open(filepath)
im.size # (width,height) tuple
查看手册了解更多信息。
这是一种无需第三方模块即可获取 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
虽然可以调用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()
二进制模式处理图像并自己开始解码。您可以在以下位置阅读有关格式的信息:
C0
并非-之间的每个 JPEG 标记CF
都是SOF
标记;我排除了 DHT ( C4
)、DNL ( C8
) 和 DAC ( CC
)。请注意,我还没有研究是否有可能以这种方式解析任何C0
帧C2
。然而,其他的似乎相当罕见(我个人没有遇到过除C0
and之外的任何东西C2
)。
无论哪种方式,这都解决了Malandy在评论中提到的问题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
注意:创建了完整的答案而不是评论,因为我还不允许这样做。
如果您碰巧安装了ImageMagick,那么您可以使用“ identify ”。例如,您可以这样称呼它:
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(',') ]
在另一个 Stackoverflow 帖子中找到了一个不错的解决方案(仅使用标准库 + 也处理 jpg):JohnTESlade answer
对于那些负担得起在 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 。
该代码确实完成了两件事:
获取图像尺寸
查找jpg 文件的真实 EOF
好吧,在谷歌搜索时,我对后一个更感兴趣。任务是从数据流中剪切出一个 jpg 文件。由于 II 没有找到任何方法来使用 Python 的“图像”来获取所以 jpg-File 的 EOF,所以我做了这个。
此示例中有趣的事情/更改/注释:
使用方法 uInt16 扩展普通 Python 文件类,使源代码更好地可读和可维护。乱用 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()
这取决于文件的输出,我不确定它是否在所有系统上都是标准化的。一些 JPEG 不报告图像大小
import subprocess, re
image_size = list(map(int, re.findall('(\d+)x(\d+)', subprocess.getoutput("file" + filename))[-1]))
偶然发现了这个,但只要你导入 numpy.
import numpy as np
[y, x] = np.shape(img[:,:,0])
它之所以有效,是因为您忽略了除一种颜色之外的所有颜色,然后图像只是 2D,因此形状告诉您它的出价。对 Python 来说还是有点新,但似乎是一种简单的方法。