PyxelとPILライブラリを使って、SlideShowを作成しました。
「16色を超える色」の255色に減色して表示を繰り返しています。
やってることは
1.画像ファイルを読み込み
2.RGBAモードに変換
3.画像サイズ変更(画像の縦横比を維持)
4.255色に減色
5.表示
前準備として、
内部で減色したカラーデータをmy_resource.pyxpalに保存して使用するため、本プログラムの実行前にPyxelエディタを実行("pyxel edit")、ファイル保存して空のリソースファイル:my_resource.pyxresを作成してください。
また、画像ファイルをカレントのimgフォルダに格納してください。
表示画像サイズや読み込みフォルダを変更したいときはコード内の該当箇所を変更してください。表示できないファイルはコンソールにエラー内容を表示してとばします。
操作方法は、マウス左クリックで次の画像へ、右クリックで終了です。
from PIL import Image
import numpy as np
import pyxel
import os
#表示画像サイズ
SCREEN_WIDTH = 640
SCREEN_HEIGHT = 480
#画像フォルダ指定
_folder_path = './img'
#----------------------------------------------------
#画像表示
def disp_image(filename):
try:
im = Image.open(filename)
except ValueError as e:
disp_error(filename + ": Image.open ERROR[ValueError]")
print(e)
return
except OSError as e:
disp_error(filename + ": Image.open ERROR[OSError]")
print(e)
return
except PIL.UnidentifiedImageError as e:
disp_error(filename + ": Image.open ERROR[PIL.UnidentifiedImageError]")
print(e)
return
except:
disp_error(filename + ": Image.open ERROR[Other Error]")
return
#----------------------------------------------------
#RGBAモードに変換
try:
im = im.convert('RGB')
except ValueError as e:
disp_error(filename + ": convert RGB ERROR[ValueError]")
print(e)
except OSError as e:
disp_error(filename + ": convert RGB ERROR[OSError]" )
print(e)
except:
disp_error(filename + ": RGB convert ERROR")
return
#----------------------------------------------------
#画像サイズ変更
try:
resize_im = im.copy()
#画像の縦横比を維持したままリサイズ
resize_im.thumbnail(( SCREEN_WIDTH, SCREEN_HEIGHT ))
#縦横のサイズの大きい方が指定サイズに収まるように拡大(割合リサイズの必要あり)
if( resize_im.width > resize_im.height ):
if( SCREEN_WIDTH > resize_im.width ):
resize_im = resize_im.resize(( SCREEN_WIDTH, SCREEN_HEIGHT ))
#指定サイズの中央に画像を置く
width, height = resize_im.size
yohaku_w = int((SCREEN_WIDTH - width)/2)
yohaku_h = int((SCREEN_HEIGHT - height)/2)
result = Image.new(resize_im.mode, (SCREEN_WIDTH, SCREEN_HEIGHT), (0,0,0))
result.paste(resize_im, (yohaku_w, yohaku_h))
resize_im = result.copy()
except ValueError as e:
disp_error(filename + ": resize ERROR[ValueError]")
print(e)
return
except OSError as e:
disp_error(filename + ": resize ERROR[OSError]" )
print(e)
return
except:
disp_error(filename + ": resize ERROR[Other Error]")
return
#----------------------------------------------------
#減色
try:
im_q = resize_im.quantize(colors=255, method=0, kmeans=100, dither=1)
except ValueError as e:
disp_error(filename + ": resize_im.quantize ERROR[ValueError]")
peint(e)
return
except OSError as e:
disp_error(filename + ": resize_im.quantize ERROR[OSError]")
peint(e)
return
except:
disp_error(filename + ": resize_im.quantize ERROR[Other Error]")
return
#----------------------------------------------------
#画像からパレットを取得してRGBの順になるように3つずつのlistに格納する
_palette = list(zip(*[iter(im_q.getpalette())]*3))
#----------------------------------------------------
#画像データ抽出して表示
_pix = np.asarray(im_q)
with open('./my_resource.pyxpal', mode='w') as f:
for _col in range(len(_palette)):
f.write( hex(_palette[_col][0]*0x10000 + _palette[_col][1]*0x100 + _palette[_col][2]).removeprefix('0x')+'\n' )
#255色カラーデータを読み込むためリソース読み込み
pyxel.load("my_resource.pyxres")
#画面クリア
pyxel.cls(0)
#描画
_scrptr = pyxel.screen.data_ptr()
for _yp in range(SCREEN_HEIGHT):
_s = _yp * SCREEN_WIDTH
_e = _s + SCREEN_WIDTH
_scrptr[ _s : _e ] = _pix[_yp]
#キー入力待ち
#----------------------------------
def disp_error(_str):
global _flag
#エラー画像はとばす
_flag = 2
print(_str)
#----------------------------------------------------
#左クリックで次の画像へ、右クリックで終了
_flag = 0
_count = 0
_piclist =[]
def update():
global _flag
global _count
global _piclist
if( _flag == 1 ):
if( pyxel.btnp(pyxel.MOUSE_BUTTON_LEFT) ):
_flag = 0
_count = _count + 1
if( _count >= len( _piclist ) ):
_count = 0
elif( pyxel.btnp(pyxel.MOUSE_BUTTON_RIGHT) ):
pyxel.quit()
#Error発生時はすぐに次へ
elif( _flag == 2 ):
_flag = 0
_count = _count + 1
if( _count >= len( _piclist ) ):
_count = 0
#----------------------------------
def draw():
global _flag
global _count
global _piclist
if( _flag == 0 ):
_flag = 1
disp_image( _folder_path + '/' + _piclist[_count].rstrip() )
#----------------------------------------------------
pyxel.init( SCREEN_WIDTH, SCREEN_HEIGHT )
try:
_piclist = os.listdir(_folder_path)
except FileNotFoundError:
print("イメージフォルダ",_folder_path,"が無いので終了")
pyxel.quit()
except:
pyxel.quit()
#初期化
_flag = 0
_count = 0
#実行
pyxel.run(update, draw)
Pyxelではこのように外部ライブラリを使うこともできます。
ただ、html化した時にPILライブラリが無いと言われてしまうので今後に期待!
参考までに、Pillow対応画像形式(ただし必ず表示できるわけではありません)
(参考URL:https://pillow.readthedocs.io/en/latest/handbook/image-file-formats.html)
[Full Support]
BLP, BMP, DDS, DIB, EPS, GIF, ICNS, ICO, IM, JPEG, JPEG2000, MSP,
PCX, PFM, PNG, APNG, PPM, SGI, SPIDER, TGA, TIFF, WebP, XBM,
[Read-only]
CUR, DCX, FITS, FLI, FLC, FPX, FTEX, GBR, GD, IMT, IPTC/NAA,
MCIDAS, MIC, MPO, PCD, PIXAR, PSD, QOI, SUN, WAL, WMF, EMF, XPM
[Write-only]
PALM, PDF, XV Thumbnails
[Identify-only]
BUFR, GRIB, HDF5, MPEG
後記:
エラー対応や処理方法など不備があるかもしれません。
その時は指摘頂けると助かります。