2011-11-07 35 views
54

我正在使用Python 2.5。使用Python的标准类,我想确定一个文件的图像大小。如何使用标准Python类获取图像大小(不使用外部库)?

我听说过PIL(Python Image Library),但它需要安装才能正常工作。

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

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

+1

你想学的什么大小格式* *图像的任何建议? –

+1

常见的图像格式(PNG和JPG) – eros

+0

参见[我的回答对一个问题(http://stackoverflow.com/a/34704661/562769),如果你不关心使用外部(但通常使用的)库 –

回答

17

尽管可以调用open(filename, 'rb')并检查二维图像标题的尺寸,但安装PIL并花时间编写出色的新软件似乎更有用!您可以获得更大的文件格式支持以及广泛使用的可靠性。 From the PIL documentation,看来该代码,你需要完成你的任务将是:

from PIL import Image 
im = Image.open('filename.png') 
print 'width: %d - height: %d' % im.size # returns (width, height) tuple 

至于自己编写代码,我不知道在Python标准库的模块会做你想要什么。你将不得不open()图像在二进制模式,并开始解码它自己。你可以在阅读的格式:

+2

+ 1的文件格式文件,但我的方向是不使用外部库只是为了获得图像大小的PNG和JPG图像文件。 – eros

+3

你需要'Image.open'不只是'Image'每tjb的答案。 – Ghopper21

59

需要Kurts回答稍微修改为我工作。

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

然后:

from PIL import Image 
im=Image.open(filepath) 
im.size # (width,height) tuple 

退房的handbook以获得更多信息。

+14

不回答问题 - “(不使用外部库)?”是在标题中指定的,然后问题用“我听说过PIL(Python图像库)”来澄清,但它需要安装库。“ –

+8

@RossAllan:当然可以,但这个问题是#1在谷歌的'Python的图像dimensions'变种,所以+1从我无重塑 - -的轮需要的答案:) –

3

如果您碰巧安装了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(',') ] 
76

这里有一个python脚本3,返回包含.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 
+0

你的代码工作大多喜欢在2.7.3中。我不得不重写它,因为我已经有了一个像对象一样的文件。 – xZise

+0

它似乎与[本](http://www.sleeplessdomain.com/comics/1431588037-WgsI3vK.jpg)失败。 – Malandy

+0

并通过[这](http://mylittlewiki.org/w/images/7/71/Bangles.jpg),它应该返回(640,480),但我得到(1281:1)。 – Malandy

1

该代码并完成两两件事:

  • 获取图像尺寸

  • 找到真正的EOF一个jpg文件

当谷歌搜索时,我对后面的一个更感兴趣。 这个任务是从数据流中剪下一个jpg文件。由于我没有找到任何方法来使用Pythons'image'来获得如此jpg文件的EOF,所以我编写了这个文件。

有趣/更改/笔记该样品中:

  • 延伸至与该方法UINT16 使源代码更好可读性和可维护性的普通的Python文件类。 与struct.unpack乱搞()迅速使得代码看起来丑陋

  • 替换读over'uninteresting”区域/块以谋求

  • 柜面你只是想获得 你可以删除行尺寸:

    hasChunk = ord(byte) not in range(0xD0, 0xDA) + [0x00] 
    

    - >自

    阅读过的图像数据块 和评论时只能得到重要的210

    只要找到该维度即可停止阅读。 ......但微笑我要告诉 - 你的编码器;)

    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() 
    
17

这里有一种方式来获得一个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

+0

如果您需要的只是标题数据,那么读取整个图像数据是否有点低效? –

+2

要解决这个问题,一个可以重构'''get_image_info()'''把文件名作为参数(而不是二进制数据),然后就去做了'''f.read(25)'''仅阅读标题信息。 –

0

偶然发现了这一个,但你可以得到只要你输入numpy,就可以使用下面的方法。

import numpy as np 

[y, x] = np.shape(img[:,:,0]) 

它的工作原理是因为您忽略了除一种颜色以外的所有颜色,然后图像只是2D,所以形状会告诉您如何出价。对Python来说还是一个新手,但似乎是一个简单的方法。

3

关于Fred the Fantastic's answer

C0之间的每一个JPEG标记 - CFSOF标记;我排除了DHT(C4),DNL(C8)和DAC(CC)。请注意,我还没有研究过是否可以用这种方式解析除C0C2以外的任何帧。然而,其他人似乎相当罕见(我个人还没有遇到除C0C2以外)。

无论哪种方式,这解决了在注释中提到的问题MalandyBangles.jpg(DHT错误地解析为SOF)。

1431588037-WgsI3vK.jpg提到的另一个问题是由于imghdr只能够检测到APP0(EXIF)和APP1(JFIF)标头。

这可以通过向imghdr添加更宽松的测试(例如简单的FFD8FFD8FF?)或更复杂的(甚至可能是数据验证)来解决。使用更复杂的方法,我只发现了以下问题:APP14(FFEE)(Adobe);第一个标记是DQT(FFDB);和APP2和issues with embedded 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 

注:创建一个完整的答案,而不是评论,因为我还没有获准。

1

发现在另一#1后一个很好的解决方案(只使用标准库+含jpg处理以及):对于那些谁能够负担得起运行“文件JohnTESlade answer

而另一种解决方案(快捷方式) '蟒内命令,运行:

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在我的情况。

-2

由于图像存储在阵列简单地用

height = len(img) 
width = len(img[0]) 
相关问题