如何使用标准的Python类获取图像大小(不使用外部库)?
我正在使用Python 2.5。 而使用Python的标准类,我想确定一个文件的图像大小。
我听说过PIL(Python图像库),但它需要安装才能正常工作。
如何在不使用任何外部库的情况下获取图像大小,仅使用Python 2.5自带的模块?
注意我想支持常见的图像格式,特别是JPG和PNG。
这里是一个python 3脚本,它返回一个包含图像高度和宽度的元组,而不使用任何外部库(即Kurt McKee在上面引用的)中的.png,.gif和.jpeg。 应该相对容易地将其转移到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()
图像并开始解码。 你可以阅读关于格式:
- PNG文件格式的文件
- 有关JPEG文件格式标题的说明
关于弗雷德神奇的答案 :
不是每个C0
– CF
之间的JPEG标记都是SOF
标记; 我排除了DHT( C4
),DNL( C8
)和DAC( CC
)。 请注意,我还没有研究过是否可以用这种方式parsingC0
和C2
以外的任何帧。 然而,其他的似乎是相当罕见的(我个人并没有遇到除了C0
和C2
)。
无论哪种方式,这解决了由Malandy与Bangles.jpg
(DHT错误地parsing为SOF)在评论中提到的问题。
与1431588037-WgsI3vK.jpg
提到的另一个问题是由于imghdr
只能检测APP0(EXIF)和APP1(JFIF)头。
这可以通过向imghdr添加更宽松的testing(例如简单的FFD8
或者FFD8FF
?)或更复杂的(甚至可能是数据validation)来解决。 使用更复杂的方法,我只发现了以下问题:APP14( FFEE
)(Adobe); 第一个标记是DQT( FFDB
); 和APP2以及embedded式ICC_PROFILE问题 。
修改后的代码,也稍微改变了对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
注:创build完整的答案,而不是评论,因为我还没有被允许。
如果您碰巧安装了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(',') ]
该代码确实完成了两件事情:
-
获取图片维度
-
find一个JPG文件的真正的EOF
那么当使用Google时,我对后面的一个更感兴趣。 任务是从数据stream中剪出一个jpg文件。 由于我没有find任何方法来使用Pythons的图像来获得这样的jpg文件的EOF我做了这个。
有趣的事情/变化/笔记在这个样本:
-
使用uInt16方法扩展普通的Python文件类,使得源代码更好的可读性和可维护性。 用struct.unpack()搞砸快速使代码看起来丑陋
-
用“寻找”replace“无趣”区域/块
-
Incase你只是想得到你可能会删除线的尺寸:
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()
在另一个Stackoverflowpost中find了一个很好的解决scheme(只使用标准库+处理jpg): JohnTESlade答案
另一个解决scheme(快速的方法),让那些可以在python中运行' file '命令的人运行:
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
你现在要做的就是格式化输出来捕捉尺寸。 352×198在我的情况。
偶然发现了这个,但是只要你inputnumpy,你可以通过使用下面的代码来得到它。
import numpy as np [y, x] = np.shape(img[:,:,0])
这是因为你忽略了所有的颜色,然后图像只是2D,所以形状告诉你如何出价。 对于Python来说还是一个新东西,但似乎是一个简单的方法来做到这一点。
由于图像存储在一个数组中简单地使用
height = len(img) width = len(img[0])