4
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

pythonでバイナリデータを読む(PNGを例として)

Last updated at Posted at 2019-06-09

環境

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

概要

前準備:読み込むpngを作る

1ピクセルの黒いpngをさくっと作ります

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)

black.png

pngをバイナリデータとして読み込む

エンディアン

pngはネットワークバイトオーダ(=ビッグエンディアン)でデータが格納されます。
以下に記載されているように、フォーマット文字列の最初に">"を入れることによってビッグエンディアンを指定します。

ちなみに、自分のマシンのエンディアン(=native)を知りたければ以下のようにしましょう。

import sys
print(sys.byteorder)
#little or big

zlibによるデータ解凍

さて、念願のデータを手に入れましたが、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で解凍しましょう。

バイト列に変換してからdecompressすればOKです。

import zlib
idata = zlib.decompress(bytearray(idata))
print(idata)
#b'\x00\x00\x00\x00'

コード全文

offsetをずらしながら、必要なデータをどんどん読み込んでいきます。

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) → 黒

データの中身を取り出すことができました。素晴らしい。

必要なのは正確なフォーマット情報と、根気ですね。

4
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?