見出し画像

Pyxel実験室「255色の画像を表示」

複数色のマンデルブロートの表示で最大255色の画像表示ができることがわかりました。
それだったら通常の画像データも表示できるんじゃない?という考えで始めてみましたが、減色で調査していた通りですんなりできるわけではありません。

・Image.load関数で Pyxel 向け配色の画像ファイル (PNG/GIF/JPEG) を読み込む

にもある通りで、「Pyxel 向け配色の画像ファイル」というのがおそらく16色の画像ファイルという意味なんだと思います。ここの方法もまだ解明はできていませんが・・・

最終的に「255色の画像の表示」はできましたが、かなり力技でした。
備忘録含めて書き残したいと思います。

JPG画像を255色に減色、ここはpythonで変換。

#減色プログラム
from PIL import Image

#オリジナル画像読み込み
im = Image.open('nextfighter_06.JPG')
im_q = im.quantize(colors=255, method=0, kmeans=100, dither=1)

#255色に減色した画像を保存(PNGのパレットモードに変換される)
im_q.save('test.png')

最初にそのままPyxelのimage.load使ってロードしてみましたが案の定真っ暗でした・・・そんなにうまく行くわけはない。

255色にしたんだからここからカラーデータを抜きつつパレットデータを作ろうかとか思っていましたが、PNGファイルのモードはパレットモードになっていました。

(注釈:ここではPNGのパレットモードだから出来たわけでそこに持っていくまでは別な作業が発生するのかも。そもそもRGBAモードからパレットモードに容易に変換できるものではないことはわかった。)

パレットモードって何?ってことでフォーマットを調査。

すでにデータがパレットデータとインデックスデータに分かれて格納されているようです。そしてそれらはpythonライブラリのPILで取得できるそうな。

pythonはしろうと同然なのでそんなことは知りませんでした。

やったこと
・PNGの画像サイズ取得
・パレットのサイズを確認(255を確認)
・パレットの取得
・インデックスの取得

で、まだ取得したデータをファイルに残す方法を知らないので(昔やった記憶はあるけど、かなり昔でもう覚えていない)コンソールに出力させてみました。(力技)

コードメモ

from PIL import Image
import numpy as np

im = Image.open('test.png')

#画像サイズを取得
#print(im.format, im.size, im.mode)
#→PNG (1200, 799) P

#画像からパレットを取得してRGBの順になるように3つずつのlistに格納する
_palette = list(zip(*[iter(im.getpalette())]*3))

#リストのサイズ取得
#print(len(_palette))
#→255

#リソースのパレットフォーマットで出力
for _col in range(len(_palette)):
	print(hex(_palette[_col][0]*0x10000 + _palette[_col][1]*0x100 + _palette[_col][2]))

#次にインデックスデータを取得
_img = np.asarray(im)
#_img[0]は、長さim.size[0](width)の配列
#_imは、長さim.size[1](height)のリスト配列

#pyxel.psetのデータを出力
for _yp in range(im.size[1]):
	for _xp in range(im.size[0]):
		print("pyxel.pset(",_xp,",", _yp,",", hex(_img[_yp][_xp]), ")")

そんなわけで取得できました。
パレットデータはtest.pyxpalとして作成。
その前に空のリソースファイルを作っておきます。ファイル名:test.pyxres

でPyxelのソースコード(インデックスデータは長いので省略してます。何しろテキストで96万行弱ありました(笑)

import pyxel

pyxel.init(1200, 799)
pyxel.cls(0)
pyxel.load("test.pyxres")
pyxel.pset( 0 , 0 , 0xba )
pyxel.pset( 1 , 0 , 0xba )
pyxel.pset( 2 , 0 , 0xba )
pyxel.pset( 3 , 0 , 0xba )
	:
pyxel.pset( 1198 , 798 , 0xe5 )
pyxel.pset( 1199 , 798 , 0xe5 )
pyxel.show()

結果:
「戦闘機」で検索して出てきた画像を拝借。

Pyxelで255色の画像表示

ツッコミどころはたくさんありますが、表示はできました。
変換用やファイル出力とかをもっとうまくやればいいのかなとか思います。

もっと簡単な方法があるのかもしれない・・・
→追記0919:pyxel.screen.data_ptr() を使えばもっと高速になりそうである。


追記0903
応用編

キャラクタに応用

一つのキャラクタ(今回は飛行機)に16色を使い、それを1パレットとして、12パレット分を組み込みました。12個の飛行機それぞれが別の16色を使って表示させてます。

これなら16色ごとにリソースエディタで編集可能で同時表示も可能になります。16色を超えたカラーデータをセットするにはイメージバンクからではなく、psetを使う必要があるということ。

今回はドットパターンを自前で書いていますが、リソースファイル展開するとそれっぽいデータが取れるのでそこからコード書くのもいいかと思います。
ちなみに私が作成したドット絵パターンは以下。

#	0 1 2 3 4 5 6 7   8 9 a b c d e f
#0	□□□□□□□□ □□□□□□□□
#1	□□□□□□■□ □■□□□□□□
#2	□□□□□□■□ □■□□□□□□
#3	□□□□□□■■ ■■□□□□□□
#4	□□■□□□■■ ■■□□□■□□
#5	□□■□□■■■ ■■■□□■□□
#6	□□■□□■■■ ■■■□□■□□
#7	□□■□□■■■ ■■■□□■□□
#
#8	□□■□■■■■ ■■■■□■□□
#9	□□■□■■■■ ■■■■□■□□
#a	□□■■■■■■ ■■■■■■□□
#b	□□■■■■■■ ■■■■■■□□
#c	□■■■■■■■ ■■■■■■■□
#d	■■■□■■■■ ■■■■□■■■
#e	■■□□■■□□ □□■■□□■■
#f	□□□□■■□□ □□■■□□□□

plyer_tbl = [0 for tbl in range(0xf6)]
plyer_tbl = [
	0x61, 0x4, 0x91, 0x4, 0x62, 0x3, 0x92, 0x3,		#0x00
	0x63, 0x3, 0x73, 0xf, 0x83, 0xf, 0x93, 0x3,		#
	0x24, 0x4, 0x64, 0xf, 0x74, 0x1, 0x84, 0x2,		#0x10
	0x94, 0xf, 0xd4, 0x4, 0x25, 0x3, 0x55, 0xa,		#
	0x65, 0xd, 0x75, 0x1, 0x85, 0x2, 0x95, 0xd,		#0x20
	0xa5, 0xa, 0xd5, 0x3, 0x26, 0x3, 0x56, 0xa,		#
	0x66, 0xd, 0x76, 0xd, 0x86, 0xd, 0x96, 0xd,		#0x30
	0xa6, 0xa, 0xd6, 0x3, 0x27, 0xf, 0x57, 0xa,		#
	0x67, 0xc, 0x77, 0xd, 0x87, 0xd, 0x97, 0xc,		#0x40
	0xa7, 0xa, 0xd7, 0xf, 0x28, 0xf, 0x48, 0xb,		#
	0x58, 0xa, 0x68, 0xf, 0x78, 0xc, 0x88, 0xc,		#0x50
	0x98, 0xf, 0xa8, 0xa, 0xb8, 0xb, 0xd8, 0xf,		#
	0x29, 0xf, 0x49, 0xb, 0x59, 0xa, 0x69, 0xf,		#0x60
	0x79, 0xa, 0x89, 0xa, 0x99, 0xf, 0xa9, 0xa,		#
	0xb9, 0xb, 0xd9, 0xf, 0x2a, 0xf, 0x3a, 0xe,		#0x70
	0x4a, 0xb, 0x5a, 0xa, 0x6a, 0xf, 0x7a, 0x9,		#

	0x8a, 0xe, 0x9a, 0xf, 0xaa, 0xa, 0xba, 0xb,		#0x80
	0xca, 0xe, 0xda, 0xf, 0x2b, 0xe, 0x3b, 0xe,		#
	0x4b, 0xb, 0x5b, 0xa, 0x6b, 0xf, 0x7b, 0x9,		#0x90
	0x8b, 0xe, 0x9b, 0xf, 0xab, 0xa, 0xbb, 0xb,		#
	0xcb, 0xe, 0xdb, 0xe, 0x1c, 0xe, 0x2c, 0xe,		#0xa0
	0x3c, 0xe, 0x4c, 0xb, 0x5c, 0xa, 0x6c, 0xf,		#
	0x7c, 0x9, 0x8c, 0xe, 0x9c, 0xf, 0xac, 0xa,		#0xb0
	0xbc, 0xb, 0xcc, 0xe, 0xdc, 0xe, 0xec, 0xe,		#
	0x0d, 0xe, 0x1d, 0xe, 0x2d, 0xe, 0x4d, 0x8,		#0xc0
	0x5d, 0x8, 0x6d, 0x7, 0x7d, 0x9, 0x8d, 0xe,		#
	0x9d, 0x7, 0xad, 0x8, 0xbd, 0x8, 0xdd, 0xe,		#0xd0
	0xed, 0xe, 0xfd, 0xe, 0x0e, 0xe, 0x1e, 0xe,		#
	0x4e, 0x5, 0x5e, 0x5, 0xae, 0x5, 0xbe, 0x5,		#0xe0
	0xee, 0xe, 0xfe, 0xe, 0x4f, 0x6, 0x5f, 0x6,		#
	0xaf, 0x6, 0xbf, 0x6, 0xff, 0xff				#0xf0
	]

1ドットを2バイトで表しています。
横方向オフセット * 0x10 + 縦方向オフセットで1バイト
カラー番号で1バイト

カラー番号に+(0x10*パレット番号)してやることでパレット番号(カラー番号)指定としています。
さらに応用すると255色のどれでも使い放題になるので何でもアリになります。255色編集可能なエディタを連携させる必要はあるけれど・・・

Pyxelは色数などの制限はあれど、容量の規定は無いので処理速度を気にするだけで何でもできるのでは無いかと思います。

あとはアイデア次第なのでは無いでしょうか?

ちなみに上記ドット絵パターンはJavaScript版麻雀で使用した手法です。
麻雀牌&フォントを全てドット絵テキストデータにおこすのはとても大変でした。
気力が無いと無理ですね(笑)

この記事が気に入ったらサポートをしてみませんか?