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

如何使用标准Python类获得图像大小(不使用外部库)?,python,image,python-2.5,Python,Image,Python 2.5,我正在使用Python 2.5。使用Python中的标准类,我想确定文件的图像大小 我听说过PIL(Python映像库),但它需要安装才能工作 在不使用任何外部库的情况下,仅使用Python 2.5自己的模块,如何获得图像的大小 注:我想支持常见的图像格式,特别是JPG和PNG。虽然可以调用open(filename,'rb')并检查二进制图像标题中的维度,但安装PIL并花时间编写优秀的新软件似乎更有用!通过广泛使用,您可以获得更大的文件格式支持和可靠性,完成任务所需的代码可能是: from P

我正在使用Python 2.5。使用Python中的标准类,我想确定文件的图像大小

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

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


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

虽然可以调用
open(filename,'rb')
并检查二进制图像标题中的维度,但安装PIL并花时间编写优秀的新软件似乎更有用!通过广泛使用,您可以获得更大的文件格式支持和可靠性,完成任务所需的代码可能是:

from PIL import Image
im = Image.open('filename.png')
print 'width: %d - height: %d' % im.size # returns (width, height) tuple
至于自己编写代码,我不知道Python标准库中有哪个模块可以满足您的需要。您必须以二进制模式打开图像,然后自己开始解码。您可以在以下位置阅读有关格式的信息:


库尔特人的答案需要稍微修改一下,才能适合我

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

然后:

有关详细信息,请查看。

如果您碰巧安装了,则可以使用“”。例如,您可以这样称呼它:

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(',') ]

下面是一个Python3脚本,它返回一个元组,其中包含.png、.gif和.jpeg的图像高度和宽度,而不使用任何外部库(即上面Kurt McKee提到的)。将其传输到Python2应该相对容易

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
导入结构
导入imghdr
def get_图像大小(fname):
''确定fhandle的图像类型并返回其大小。
来自draco“
以open(fname,'rb')作为fhandle:
头部=手柄读数(24)
如果len(头)!=24:
返回
如果imghdr.what(fname)=‘png’:
check=struct.unpack('>i',head[4:8])[0]
如果检查!=0x0d0a1a0a:
返回
宽度、高度=结构拆包('>ii',头部[16:24])
elif imghdr.what(fname)='gif':
宽度,高度=结构解包('H',F句柄读取(2))[0]-2
#我们在一个小街区
fhandle.seek(1,1)#跳过'precision'字节。
高度、宽度=结构拆包('>HH',fhandle.read(4))
例外情况除外:#忽略:W0703
返回
其他:
返回
返回宽度、高度

该代码确实完成了两件事:

  • 获取图像维度

  • 查找jpg文件的真实EOF

当我在谷歌上搜索时,我对后面的一个更感兴趣。 任务是从数据流中剪切出一个jpg文件。因为我没有找到任何方法来使用Pythons的‘image’来获得so-jpg文件的EOF,所以我编了这个

此示例中有趣的事情/更改/注释:

  • 使用uInt16方法扩展普通Python文件类 使源代码具有更好的可读性和可维护性。 乱搞struct.unpack()很快会让代码看起来很难看

  • 将“无趣”区域/区块的读取替换为seek

  • 如果你只是想得到尺寸 您可以删除该行:

    hasChunk = ord(byte) not in range( 0xD0, 0xDA) + [0x00] 
    
    ->因为这只在读取图像数据块时才重要 并在

    #break
    
    一旦发现尺寸,立即停止读取。 ……但请对我说的话微笑——你是编码员;)

    导入结构
    导入io、os
    类myFile(文件):
    def字节(自身):
    返回file.read(self,1);
    def uInt16(自身):
    tmp=file.read(self,2)
    返回解包结构(“>H”,tmp)[0];
    jpeg=myFile('grafx_ui.s00\\08521678_Unknown.jpg','rb')
    尝试:
    高度=-1
    宽度=-1
    EOI=-1
    键入\u check=jpeg.read(2)
    如果键入_check!=b'\xff\xd8':
    打印(“非JPG”)
    其他:
    byte=jpeg.byte()
    而字节!=b.“:
    而字节!=b'\xff':byte=jpeg.byte()
    而byte==b'\xff':byte=jpeg.byte()
    #FF D8 SOI映像的开始
    #FF D0..7 RST DRI在压缩数据内定义重新启动间隔
    #FF 00蒙面FF内部压缩数据
    #FF D9 EOI图像结束
    # http://en.wikipedia.org/wiki/JPEG#Syntax_and_structure
    hasChunk=ord(字节)不在范围内(0xD0,0xDA)+[0x00]
    如果是hasChunk:
    ChunkSize=jpeg.uInt16()-2
    ChunkOffset=jpeg.tell()
    下一步\u ChunkOffset=ChunkOffset+ChunkSize
    #查找标记帧开始的字节\xFF\xC0..C3
    
    如果(byte>=b'\xC0'和byte,这里有一种无需第三方模块即可获取png文件的维度的方法

    运行此操作时,它将返回:

    True
    (x, y)
    
    另一个例子也包括JPEG的处理:

    偶然发现了这一点,但只要导入numpy,您就可以使用以下方法获得它

    import numpy as np
    
    [y, x] = np.shape(img[:,:,0])
    
    它之所以有效,是因为您忽略了除一种颜色以外的所有颜色,然后图像只是二维的,因此形状可以告诉您它的出价。对于Python来说,这还是一种新的方法,但似乎是一种简单的方法。

    关于:

    并非
    C0
    -
    CF
    之间的每个JPEG标记都是
    SOF
    标记;我排除了DHT(
    C4
    )、DNL(
    C8
    )和DAC(
    CC
    )。请注意,我甚至没有研究过是否可以以这种方式解析除
    C0
    C2
    之外的任何帧。但是,其他帧似乎非常罕见(我个人没有遇到过除
    C0
    C2
    之外的任何帧)

    无论哪种方式,这都解决了Malandy在评论中提到的问题,即
    Bangles.jpg
    (DHT被错误地解析为SOF)

    提到的另一个问题
    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)
    
    import numpy as np
    
    [y, x] = np.shape(img[:,:,0])
    
    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
    
    import subprocess, re
    image_size = list(map(int, re.findall('(\d+)x(\d+)', subprocess.getoutput("file" + filename))[-1]))