猫の手ツール

Canvas Compositing & Filtering

写真をインクに「刷り込む」ためのレイヤー合成テクニック

ただ写真をセピアにするだけでは、「紙にインクが染み込んだ」という質感は生まれません。本ツールで採用している、乗算合成と動的なインク滲みを再現するアルゴリズムについて解説します。

このツールの入力から出力まで

現行コードの確認日:

入力
写真を選び、紙・インクの濃さ・滲みを指定します。
処理
縮小画像をずらして重ね、multiply合成でインクを着色し、紙色の背景へ描きます。
出力
長辺 2000px 以下の入力を使い、1000×1000px の JPEG(品質指定 0.85)にします。

まず確認する点:source-overの5回重ねは単純平均ではありません。滲みの値は濃さにも関わるため、滲み0と小さな値で比較します。

仕上がりの例

写真を古い手紙の挿絵風に加工した例です。

加工前・加工後
左は愛猫2匹が並ぶ写真。右は茶色い紙の中央に淡い猫の画像を配置した完成例。

加工前・加工後

左は愛猫2匹が並ぶ写真。右は茶色い紙の中央に淡い猫の画像を配置した完成例。

掲載画像はサイトにある既存の公開作例です。保存済みの資料では運営者の愛猫の写真を使用しています。今回の確認日が、この作例を実行した日を表すわけではありません。

保存済み検証記録の条件を見る

資料の種類は「ツールの出力画像を保存した記録」です。公開作例と保存済み記録で素材や色などが異なる場合があるため、下の数値は保存済み検証記録の条件として読んでください。

記録の入力画像
800×667px (JPEG)
記録の出力画像
1000×1000px (JPEG)
保存済み記録の主な操作・出力条件
画面の項目記録の値現行コードの初期値・範囲
記録で選択されていた項目日焼け—
インクの濃さ80初期値 80 / 範囲 10〜100
インクの滲み2初期値 2 / 範囲 0〜10
写真のズーム80初期値 80 / 範囲 10〜300

記録では「古い手紙風に加工!」から完成表示へ進んでいます。初期値と記録値を比べてから、効果を1項目ずつ変えると作用を確認しやすくなります。

資料ファイルの作成日は実行日として扱っていません。個別端末の処理速度や、ほかの写真に対する検出・加工の精度を測定した資料でもありません。

実装の確認箇所:src/pages/image/ink-letter/index.astro。以下のコード抜粋と出力条件は、この本番実装に基づいて説明します。

仕組みを読み進めるときは、Canvas APIと画像処理(画像寸法、drawImage、画素と透明度の扱い)、メモリ管理と画像処理(画素バッファ、縮小と容量予算)が参考になります。

1. 乗算(Multiply)とカラー合成の分離構造

このツールの最大の特徴は、インクの「濃淡(明暗)」と「色(セピア)」を別々のレイヤーとしてCanvasに合成している点です。

まず写真をグレースケール化して「インクの乗り」を抽出し、それを globalCompositeOperation = 'multiply' で羊皮紙の背景に重ねます。これにより、紙のテクスチャの暗い部分と写真が美しく馴染みます。その上からさらにカラー情報を重ねることで、深みのあるアンティーク調を実現しています。

滲み設定から縮小率とずらし幅を計算する例です。実装は中央と4つの対角方向に5回重ねます。

function inkBlurSettings(amount) {
  return { scale: 1 / (amount * 0.3 + 1), spread: amount * 1.5,
    offsets: [[0, 0], [1, 1], [-1, -1], [1, -1], [-1, 1]] };
}

この「明暗」と「色」の分離により、ユーザーがインクの濃さを調整しても、セピアの絶妙な色合いが崩れることなく、紙色とインクの濃さを別々に調整できます。見た目は写真の明暗によって変わります。

2. 軽量な「疑似ブラー」によるインク滲みの再現

紙にインクが染み込むと、エッジがわずかにぼやけます。これを標準の filter: blur() で行うと非常に重くなるため、本ツールでは「画像を低解像度化してから戻す」ハックと「微細な多重描画」を組み合わせています。

この手法のメリットは、高価な畳み込み演算(ガウスぼかし等)を回避しつつ、アナログ特有の「インクが広がるムラ」を縮小画像をずらして重ねる処理で近似できる点にあります。描画負荷は端末によって異なります。

3. モバイル環境向けの「メモリ・セーフティ」処理

数千万画素の写真をブラウザでそのまま処理すると、端末によってはメモリ上限に達する場合があります。

本ツールでは、画像の読み込み直後に長辺をチェックし、一定の閾値を超える場合にはアスペクト比を保ちながら動的にリサイズし、後続の描画に使う画像を小さくするガードレールを実装しています。

出力の仕様と確認する点

長辺 2000px 以下の入力を使い、1000×1000px の JPEG(品質指定 0.85)にします。写真はドラッグで移動、10〜300% のズームで紙面内の大きさを変えられます。

滲み 0 では1回描画し、1〜10 では縮小画像を透明度 0.2 で5回重ねます。source-over の重ね合わせなので5枚の単純平均ではなく、滲みの強さで濃さや周辺の透明度も変わります。

紙の種類は背景色とインクの着色を変え、インク濃度は multiply 合成の不透明度を変えます。実際の紙の繊維やインクの吸収を解析する処理、文字への変換機能はありません。

制作時に確かめたこと