やってみる

アウトプットすべく己を導くためのブログ。その試行錯誤すらたれ流す。

ドット絵で遊ぶ Piskel

 今週のお題「最近見つけたかわいいもの」。ドット絵ってチマーンとしてて可愛いから好き。

ドット絵

 ドット絵の魅力は素人でもポチポチすれば絵が描ける所です。それがチンマリしてて可愛い。なにより、動かすことができます。動くと一気に生きてる感が出てきて楽しくなります。

 残念ながら私の絵心では、可愛いというよりキモイ何かしか生まれませんが。

 一見普通のつまらない絵だけど、なんかマクドナルドのドナルド的な、サイコパスみを感じる。何一つおめでたくない紅白ヅラで、狂ったように満面の笑みを繰り返す。恐怖しかない。

 10秒以上見つめると正気を失いそう。ママーこれなにー? 見ちゃいけません!

piskel

 ドット絵を描くには専用ツールを使うのがいいです。ググればWEBツールがいくつか出ますが、私はpiskelを推します。

 お勧めポイントは次のとおりです。

  • 無料
  • アカウント不要
  • どのOSでも動作する
  • わかりやすいUI
  • 高機能(レイヤ・アニメ・範囲選択等)
  • 出力形式がプログラマブルでゲーム等にも使いやすい
  • OSS(オープン・ソース・ソフトウェア)で改造し放題

 欲しい機能があり、最短でアクセスでき、不要なものが無い。最高のドット絵WEBツールです。

 サイトが英語なので嫌煙されそうなのが難点です。

 他にもドット絵のツールとしては、EDGEやAsepriteが有名ですが、EDGEはWindows専用だし、Asepriteは有料です。残念ながらpiskelには勝てません。

使い方

  1. piskelにアクセスする
  2. Create Spriteボタンを押す
  3. エディタが表示される
  4. 画面左のドロー・ツール(Pen)をクリックする
  5. 画面中央でクリックやドラッグする
  6. 画面右のSAVESave as .piskelボタンを押す
  7. JSONファイルがダウンロードされる
  8. 次回そのファイルをpiskelエディタにドラッグ&ドロップすると編集再開できる

 エディタの使い方については触ってみたほうが早いので省略します。

 piskelの強みはミラーペンです。反対方向にも同時に描けるので左右や上下に対照の絵を描く時に重宝します。

成果物

  • 16*16 pixcel
  • 背景色:透明
  • 前景色:赤

 男らしく赤一色です。

 画像サイズは16ピクセルと小さすぎるので、サイトで表示するときは8倍の256ピクセルにしました。

<img width="256" height="256" style="image-rendering: pixelated;" src="https://cdn-ak.f.st-hatena.com/images/fotolife/y/ytyaru/20250212/20250212115200.gif">

 上記はGIFアニメとして出力されたものです。

 piskelでは次のような形式で出力できます。

GIFアニメ

 ドット絵といえばアニメです。複数の画像を高速で差し替えたパラパラ漫画です。この一枚の画像をフレームと呼びます。

  1. piskelの画面右にあるAdd new frameを押下する
  2. 各フレームに絵を描く
  3. 画面右にアニメが表示される

 あとはこれをダウンロードするだけです。

  1. 画面右メニュー→EXPORTGIFDownloadを押す

.piskel形式(JSON形式)

 piskelのUIでは.piskel形式と言っていますが、ファイル名はNew Piskel.jsonでした。つまりJSONファイルです。その内容は以下です。

{"modelVersion":2,"piskel":{"name":"New Piskel","description":"","fps":12,"height":16,"width":16,"layers":["{\"name\":\"Layer 1\",\"opacity\":1,\"frameCount\":4,\"chunks\":[{\"layout\":[[0],[1],[2],[3]],\"base64PNG\":\"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEAAAAAQCAYAAACm53kpAAAAAXNSR0IArs4c6QAAAJtJREFUWEftV9ESgCAIg///aLse7DgiF3YGmb55E2VrQjL9fPBM/AtRqXyY6MTNwo9FErQ2+QIuSe/53plP5YAeNy8BelTLHKOtr3PVuFkorAJSN/IegBKIxpcA0V8g+vzpHOCtT6sLeBXLvt76YdM5yyKfzgFeAk9ryBABrlolaqGo1Y6IbwqAHhet64DeDugqvRU/xAGIXCZ8A2srdBE7SLvXAAAAAElFTkSuQmCC\"}]}"],"hiddenFrames":[""]}}

 このJSONファイルをpiskelのエディタにドラッグ&ドロップすれば、編集を再開できます。

 次のようなダイアログが出ます。「今の作業消えちゃうけど良いの?」ということなのでOKならボタンを押せば編集再開できます。

 JSON内にあるdataURI部分のみを抽出し、ブラウザのURL欄に入力すると、画像が復元されます。

data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAKZJREFUWEftl+EOgCAIhPH9H9rWj5qzA2TDYMz+lXPSd0dHjYKvFnw+vQV0oj4X02j/eh4CUVLkI3B7YdR+JuO9/iHgfYD2AqeAfCb8ux1rEuA6CT0XCYz5IH0bkGxatjx7akpgMbIrAU0ytO46D8zzw8q9KwEL+romtKbpScN6BKydUK8NUQhJPzzQAxpGz6kZSmDJcy6KUZGmeWA1zzlaq/vDTXgB6It0IRvncRQAAAAASUVORK5CYII=

 ちなみにSave in Browserのほうはブラウザに保存する方法です。

PNG形式(スプライトシート)

 piskelPNG形式は、スプライトシートになっています。すなわち、アニメーションに必要な複数枚の画像を一枚の画像にまとめたものです。

 今回作成したアニメは4枚の顔画像があります。それを1枚のPNG画像として保存しています。

 この4枚はアニメーションするとき順番に表示させる画像です。一枚あたりを「フレーム」と呼んでいます。

 一枚のPNG画像から各位置のフレームを抜き出すために、フレームあたりの幅、高さ、開始座標をJSONデータに記録してあります。

 わざわざ一枚のPNG画像にまとめたのは、そのほうが効率的だからです。

 ZIP形式でダウンロードすると、以下4枚の個別画像ファイルになります。

 ですが、尤もすばらしいのは以下です。

  1. piskelEXPORTPNGpixiJS Movie exportボタンがあります
  2. ここでInline SpriteSheet as data-urlに✔チェックします
  3. Downloadボタンを押下します

 次のようなJSONファイルがダウンロードされます。

{"frames":{"New Piskel0.png":{"frame":{"x":0,"y":0,"w":16,"h":16},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":16,"h":16},"sourceSize":{"w":16,"h":16}},"New Piskel1.png":{"frame":{"x":16,"y":0,"w":16,"h":16},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":16,"h":16},"sourceSize":{"w":16,"h":16}},"New Piskel2.png":{"frame":{"x":0,"y":16,"w":16,"h":16},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":16,"h":16},"sourceSize":{"w":16,"h":16}},"New Piskel3.png":{"frame":{"x":16,"y":16,"w":16,"h":16},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":16,"h":16},"sourceSize":{"w":16,"h":16}}},"meta":{"app":"https://github.com/piskelapp/piskel/","version":"1.0","image":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAKZJREFUWEftl+EOgCAIhPH9H9rWj5qzA2TDYMz+lXPSd0dHjYKvFnw+vQV0oj4X02j/eh4CUVLkI3B7YdR+JuO9/iHgfYD2AqeAfCb8ux1rEuA6CT0XCYz5IH0bkGxatjx7akpgMbIrAU0ytO46D8zzw8q9KwEL+romtKbpScN6BKydUK8NUQhJPzzQAxpGz6kZSmDJcy6KUZGmeWA1zzlaq/vDTXgB6It0IRvncRQAAAAASUVORK5CYII=","format":"RGBA8888","size":{"w":32,"h":32}}}

 dataURIにスプライトシートの画像があります。つまり、このJSONファイル内にPNG画像データが含まれています。あとはそれをBase64で解析してバイナリコードにし、それをPNG形式でデコードしてやれば、画像を再現できます。

 さらに、JSONにはフレーム画像ごとの座標やサイズがあります。取得したスプライト画像をこのデータに沿って分断すれば、各フレーム画像が取得できます。

 残念ながらFPSの情報が欠落しています。.piskel形式(JSON形式)のほうが良いでしょう。でもpiskelpixiJSに対応した形式にもエクスポートできますよ、という話です。

 試しにdataURIが示す画像ファイルをダウンロードするJavaScriptコードを書いてみました。

 下のdownloadボタンを押すと、4枚の顔があるスプライトシート画像がダウンロードされます。

window.addEventListener('DOMContentLoaded', async(event) => {
  document.querySelector('#download').addEventListener('click', async(e)=>{
    const dataUri = document.querySelector('#data-uri').value;
    let blob = await url2Blob(dataUri);
    download(blob);
  });
  async function url2Blob(url){return await (await fetch(url)).blob()}
  function download(blob, name='some.png'){
    var a = document.createElement("a");
    a.href = URL.createObjectURL(blob);
    a.target = '_blank';
    a.download = name;
    a.click();
  }
})

 ちなみにBlobからdataURIに変換するには以下メソッドを使います。

async function convert2DataUrl(blobOrFile){
    let reader = new FileReader()
    reader.readAsDataURL(blobOrFile)
    await new Promise(resolve => reader.onload = function(){ resolve() })
    return reader.result
}

 JSONの解析は以下。

const piskel = JSON.parse(`{"frames":{"New Piskel0.png":{"frame":{"x":0,"y":0,"w":16,"h":16},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":16,"h":16},"sourceSize":{"w":16,"h":16}},"New Piskel1.png":{"frame":{"x":16,"y":0,"w":16,"h":16},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":16,"h":16},"sourceSize":{"w":16,"h":16}},"New Piskel2.png":{"frame":{"x":0,"y":16,"w":16,"h":16},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":16,"h":16},"sourceSize":{"w":16,"h":16}},"New Piskel3.png":{"frame":{"x":16,"y":16,"w":16,"h":16},"rotated":false,"trimmed":false,"spriteSourceSize":{"x":0,"y":0,"w":16,"h":16},"sourceSize":{"w":16,"h":16}}},"meta":{"app":"https://github.com/piskelapp/piskel/","version":"1.0","image":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAKZJREFUWEftl+EOgCAIhPH9H9rWj5qzA2TDYMz+lXPSd0dHjYKvFnw+vQV0oj4X02j/eh4CUVLkI3B7YdR+JuO9/iHgfYD2AqeAfCb8ux1rEuA6CT0XCYz5IH0bkGxatjx7akpgMbIrAU0ytO46D8zzw8q9KwEL+romtKbpScN6BKydUK8NUQhJPzzQAxpGz6kZSmDJcy6KUZGmeWA1zzlaq/vDTXgB6It0IRvncRQAAAAASUVORK5CYII=","format":"RGBA8888","size":{"w":32,"h":32}}}`)
console.log(piskel)
console.log(piskel.meta.image); // dataURI

 あとはもう、やりたい放題です。

 アニメの再現や、PNG形式の解析・変更、フレーム画像切り抜き、ピクセル画像の編集など。

 手をかけるほど思い通りになっていき、可愛いですね〜。

 共感は得られないでしょう。知ってた。