LINEスタンプ用の画像を、規定サイズに切り抜くためだけのツールを作りました。スタンプサイズメーカーといいます。
やることは2つだけです。決められた3つのサイズにぴったり書き出すことと、縁の余白(セーフゾーン)を色付きで表示すること。それ以外の機能はありません。
機能を絞ったのには理由があって、そのあたりの判断と、実装で引っかかったところを書き残しておきます。個人開発の記録としても、あとで自分が読み返す用としても。
なお、LINEスタンプの画像サイズそのものについては副業ベースの記事にまとめてあるので、規定を知りたいだけの方はそちらへどうぞ。
きっかけは「AIで絵は作れるのに、そこから進まない」

ChatGPTで背景透過のイラストが作れるようになりました。プロンプトを工夫すれば、スタンプに使えそうなキャラクターがそれなりに返ってきます。
じゃあそのまま申請できるかというと、できないんですよね。LINEスタンプには決まったサイズがあって、スタンプ画像は最大370×320px、メイン画像は240×240px、タブ画像は96×74px。しかも縁から10pxくらいは余白を空けるように、とガイドラインに書かれている。
パソコンがあればPhotoshopなりGIMPなりで済む話です。でも、スマホしか持っていない人にとってはここが壁になります。
調べてみると、この壁は思ったより厚い。まず、ピクセル単位でサイズを指定できるスマホアプリが少ない。写真加工が前提のアプリは「正方形」「16:9」といった比率でしか切り抜けないものが多くて、「370×320px」という指定ができない。
そして決定的なのが、Canvaで透過PNGとしてダウンロードするのは有料プランの機能だということ。サイズを合わせるところまではCanvaでできるのに、書き出すと白背景になる。せっかく透過で作った画像が台無しです。
結果、「透過するアプリ」「サイズを合わせるアプリ」「余白を確認するアプリ」を行き来することになる。40枚のスタンプで毎回それをやるのは、ちょっと無理があります。
AIが絵を作る部分を担ってくれるようになったぶん、その先の「規格に合わせる」という地味な工程がボトルネックとして浮き上がってきた。そこだけを取り除く道具があればいい、と考えました。
先に「作らないもの」を決めた
このツールで意識的に外した機能があります。
- 画像の加工(フィルター、明るさ調整、文字入れ)
- 背景の透過処理
- 縦横比の自由な指定
- 複数枚の一括書き出し
透過処理を入れなかったのは、そこはもうChatGPTや専用アプリの領域だからです。中途半端な切り抜き機能を足しても、誰も使わない。入口を「透過済みの画像を持っている人」に限定するかわりに、その人に対しては完璧に動く、という設計にしました。
サイズを自由に指定できるようにしなかったのも同じ理由です。自由に指定できるツールなら既に世の中にたくさんある。むしろ選択肢が3つしかないことが、このツールの価値だと思っています。「370って何だっけ」と調べ直す必要がないので。
一括書き出しは、スマホだと保存ダイアログが枚数ぶん出てきて逆に面倒になるので外しました。1枚ずつ確実に落とす導線に振り切っています。
機能を足すたびに、初めて使う人が迷う可能性が増えます。ツールの善し悪しは、機能の数ではなく「最初の30秒で目的を達成できるか」で決まる。今回はそこだけを見て判断しました。
セーフゾーンをどう見せるか
このツールの本体と言っていい部分です。
余白10pxというのは、数字で言われてもピンとこない。370×320pxのキャンバスに対する10pxがどのくらいなのか、頭の中で想像するのは難しい。だから見えるようにする必要がありました。
やり方としては、キャンバス全体を覆う矩形と、内側の安全領域の矩形、この2つを1つのパスにまとめて evenodd で塗っています。
ctx.beginPath();
ctx.rect(0, 0, W * k, H * k);
ctx.rect(inset * k, inset * k, (W - inset * 2) * k, (H - inset * 2) * k);
ctx.fill("evenodd");
evenodd は、重なった領域を打ち消す塗り方です。これで外側の帯だけが塗られて、内側は透明のまま残る。ドーナツ状の塗りを1回のパスで作れるので、余計な計算がいりません。この上に破線の境界を引いて完成です。
色は最初オレンジにしていましたが、サイトのUIを紫と水色でまとめた段階で浮いてしまったのでピンクに変えました。市松模様(透明部分の表現)の上でも視認できて、イラストに使われている色ともぶつかりにくい色、という条件で選んでいます。
余白の幅はスライダーで変えられます。タブ画像だけ初期値を5pxにしてあるのがポイントで、これは公式ガイドラインにタブ画像の余白の記載がないためです。96×74pxで10px取ると使える範囲が76×54pxまで縮んでしまうので、5pxを初期値にして、必要なら広げてもらう形にしました。
ピンチ操作は、自分で書く必要がある
スマホ前提のツールなので、2本指での拡大縮小は必須でした。これ、ブラウザが勝手にやってくれそうな気がしますが、やってくれません。
理由は、キャンバス上でページ全体のピンチズームを止めているからです。止めないと、画像を動かそうとした瞬間にページごと拡大されて操作になりません。touch-action: none を指定して、ブラウザ標準のジェスチャーを無効化する。そのかわり、2本指の動きを自分で解釈する必要が出てきます。
やっていることは単純で、Pointer Eventsで触れている指をMapに保持して、2本あるときは距離と中点を計算します。
function gesture(){
var a = []; pointers.forEach(function(v){ a.push(v); });
if (a.length >= 2) {
var dx = a[0].x - a[1].x, dy = a[0].y - a[1].y;
return { d: Math.sqrt(dx*dx + dy*dy),
mx: (a[0].x + a[1].x) / 2,
my: (a[0].y + a[1].y) / 2 };
}
return { d: 0, mx: a[0].x, my: a[0].y };
}
前フレームとの距離の比が拡大率、中点の差が平行移動になります。指が1本のときは距離が0になるので、そのまま移動だけが効く。この形にしておくと、途中で指を1本離しても画像が飛びません。
拡大するときは、中点の位置を固定したままスケールを変える必要があります。指で挟んだ場所が動かないようにするやつです。
s.x = (ox - p.w/2) - ratio * ((ox - p.w/2) - s.x);
ox が中点のキャンバス座標、ratio が新旧のスケール比。この1行を X と Y に対して書くだけで、狙った点を軸にした拡大縮小になります。ここは何度も書いているはずなのに、毎回符号で迷います。
画像をサーバーに送らない
処理は全部ブラウザの中で完結させています。読み込んだ画像がサーバーに行くことはありません。
技術的には、FileReader すら使わずに URL.createObjectURL() で Image に読ませて、Canvasに描いて、canvas.toBlob() でPNGを取り出すだけです。難しいことはしていません。
ただ、これは技術選定である以上に、信用の設計だと思っています。
自分の描いたイラストを、どこの誰が運営しているか分からないサイトにアップロードするのは、けっこう抵抗があるはずです。ましてやこれから販売しようとしている作品なら。「送信されません」と書いてあることが、使う前の不安を消します。
Toolipsのときにも同じ方針を取りましたが、ブラウザ完結には副次的な利点もあって、サーバー費用がゼロになる。静的ファイルを置くだけなので、アクセスが増えても運用コストが上がらない。個人開発でツールを増やしていくなら、この形がいちばん続けやすいと思っています。
透過されていない画像を読み込んだときに警告を出す機能も付けました。64pxに縮小して描画して、アルファ値を走査するだけです。
var d = x.getImageData(0, 0, n, n).data;
for (var i = 3; i < d.length; i += 4) {
if (d[i] < 250) return true;
}
return false;
全ピクセルが不透明なら「透過されていません」と表示します。iOSの写真ピッカー経由でPNGがJPEGに変換されてしまうケースがまだあるので、その保険です。ユーザーが原因を自力で切り分けられない種類の失敗は、ツール側で拾ったほうがいい。
スマホで一度、盛大に崩れた
実機で確認したら、レイアウトが画面からはみ出していました。「画像を選ぶ」ボタンが画面外にあって、そもそも操作を始められない状態です。
原因はCSS Gridでした。grid-template-columns: 1fr のトラックは、最小値が auto(=min-content)になります。つまり中に縮まない要素があると、画面幅を無視してトラックごと広がる。画像を読み込む前のキャンバスが370px固定で置いてあったので、それが引き金になっていました。
対処は3つ重ねました。グリッドの子に min-width: 0 を指定する。プレビューの表示サイズを親要素からではなく document.documentElement.clientWidth から逆算する。そして画像を読み込む前はキャンバス自体を置かない。
3つめが本質的な解決です。親から計算すると、はみ出した幅を基準にしてさらにはみ出す、という悪循環になり得るので、原因そのものを消しました。空の状態でアップロードボタンだけが大きく出るようになって、UIとしても分かりやすくなっています。
ほかにも実機で分かったことがいくつか。iOSはフォントサイズが16px未満の入力欄にフォーカスすると勝手にズームするので、ファイル名の入力欄は16pxにしています。画面下に固定したバーは env(safe-area-inset-bottom) を足さないとホームバーに潜り込む。このへんは毎回やっているのに毎回忘れます。
デザインは4回作り直した

これが今回いちばん時間を使ったところかもしれません。
最初はカッティングマット風にしました。トリミングツールだから切り取りマット、という連想です。深緑の背景にグリッド、丸ゴシック、オレンジのアクセント。狙いは分かりやすいけど、見せたら「一昔前のサイトみたい」と言われました。まったくその通りで、装飾でテーマ性を出そうとすると古くなるんですよね。
2回目はミニマルに振りました。ほぼ白、影を消して1pxの罫線、余白で構造を見せる。今度は「さっぱりしすぎ」。正しいけど面白くない、という状態です。
3回目でダークにして、背景に光の塊をゆっくり漂わせる形にしました。ガラス質のパネル、グラデーションの見出し、等幅フォントの英字ラベル。いわゆるテック系の質感です。
ここで指摘されたのが、日本の一般ユーザーにとって黒い背景のサイトは「怪しい」と受け取られかねないという点。言われてみればその通りで、副業ブログから流入してくる読者層を考えると、これはリスクです。
最終的に4回目で、動きとガラス質はそのまま、土台を白に反転させました。淡いラベンダー・水色・桜色が漂う背景に、すりガラスのパネル。動きがあるので退屈にならず、白ベースなので身構えられない。
「洗練されている」と「安心できる」は別軸で、ツールサイトでは後者を優先すべき場面がある、というのが今回の学びです。かっこよさを追うと、対象読者から離れることがある。
公開してから
サイト構成は、ツール本体・使い方・利用規約・プライバシーポリシーの4ページ。これはToolipsやかんたん表メーカーのときと同じ型で、そのまま流用しています。CSSは共通ファイルに切り出して ?v= でバージョン管理。
広告は自動広告を使わず、操作の流れから外れた2か所にだけ手動で配置しました。自動広告はキャンバスの真上に差し込まれたり、スマホの画面下に貼り付いて保存ボタンと重なったりするので、ツールサイトとは相性が悪いと判断しています。
作ってみて改めて思ったのは、個人開発でいちばん効くのは「自分が困ったこと」を起点にすることだなと。今回は僕自身がスタンプを作ろうとして詰まったところから始まっているので、何が本当に面倒なのかを考える必要がありませんでした。
ツールは無料で公開しています。LINEスタンプを作る予定のある方は、よかったら使ってみてください。
関連記事
※「LINE」はLINEヤフー株式会社の商標または登録商標です。スタンプサイズメーカーは個人が運営する非公式のツールで、同社とは一切関係ありません。



