pythn에서 바이너리 데이터 읽기(PNG의 경우)

컨디션

  • Windows10 Pro
  • Python 3.6.4::Anaconda
  • zlib 1.2.11
  • 개요

  • struct 모듈은pythn에서 바이너리를 읽기와 쓰기에 편리하다

  • https://docs.python.org/ja/3/library/struct.html#struct.unpack_from
  • png의 내용을 읽어 보세요
  • http://web.archive.org/web/20050407143942/http://tech.millto.net/~pngnews/kndh/PngSpec1.2/PNGcontents.html
  • 사전 준비: 읽는 pg 만들기


    1픽셀의 검은색 pg 만들기
    makePng.py
    from PIL import Image, ImageDraw
    
    screen = (1,1)
    bgcolor=(0,0,0)
    filename = "black.png"
    
    img = Image.new('RGB', screen, bgcolor)
    img.save(filename)
    

    pg를 2진 데이터로 읽기


    반숙


    png은 네트워크 바이트 (= 대단절 순서) 에 데이터를 저장합니다.
    다음과 같이 형식 문자열의 시작 부분에 '>' 을 입력해서 큰 endian을 지정합니다.
  • https://docs.python.org/ja/3/library/struct.html#byte-order-size-and-alignment
  • 참고로 자신의 기계의 endian(=native)을 알고 싶다면 다음과 같다.
    import sys
    print(sys.byteorder)
    #little or big
    

    zilib을 통한 데이터 동결 해제


    그러면 소원의 데이터를 얻었지만 deflate 압축이 걸려 있습니다.
    idata = list(struct.unpack_from(">" + str(length[0]) + "B", data, offset + 8))
    print(idata)
    #[120, 156, 99, 96, 96, 96, 0, 0, 0, 4, 0, 1]
    
    여러분이 가장 좋아하는 zlib으로 해동하세요.
  • https://docs.python.org/ja/3/library/zlib.html
  • 바이트열로 변환하면 decomparess가 됩니다.
    import zlib
    idata = zlib.decompress(bytearray(idata))
    print(idata)
    #b'\x00\x00\x00\x00'
    

    코드 전체 텍스트


    오프셋을 엇갈리게 하면서 필요한 데이터를 계속 읽습니다.
    binary.py
    import struct
    import os
    import zlib
    
    f = open("black.png", "rb")
    data = f.read()
    
    #unpack_fromはtupleを返す,たとえ要素が1つでも
    #pngシグネチャ 8byteで(0x89 0x50 0x4E 0x47 0x0D 0x0A 0x1A 0x0A)
    signature = struct.unpack_from(">8B", data, 0)
    
    offset = 8
    
    #image header(25 bytes)
    length = struct.unpack_from(">I", data, offset) 
    ctype = struct.unpack_from(">4s", data, offset + 4)
    width = struct.unpack_from(">I", data, offset + 8)
    height = struct.unpack_from(">I", data, offset + 12)
    bitDepth = struct.unpack_from(">B", data, offset +16)
    colorType = struct.unpack_from(">B", data, offset + 17)
    compless = struct.unpack_from(">B", data, offset + 18)
    filter = struct.unpack_from(">B", data, offset + 19)
    interlace = struct.unpack_from(">B", data, offset + 20)
    crc = struct.unpack_from(">I", data, offset + 21)
    
    print(length, ctype, width, height, bitDepth, colorType, compless, filter, interlace)
    offset += 25
    
    #image data
    length = struct.unpack_from(">I", data, offset) 
    ctype = struct.unpack_from(">4s", data, offset + 4)
    print(length, ctype)
    idata = list(struct.unpack_from(">" + str(length[0]) + "B", data, offset + 8))
    
    offset += length[0] + 12
    
    #Image trailer(12 bytes)
    length = struct.unpack_from(">I", data, offset) 
    ctype = struct.unpack_from(">4s", data, offset + 4)
    print(length, ctype)
    
    f.close()
    
    #zlibによる解凍
    idata = zlib.decompress(bytearray(idata))
    print(idata)
    

    출력

    (13,) (b'IHDR',) (1,) (1,) (8,) (2,) (0,) (0,) (0,)
    (12,) (b'IDAT',)
    (0,) (b'IEND',)
    b'\x00\x00\x00\x00'
    
    마지막 줄은 png의 데이터 열입니다.
    데이터는 (필터, R, G, B) 순으로 들어갑니다.
    필터: 0 - 필터 없음
    R, G, B: (0, 0, 0)→블랙
    나는 데이터의 내용을 꺼냈다.대박이다.
    정확한 양식의 정보와 끈기가 필요하다.

    좋은 웹페이지 즐겨찾기