program story

표준 Python 클래스를 사용하여 이미지 크기를 얻는 방법 (외부 라이브러리를 사용하지 않고)?

inputbox 2020. 11. 16. 08:15
반응형

표준 Python 클래스를 사용하여 이미지 크기를 얻는 방법 (외부 라이브러리를 사용하지 않고)?


Python 2.5를 사용하고 있습니다. 그리고 파이썬의 표준 클래스를 사용하여 파일의 이미지 크기를 결정하고 싶습니다.

PIL (Python Image Library)을 들었지만 작동하려면 설치가 필요합니다.

Python 2.5 자체 모듈을 사용하여 외부 라이브러리를 사용하지 않고 이미지 크기를 어떻게 얻을 수 있습니까?

참고 일반적인 이미지 형식, 특히 JPG 및 PNG를 지원하고 싶습니다.


다음은 외부 라이브러리를 사용하지 않고 .png, .gif 및 .jpeg에 대한 이미지 높이와 너비를 포함하는 튜플을 반환하는 파이썬 3 스크립트입니다 (예 : 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

Kurts 대답은 나를 위해 작동하도록 약간 수정해야했습니다.

첫째, 우분투에서 : sudo apt-get install python-imaging

그때:

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

자세한 내용 핸드북확인하십시오 .


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 파일의 크기를 얻을 수있는 방법이 있습니다. 에서 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


에 관한 프레드 환상적인 '의 대답 :

아니 모든 JPEG 마커 사이에 C0- CF있는 SOF마커; DHT ( C4), DNL ( C8), DAC ( CC)는 제외했습니다. 나는 아닌 다른 프레임 구문 분석하는 것도 가능 여부에보고하지 않았 음을 참고 C0하고 C2이러한 방식을. 그러나 다른 것들은 매우 드물게 보입니다 (개인적으로 C0이외의 다른 것을 본 적이 없습니다 C2).

어느 쪽이든 이것은 MalandyBangles.jpg(DHT가 SOF로 잘못 구문 분석 됨) 주석에 언급 된 문제를 해결합니다 .

언급 된 다른 문제 는 APP0 (EXIF) 및 APP1 (JFIF) 헤더 만 감지 할 수 1431588037-WgsI3vK.jpg있기 때문 imghdr입니다.

imghdr (예 : 간단히 FFD8또는 아마도 FFD8FF?)에 더 느슨한 테스트를 추가 하거나 훨씬 더 복잡한 것 (데이터 유효성 검사도 가능) 을 추가하여이 문제를 해결할 수 있습니다 . 더 복잡한 접근 방식으로 다음과 같은 문제 만 발견했습니다. APP14 ( FFEE) (Adobe); 첫 번째 마커는 DQT ( FFDB); 및 APP2 및 임베디드 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

참고 : 아직 허용되지 않았으므로 댓글 대신 전체 답변을 작성했습니다.


당신이하는 일이 있다면 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(',') ]

이 코드는 두 가지를 수행합니다.

  • 이미지 치수 얻기

  • jpg 파일 의 실제 EOF 찾기

인터넷 검색을 할 때 나는 나중에 더 많은 관심을 보였습니다. 작업은 데이터 스트림에서 jpg 파일을 잘라내는 것이 었습니다. II는 Python의 '이미지'를 사용하여 jpg-File의 EOF를 얻는 방법을 찾지 못했기 때문에 이것을 구성했습니다.

이 샘플의 흥미로운 사항 / 변경 사항 / 참고 사항 :

  • uInt16 메소드를 사용하여 일반 Python 파일 클래스를 확장하여 소스 코드를 더 읽기 쉽고 유지 관리하기 쉽게 만듭니다. struct.unpack ()을 엉망으로 만들면 코드가 빠르게보기 흉해집니다.

  • '관심없는'영역 / 청크에 대한 읽기를 탐색으로 대체했습니다.

  • 치수를 얻고 싶다면 선을 제거 할 수 있습니다.

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

    -> 이미지 데이터 청크를 읽고 댓글을 달 때만 중요하기 때문에

    #break
    

    치수가 발견되는 즉시 읽기를 중지합니다. ...하지만 내가 말하는 것을 웃으십시오 -당신은 Coder입니다;)

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

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.


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]))

Stumbled upon this one but you can get it by using the following as long as you import numpy.

import numpy as np

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

It works because you ignore all but one color and then the image is just 2D so shape tells you how bid it is. Still kinda new to Python but seems like a simple way to do it.

참고URL : https://stackoverflow.com/questions/8032642/how-to-obtain-image-size-using-standard-python-class-without-using-external-lib

반응형