Python PNG画像を自力で出力する その4 |
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import binascii,struct,zlib
from struct import *
class MyPNG:
"""
初期化 イメージの大きさをピクセル単位で指定する
"""
def __init__(self, width, height):
self.width = width
self.height = height
self.pix = []
#内包するピクセルを1(白)で初期化
for h in range(height):
self.pix.append([1]*width)
"""
長方形を描画する
例)
rectangle((10,10,100,100))
"""
def rectangle(self, xy):
x1,y1,x2,y2 = xy
#todo 引数チェック処理
#塗りつぶし実行
for y in range(y1, y2):
for x in range(x1, x2):
self.pix[y][x] = 0
"""
イメージの保存を実行する
"""
def save(self, filepath):
self.open(filepath)
#pngヘッダ出力
self.write_png_header()
#ihdrチャンク出力
self.write_ihdr_chunk()
#idatチャンク出力
self.write_idat_chunk()
#iendチャンク出力
self.write_iend_chunk()
self.close()
def open(self, filepath):
self.f = open(filepath, 'wb')
def close(self):
self.f.close()
#pngヘッダー出力
def write_png_header(self):
self.write((0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A))
#ihdrチャンク出力
def write_ihdr_chunk(self):
#■長さ
self.write((0x00, 0x00, 0x00, 0x0D))
datas = []
#■チャンク形式
datas.extend((0x49, 0x48, 0x44, 0x52))
#■幅
datas.extend(unpack('BBBB', pack('>L', self.width)))
#■高さ
datas.extend(unpack('BBBB', pack('>L', self.height)))
#■ビット深度、カラータイプ、圧縮方法、フィルター方法、インターレース方法
datas.extend((0x01, 0x00, 0x00, 0x00, 0x00))
#■CRC32
datas.extend(self.crc32(datas))
self.write(datas)
#idatチャンク出力
def write_idat_chunk(self):
datas = []
for y in range(self.height):
line = ""
datas.append(0)
for x in range(self.width):
line += str(self.pix[y][x])
if len(line) == 8:
datas.append(int(line, 2))
line = ""
if line != "":
line += "0" * (8 - len(line))
datas.append(int(line, 2))
target = ""
for d in datas:
target += chr(d)
#zip圧縮
lines = zlib.compress(target)
datas = []
for l in lines:
datas.append(ord(l))
#■長さ
self.write(unpack('BBBB', pack('>L', len(datas))))
#■チャンク形式(IDAT)挿入 0x49 0x44 0x41 0x54
datas.insert(0, 0x49)
datas.insert(1, 0x44)
datas.insert(2, 0x41)
datas.insert(3, 0x54)
#■CRC32
datas.extend(self.crc32(datas))
self.write(datas)
#iendチャンク出力
def write_iend_chunk(self):
#■長さ
self.write((0x00, 0x00, 0x00, 0x00))
#■チャンク形式(IEND)
self.write((0x49, 0x45, 0x4E, 0x44))
#■CRC32
self.write((0xAE, 0x42, 0x60, 0x82))
#バイトデータ出力
def write(self, values):
for v in values:
self.f.write(pack('B', v))
#crc32を計算
def crc32(self, datas):
target = ""
for d in datas:
target += chr(d)
crc = binascii.crc32(target)
return unpack('BBBB', pack("!l", crc))
if __name__ == '__main__':
png = MyPNG(width=200, height=50)
png.rectangle((100,5,120,45))
png.save('test.png')
ちゃんと出力されている模様です。