この記事は、 Jasmine Tea アドベントカレンダー 2023 の第22日目です。
こんにちは!Jasmine Tea の開発に参加している松尾です。
なんとなく、季節柄か Jasmine Tea でサンタ🎅を表示したいと思ったのでやってみました。
Jasmine Tea には、PIC パターンという仕組みがあります。これは 16x16 のイメージデータが予めいくつも登録してあり、PIC パターンの番号を指定するだけで登録済みのイメージを画面に表示することができる仕組みです。これより高次の機能であるスプライトやアニメーションの元になっています。
また、Jasmine Tea のユーザーは独自の PIC パターンを登録することもできます。これには data
命令を使うようです。下記のような感じです。
Jasmine Tea のドキュメントからの抜粋
p@=[]
for i=0 to 255
read p@[i]
next
def pic 532,p@
put (100,100),532
end
data -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
data -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
data -1,-1,-1, 3, 3,-1,-1,-1,-1,-1,-1, 3, 3,-1,-1,-1
data -1,-1, 3, 3, 3, 3,-1,-1,-1,-1, 3, 3, 3, 3,-1,-1
data -1,-1, 3, 3, 3, 3, 3,-1,-1, 3, 3, 3, 3, 3,-1,-1
data -1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,-1
data -1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,-1
data -1,-1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,-1,-1
data -1,-1,-1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,-1,-1,-1
data -1,-1,-1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,-1,-1,-1
data -1,-1,-1,-1, 3, 3, 3, 3, 3, 3, 3, 3,-1,-1,-1,-1
data -1,-1,-1,-1,-1, 3, 3, 3, 3, 3, 3,-1,-1,-1,-1,-1
data -1,-1,-1,-1,-1,-1, 3, 3, 3, 3,-1,-1,-1,-1,-1,-1
data -1,-1,-1,-1,-1,-1,-1, 3, 3,-1,-1,-1,-1,-1,-1,-1
data -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
data -1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1
なるほど。data から 256 個のピクセルを配列に読んで def pic
命令で登録するわけですね。Jasmine Tea で使用できるカラーパレットはあまり多くないので、色のマッピングをしてあげないといけないようですね。
js でチャチャッとスクリプトを書いてマッピングできるようにしてみましょう。
interface color {
r: number,
g: number,
b: number,
}
const colors: { [key: number]: color } = {
0: { r: 0, g: 0, b: 0 },
1: { r: 0, g: 0, b: 255 },
2: { r: 255, g: 0, b: 0 },
3: { r: 255, g: 0, b: 255 },
4: { r: 0, g: 255, b: 0 },
5: { r: 0, g: 255, b: 255 },
6: { r: 255, g: 255, b: 0 },
7: { r: 255, g: 255, b: 255 },
8: { r: 119, g: 119, b: 119 },
9: { r: 0, g: 0, b: 170 },
10: { r: 170, g: 0, b: 0 },
11: { r: 170, g: 0, b: 170 },
12: { r: 0, g: 170, b: 0 },
13: { r: 0, g: 170, b: 170 },
14: { r: 170, g: 170, b: 0 },
15: { r: 170, g: 170, b: 170 },
16: { r: 77, g: 129, b: 166 },
17: { r: 78, g: 60, b: 60 },
18: { r: 86, g: 98, b: 208 },
19: { r: 87, g: 164, b: 254 },
20: { r: 97, g: 166, b: 75 },
21: { r: 124, g: 210, b: 207 },
22: { r: 138, g: 218, b: 255 },
23: { r: 139, g: 131, b: 129 },
24: { r: 142, g: 76, b: 80 },
25: { r: 152, g: 128, b: 248 },
26: { r: 161, g: 112, b: 142 },
27: { r: 172, g: 148, b: 124 },
28: { r: 198, g: 192, b: 192 },
29: { r: 205, g: 217, b: 59 },
30: { r: 210, g: 191, b: 161 },
31: { r: 238, g: 146, b: 43 },
32: { r: 240, g: 112, b: 182 },
33: { r: 245, g: 84, b: 64 },
34: { r: 248, g: 157, b: 156 },
35: { r: 249, g: 232, b: 216 },
36: { r: 250, g: 205, b: 80 },
37: { r: 251, g: 232, b: 42 },
};
function getClosestColorNumber(c: color): number {
let smallestDiff = 255 * 3;
let ret = 0;
for (const n in colors) {
const target = colors[n];
const diff =
Math.abs(c.r - target.r)
+ Math.abs(c.g - target.g)
+ Math.abs(c.b - target.b);
if (diff < smallestDiff) {
smallestDiff = diff;
ret = parseInt(n, 10);
}
}
return ret;
}
あとは画像データを Jasmine Tea の data
命令に変換してあげれば良さそうです。今回は便利そうな Jimp というライブラリを使いました。
(async () => {
const j = await Jimp.read(args[2]);
const result: number[][] = [];
for (let y = 0; y < 32; y++) {
result.push([]);
for (let x = 0; x < 32; x++) {
const c = j.getPixelColor(x, y);
const rgb = Jimp.intToRGBA(c);
const colorNumber = getClosestColorNumber(rgb);
result[y].push(colorNumber);
}
}
// Top left
for (let y = 0; y < 16; y++) {
console.log(`data ${result[y].slice(0, 16).join(',')}`);
}
// Top right
for (let y = 0; y < 16; y++) {
console.log(`data ${result[y].slice(16, 32).join(',')}`);
}
// Bottom left
for (let y = 16; y < 32; y++) {
console.log(`data ${result[y].slice(0, 16).join(',')}`);
}
// Bottom right
for (let y = 16; y < 32; y++) {
console.log(`data ${result[y].slice(16, 32).join(',')}`);
}
})();
アルファチャンネルの処理をしてないので、透明なところの表現ができてないですが、まあいいでしょう。こんな感じでJasmine Tea でサンタクロースを表示することができました〜
それでは、メリークリスマス🎅