如何使用标准Python类(不使用外部库)获取图像大小?

ero*_*ros 65 python image python-2.5

我使用的是Python 2.5.使用Python的标准类,我想确定文件的图像大小.

我听说过PIL(Python图像库),但需要安装才能工作.

如何在不使用任何外部库的情况下获取图像的大小,只使用Python 2.5自己的模块?

注意我想支持常见的图像格式,特别是JPG和PNG.

Fre*_*tic 86

这是一个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
Run Code Online (Sandbox Code Playgroud)


tjb*_*tjb 62

Kurts的答案需要稍加修改才能适合我.

首先,在ubuntu上: sudo apt-get install python-imaging

然后:

from PIL import Image
im=Image.open(filepath)
im.size # (width,height) tuple
Run Code Online (Sandbox Code Playgroud)

查看手册了解更多信息.

  • 不回答问题 - "(不使用外部库)?" 在标题中指定,然后问题澄清"我听说过PIL(Python图像库),但它需要安装库." (16认同)
  • @RossAllan:当然,但是这个问题在Google上对于"Python Image dimensions"的变体来说是第一个问题,所以+1来自我,因为它不需要重新发明轮子所需的答案:) (12认同)

Kur*_*Kee 19

虽然可以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
Run Code Online (Sandbox Code Playgroud)

至于自己编写代码,我不知道Python标准库中的一个模块可以做你想做的事情.您必须以open()二进制模式处理图像并自行开始解码.您可以在以下位置阅读有关格式:

  • 每个tjb的答案都需要`Image.open`而不仅仅是`Image`. (3认同)
  • +1文件格式文档,但我的方向是不使用外部库只是为了获取png和jpg图像文件的图像大小. (2认同)

小智 18

这是一种获取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)
Run Code Online (Sandbox Code Playgroud)

当你运行它时,它将返回:

True
(x, y)
Run Code Online (Sandbox Code Playgroud)

另一个例子包括处理JPEG:http: //markasread.net/post/17551554979/get-image-size-info-using-pure-python-code

  • 为了解决这个问题,可以重构```get_image_info()```将文件名作为参数(而不是二进制数据),然后只需执行```f.read(25)```仅读取标题信息. (2认同)

jen*_*sph 5

如果您碰巧安装了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(',') ]
Run Code Online (Sandbox Code Playgroud)

  • 这是一个好主意,但不需要调用正则表达式机制或列表理解: `width, height = list( map( int, dim.decode('utf-8').strip('"').split(' ,')))` (2认同)

小智 5

关于弗雷德神奇的回答

并非所有JPEG标记之间都是C0- 标记;我排除了DHT(),DNL()和DAC()。请注意,我还没有研究是否甚至可以分析比其他任何帧,并以这种方式。但是,其他选项似乎很少见(我个人除了和以外都没有遇到过)。CFSOFC4C8CCC0C2C0C2

无论哪种方式,这解决了问题,在注释中提到的MalandyBangles.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
Run Code Online (Sandbox Code Playgroud)

注意:由于我尚未被允许,因此创建了完整的答案而不是评论。