How to obtain image size using standard Python class (without using external library)?

后端 未结 10 1490
有刺的猬
有刺的猬 2020-11-29 18:02

I am using Python 2.5. And using the standard classes from Python, I want to determine the image size of a file.

I\'ve heard PIL (Python Image Library), but it requi

相关标签:
10条回答
  • 2020-11-29 18:42

    It depends on the output of file which I am not sure is standardized on all systems. Some JPEGs don't report the image size

    import subprocess, re
    image_size = list(map(int, re.findall('(\d+)x(\d+)', subprocess.getoutput("file" + filename))[-1]))
    
    0 讨论(0)
  • 2020-11-29 18:44

    While it's possible to call open(filename, 'rb') and check through the binary image headers for the dimensions, it seems much more useful to install PIL and spend your time writing great new software! You gain greater file format support and the reliability that comes from widespread usage. From the PIL documentation, it appears that the code you would need to complete your task would be:

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

    As for writing code yourself, I'm not aware of a module in the Python standard library that will do what you want. You'll have to open() the image in binary mode and start decoding it yourself. You can read about the formats at:

    • PNG file format documentation
    • Notes on the JPEG file format headers
    0 讨论(0)
  • 2020-11-29 18:44

    Found a nice solution in another Stackoverflow post (using only standard libraries + dealing with jpg as well): JohnTESlade answer

    And another solution (the quick way) for those who can afford running 'file' command within python, run:

    import os
    info = os.popen("file foo.jpg").read()
    print info
    

    Output:

    foo.jpg: JPEG image data...density 28x28, segment length 16, baseline, precision 8, 352x198, frames 3
    

    All you gotta do now is to format the output to capture the dimensions. 352x198 in my case.

    0 讨论(0)
  • 2020-11-29 18:48

    Regarding Fred the Fantastic's answer:

    Not every JPEG marker between C0-CF are SOF markers; I excluded DHT (C4), DNL (C8) and DAC (CC). Note that I haven't looked into whether it is even possible to parse any frames other than C0 and C2 in this manner. However, the other ones seem to be fairly rare (I personally haven't encountered any other than C0 and C2).

    Either way, this solves the problem mentioned in comments by Malandy with Bangles.jpg (DHT erroneously parsed as SOF).

    The other problem mentioned with 1431588037-WgsI3vK.jpg is due to imghdr only being able detect the APP0 (EXIF) and APP1 (JFIF) headers.

    This can be fixed by adding a more lax test to imghdr (e.g. simply FFD8 or maybe FFD8FF?) or something much more complex (possibly even data validation). With a more complex approach I've only found issues with: APP14 (FFEE) (Adobe); the first marker being DQT (FFDB); and APP2 and issues with embedded ICC_PROFILEs.

    Revised code below, also altered the call to imghdr.what() slightly:

    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
    

    Note: Created a full answer instead of a comment, since I'm not yet allowed to.

    0 讨论(0)
  • 2020-11-29 18:53

    Here's a python 3 script that returns a tuple containing an image height and width for .png, .gif and .jpeg without using any external libraries (ie what Kurt McKee referenced above). Should be relatively easy to transfer it to 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 讨论(0)
  • 2020-11-29 18:53

    Here's a way to get dimensions of a png file without needing a third-party module. From 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)
    

    When you run this, it will return:

    True
    (x, y)
    

    And another example that includes handling of JPEGs as well: http://markasread.net/post/17551554979/get-image-size-info-using-pure-python-code

    0 讨论(0)
提交回复
热议问题