pythonでpngファイルを開いてみる3.5

手探りpython

まずは前回の記事へのリンク。

pythonでpngファイルを開いてみる3 - 放心ラボラトリ

前回、こんなコードを書いています。

self.i_width = int(self.f.read(4).hex(),16)

なんというか、()が多いのがまずイマイチ。そして、わざわざ16進数に直してから整数型で返しているし…。なにをやりたいんだ?
と言われてもしょうがないですね。で相変わらずネットポチポチしてたら見つけましたよ。

import struct
・・・
self.f = open(fname,'rb')
imgdata = self.f.read()
width = struct.unpack_from(">I", imdata, 16)

byte型を所定の型に変換(unpack)して返してくれるらしい。マニュアルに載ってた。

struct.unpack_from(fmt, buffer[, offset=0])
buffer を与えられたフォーマットでアンパックします。 値が一つしかない場合を含め、結果はタプルで返されます。 buffer には最低でも format に要求されるサイズのデータが必要です。 (len(buffer[offset:]) は calcsize(fmt) 以上で無ければなりません)。

ですよねー。そりゃあ、それくらいありますよねー。まさにCの型に変換するのを目的としているらしいですよ。 第一引数が型指定のようです。 今回使ったやつだけメモしとこう。

引数で指定 Cの型
I unsigned int
i int
s char
B unsigned char
b char

python勉強してて思うこと

byteとかbinaryで読み出して他の型(整数型とか)に直したい時なんて、当然のようにあるから、標準ライブラリには当然のように実装されているだろうとは思ってました。そして実際に標準ライブラリに実装されていました。
だだ、よく考えるまでもなく、pythonって型宣言しなくても良いんですよね。勝手に解釈してくれるから。で、世間に出回ってるライブラリが超豊富だから、大体のことはサンプルコードコピペで出来ちゃう。
ということは、初めての言語がpythonで、独学で学ぼうとする場合、変数の型なんて意識せずに結構なアプリ開発ができるようになるのかな。なるんでしょうね。 pythonは、VMの機能が強烈なのか、各種ライブラリがそこまでフォローしているのか…。まあ、何でもかんでもオブジェクトにしてやってこう、という考え方とたいへんマッチしていると思いました。とにかく、コードを書く人がPC側の都合に左右されないように、という考え方のもと設計されているということですね。むしろその先がプログラマの方々のウデの見せ所になるのか。

なんとなくコードを載せておこう

上記を反映させて、以下のようなソースとしてみました。我がPCにお住まいのlennaさん、サブチャンクないと思っていたら、sRGBというのが入ってました。あと、結局、見難さは変わっていないというね。

import struct

class png_img:
    def __init__(self,fname):
        self.f = open(fname,'rb')
        self.imgdata = self.f.read()
        self.signature = struct.unpack_from(">8B", self.imgdata, 0)
        self.slength = struct.unpack_from(">I", self.imgdata, 8)
        self.c_type = struct.unpack_from(">4s", self.imgdata, 12)
        self.i_width = struct.unpack_from(">I", self.imgdata, 16)
        self.i_height = struct.unpack_from(">I", self.imgdata, 20)
        self.bit_depth = struct.unpack_from(">B", self.imgdata, 24)
        self.color_type = struct.unpack_from(">B", self.imgdata, 25)
        self.comp_method = struct.unpack_from(">B", self.imgdata, 26)
        self.filter_method = struct.unpack_from(">B", self.imgdata, 27)
        self.interlace_method = struct.unpack_from(">B", self.imgdata, 28)
        self.crc = struct.unpack_from(">B", self.imgdata, 29)
        self.cslength = struct.unpack_from(">I", self.imgdata, 33)
        self.cs_type = struct.unpack_from(">4s", self.imgdata, 37)
        self.cs_val = struct.unpack_from(">B", self.imgdata, 41)
        self.cs_crc = struct.unpack_from(">B", self.imgdata, 42)
        self.idat_length = struct.unpack_from(">I", self.imgdata, 46)
        self.idat_type = struct.unpack_from(">4s", self.imgdata, 50)
        self.f.close()
    def getsLength(self):
        return self.slength
    def getSignature(self):
        return self.signature
    def getWidth(self):
        return self.i_width
    def getHeight(self):
        return self.i_height
    def printsignature(self):
        print(self.signature)
    def printIHDR(self):
        print(self.slength,self.c_type,self.i_width,self.i_height,
        self.bit_depth,self.color_type,self.comp_method,
        self.filter_method,self.interlace_method,self.crc)
    def printsRGB(self):
        print(self.cslength,self.cs_type,self.cs_val,self.cs_crc)
    def printIDAT(self):
        print(self.idat_length,self.idat_type)

name='フルパス/lenna.png'
png=png_img(name)
png.printsignature()
png.printIHDR()
png.printsRGB()
png.printIDAT()

で、今IDATチャンクを読み出していってるんだけど、いっぱいあるんですよね。複数あっても結合するように書かないといけないんだな。面倒だな。Cだったらすぐできそうだけど(強がりです)、pythonだとどうすれば良いのかな。勉強だな。