Python で png 画像を自力で生成する
Ruby で png 画像を自力で生成する - まめめも を Python に移植しただけw
# -*- coding: utf-8 -*- from sys import stdout from struct import pack from zlib import crc32, compress width, height = 100, 20 depth, color_type = 8, 2 # グラデーションのベタデータ line = [[x * 255 / width, 0, 0] for x in range(width)] raw_data = [line] * height # チャンクのバイト列生成関数 def chunk(type, data): return pack('!I4s%dsi' % len(data), len(data), type, data, crc32(type + data)) # ファイルシグニチャ stdout.write('\x89PNG\r\n\x1a\n') # ヘッダ stdout.write(chunk('IHDR', pack("!IIBBBBB", width, height, depth, color_type, 0, 0, 0))) # 画像データ img_data = ''.join(pack("%dB" % (width * 3 + 1), *sum([[0]] + line, [])) for line in raw_data) stdout.write(chunk("IDAT", compress(img_data))) # 終端 stdout.write(chunk('IEND', ''))
* が使える Ruby の pack が羨ましいです><
# -*- coding: utf-8 -*- # http://www.physics.sfasu.edu/astro/color/spectra.html def wavelength_to_rgb(n): if n < 380: rgb = [0.0 , 0.0 , 0.0 ] elif n < 440: rgb = [(440.0 - n) / 60.0, 0.0 , 1.0 ] elif n < 490: rgb = [0.0 , (n - 440.0) / 50.0, 1.0 ] elif n < 510: rgb = [0.0 , 1.0 , (510.0 - n) / 20.0] elif n < 580: rgb = [(n - 510.0) / 70.0, 1.0 , 0.0 ] elif n < 645: rgb = [1.0 , (645 - n) / 65.0 , 0.0 ] elif n < 780: rgb = [1.0 , 0.0 , 0.0 ] else: rgb = [0.0 , 0.0 , 0.0 ] if n < 380: factor = 0.0 elif n < 420: factor = 0.3 + 0.7 * (n - 380.0) / 40.0 elif n < 700: factor = 1.0 elif n < 780: factor = 0.3 + 0.7 * (780.0 - n) / 80.0 else: factor = 0.0 return map(lambda c: 0 if c == 0.0 else 255 * ((c * factor) ** 0.8), rgb) # generate png from sys import stdout from struct import pack from zlib import crc32, compress width, height = 100, 20 depth, color_type = 8, 2 line = map(lambda x: wavelength_to_rgb(380 + x * 400 / width), range(width)) raw_data = [line] * height def chunk(type, data): return pack('!I4s%dsi' % len(data), len(data), type, data, crc32(type + data)) stdout.write('\x89PNG\r\n\x1a\n') stdout.write(chunk('IHDR', pack("!IIBBBBB", width, height, depth, color_type, 0, 0, 0))) img_data = ''.join(pack("%dB" % (width * 3 + 1), *sum([[0]] + line, [])) for line in raw_data) stdout.write(chunk("IDAT", compress(img_data))) stdout.write(chunk('IEND', ''))
さすがに芸が無いかなと思ったので、Sub フィルタを突っ込んでみたw
# -*- coding: utf-8 -*- from sys import stdout from struct import pack from zlib import crc32, compress width, height = 100, 20 depth, color_type = 8, 2 line = [[x * 255 / width, 0, 0] for x in range(width)] # Sub フィルタを適用 for i in range(width - 1, 0, -1): line[i][0] = (line[i][0] - line[i - 1][0] + 255) % 255 raw_data = [line] * height def chunk(type, data): return pack('!I4s%dsi' % len(data), len(data), type, data, crc32(type + data)) stdout.write('\x89PNG\r\n\x1a\n') stdout.write(chunk('IHDR', pack("!IIBBBBB", width, height, depth, color_type, 0, 0, 0))) img_data = ''.join(pack("%dB" % (width * 3 + 1), *sum([[1]] + line, [])) for line in raw_data) stdout.write(chunk("IDAT", compress(img_data))) stdout.write(chunk('IEND', ''))