生成画像をドット絵に落とす:手で直す場所
遊びをつくる執筆にClaudeを使用しています。

生成した画像を縮小して色数を減らせば、見た目はドット絵に近づきます。ただ、そのまま使える仕上がりになるのか、どこかに必ず手直しが要るのかは、画像を一枚ずつ見てみないと分かりません。この記事の問いは「自動変換の結果のうち、どの種類の乱れが手直しの対象になり、どれは放っておけるのか」です。 32×32に縮めたキャラクターを画面に並べる場面を考えてみます。全体の印象は悪くないのに、目が一つの点に潰れていたり、輪郭の一部が途切れていたりすることがあります。逆に、遠目では気になる箇所が、ゲーム画面の実寸ではまったく目立たないこともあります。この「直すべき乱れ」と「見逃してよい乱れ」の線引きを、自分の画像で決められるようにするのがねらいです。 以下は結果の報告ではなく、読者が自分で行うための実験の設計書です。小さなHTMLで自動変換を再現し、出力を観察して「手直しの種類」を分類します。数値や傾向は、手元の画像で記録して初めて意味を持ちます。
問いを三つに分ける
「手直しが必要か」という問いは大きすぎます。次の三つに分けると、記録が取りやすくなります。
- 形の問い:輪郭、目、指、小物など、細く小さい部分が判読できるか。
- 色の問い:減色で肌や影の階調がつぶれていないか。隣り合う色が近すぎて境目が消えていないか。
- ノイズの問い:本来は連続しているはずの面に、孤立した1ピクセルが散らばっていないか。
縮小は面積の平均を取るため、細い線や小さな目は周囲の色に混ざりやすいはずだ、という予想は立てられます。ただ、これは予想であって結果ではありません。画風や背景によって外れることもあるので、予想を紙に書いてから観察すると、外れ方も記録に残せます。
準備するもの
- 生成画像を3枚以上。キャラクター、背景小物、文字入りの看板など、細部の種類が違うものを混ぜます。
- 下のHTMLを保存したファイルと、ブラウザ。外部ライブラリは使いません。
- 手直し用のドット絵エディタ(普段使っているもので構いません)。
- 記録用の表(次々節)とストップウォッチ。
生成画像の利用条件は、使ったサービスの規約で変わります。ゲームに入れる前に、そのサービスの公式案内で商用利用や再配布の可否を確認してください。法的な判断が必要な場合は、専門家への相談も検討します。
手順
1. 自動変換の道具を用意する
次のコードを dot.html として保存し、ブラウザで開きます。画像を選ぶと、長辺を指定サイズに縮小し、k-means法(色を近いものどうしでまとめる方法)で指定の色数に減らして、整数倍に拡大表示します。拡大時は補間を切っているので、ピクセルの境目がそのまま見えます。
<input type="file" id="f" accept="image/*">
サイズ<input type="number" id="n" value="32" min="8" max="128">
色数<input type="number" id="k" value="8" min="2" max="32">
<a id="a" download="dot.png" href="#">等倍で保存</a><br>
<canvas id="c"></canvas>
<script>
const $=id=>document.getElementById(id);
$('f').onchange=()=>{const i=new Image();i.onload=()=>run(i);i.src=URL.createObjectURL($('f').files[0]);};
$('n').onchange=$('k').onchange=()=>{if(window.im)run(im)};
function run(i){
window.im=i;
const n=+$('n').value,k=+$('k').value,s=n/Math.max(i.width,i.height);
const w=Math.max(1,Math.round(i.width*s)),h=Math.max(1,Math.round(i.height*s));
const t=document.createElement('canvas');t.width=w;t.height=h;
const x=t.getContext('2d');x.imageSmoothingQuality='high';x.drawImage(i,0,0,w,h);
const d=x.getImageData(0,0,w,h),p=d.data,px=[];
for(let j=0;j<p.length;j+=4)px.push([p[j],p[j+1],p[j+2]]);
let c=[];for(let j=0;j<k;j++)c.push(px[Math.floor(j*px.length/k)].slice());
const near=q=>{let b=0,m=1e9;c.forEach((u,j)=>{const e=(u[0]-q[0])**2+(u[1]-q[1])**2+(u[2]-q[2])**2;if(e<m){m=e;b=j}});return b};
for(let r=0;r<8;r++){const sum=c.map(()=>[0,0,0,0]);
px.forEach(q=>{const b=near(q),a=sum[b];a[0]+=q[0];a[1]+=q[1];a[2]+=q[2];a[3]++});
sum.forEach((a,j)=>{if(a[3])c[j]=[a[0]/a[3],a[1]/a[3],a[2]/a[3]]})}
px.forEach((q,j)=>{const u=c[near(q)];p[j*4]=u[0];p[j*4+1]=u[1];p[j*4+2]=u[2];p[j*4+3]=255});
x.putImageData(d,0,0);$('a').href=t.toDataURL();
const o=$('c'),z=Math.max(1,Math.floor(512/Math.max(w,h)));
o.width=w*z;o.height=h*z;
const g=o.getContext('2d');g.imageSmoothingEnabled=false;g.drawImage(t,0,0,w*z,h*z);
}
</script>このコードは透明部分を考慮せず、すべて不透明にします。透過PNGを読み込むと、背景が単色で塗りつぶされることがあります。透過の扱いは、手直しの段階でエディタ側で行います。
2. 条件を決めて変換する
最初の条件は、サイズ32、色数8とします。同じ画像で、次のように条件を一つずつ変えます。
- サイズ:32、48、64
- 色数:4、8、16
一度に二つを動かすと、乱れの原因が分からなくなります。サイズを変えるときは色数を8に固定し、色数を変えるときはサイズを32に固定してください。
3. 拡大画面で観察して、乱れに印を付ける
拡大表示のまま、画面を見て次の三種の乱れを探します。
- 途切れ:本来つながっている輪郭や線が、1ピクセル以上切れている箇所。
- 孤立点:周囲8マスのどれとも同じ色でない、1ピクセルだけの点。
- 潰れ:目や指などの重要部位が、判読できなくなっている箇所。
次に、ブラウザの拡大率を下げるか、画面から離れて、ゲーム内の実寸に近い大きさで見ます。拡大では目立つのに実寸では気にならない乱れは、手直しの優先度を下げる候補です。
4. 手直しして時間を測る
「等倍で保存」でPNGを保存し、エディタで開きます。印を付けた乱れを直し、完了までの時間を分単位で記録します。途中で作業内容が変わったら、その区切りごとに記録を分けると、あとで「どの種類の乱れに時間がかかったか」が読み取れます。
記録の取り方
画像ごと、条件ごとに1行ずつ、次の表で記録します。
- 画像名・条件、記録する内容:サイズと色数、単位・方法:例:A/32/8
- 途切れ、記録する内容:輪郭が切れた箇所の数、単位・方法:箇所
- 孤立点、記録する内容:周囲と同色でない1ピクセルの数、単位・方法:個(目視で数える)
- 潰れ、記録する内容:判読できない重要部位、単位・方法:部位名(目、手など)
- 実寸での気づき、記録する内容:実寸で見て気になったか、単位・方法:あり/なし
- 手直し時間、記録する内容:直すのにかかった時間、単位・方法:分
回数の目安は、3枚の画像に対して、サイズ3条件と色数3条件で、合計およそ5条件(共通の32/8を含む)です。つまり15行ほどになります。孤立点の目視カウントは数え間違いが出やすいので、同じ画像を日を置いて2回数えると、ぶれの幅が分かります。
結果の読み方
数字が出たら、次の基準で読んでみてください。基準の数値は目安であり、自分のゲームの画面サイズに合わせて調整します。
- 同じ種類の乱れが、3枚中2枚以上に出る:変換の仕組み(縮小と減色)に由来する可能性が高いです。条件を変えても残るなら、手直しを最初から工程に組み込む対象と考えます。
- 特定の1枚にだけ出る:画像の描き込み(細すぎる線、小さすぎる模様)に由来する可能性があります。変換条件ではなく、元画像を作り直す選択肢も浮かびます。
- サイズを上げると乱れが減る:そのサイズがゲームの用途に許されるなら、手直しより解像度で解決できます。許されないなら、手直しに進みます。
- 色数を上げても乱れが減らない:原因は色ではなく、縮小で情報が失われている可能性があります。色数の調整は後回しにしてよい合図です。
- 拡大では気になるが実寸では気にならない:直さない判断が成り立ちます。手直し時間を、実寸でも目立つ箇所に回します。
手直し時間は、「自動変換+手直し」の合計と、自分でゼロから描く場合の見積もりを比べる材料になります。ゼロから描く時間は、実際に1枚描いて測るか、見積もりとして別欄に書き分けてください。見積もりと実測を混ぜないことが大切です。
起こりやすい誤り
- 拡大時の補間を切り忘れる:補間が効くとピクセルがにじみ、ドット絵の判断ができません。上のコードは切っていますが、別のツールで見るときは注意が必要です。
- 整数倍でない拡大:2.5倍のような拡大は、ピクセルの幅が不揃いになり、途切れや孤立点の見え方が変わります。
- 条件を同時に変える:サイズと色数を同時に動かすと、原因の切り分けができません。
- 1枚だけで判断する:画風や背景で結果が大きく変わりやすいため、最低3枚は見ます。
- 透過の扱いを忘れる:背景が単色で塗りつぶされた状態でゲームに組み込むと、キャラクターの周りに四角が残ります。
- 規約の確認を後回しにする:手直し後の画像でも、元画像の利用条件は引き継がれる可能性があります。公開前に、元のサービスの案内で確認してください。
次の行動
手元の生成画像を3枚選び、サイズ32・色数8から、記録表の1行目を埋めてみてください。表が埋まったら、手直しが必要だった乱れの種類を並べ、自分の画風でいちばん多かった種類から工程に組み込みます。ゲームに入れるときは、PNGを相対パスで参照し、直下の index.html を入口にしてZIPにまとめると、アソバースへ投稿できます(アップロードは20MiB以内です)。
