猫の手ツール

Algorithm & UI/UX

ブラウザ完結型ウォーターマーク合成の裏側:文字のタイル配置と描画サイズの制御

透かしは、画像に名前や出典を視覚的に示す文字を重ねる機能です。タイル配置、背景色に合わせた影、読み込み時の縮小を使って、ブラウザ内で1枚の画像に合成します。

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

現行コードの確認日:

入力
画像と透かしにする文字、中央・右下・全体の配置を選びます。
処理
長辺を基準に文字サイズを決め、不透明度0.5の文字をCanvasへ重ねます。全体配置の間隔は測った文字幅で決めます。
出力
出力は長辺最大 2500px の JPEG(品質指定 0.95)。

まず確認する点:文字は保存画像の画素へ焼き付きます。長い文字のはみ出し、細かい背景での読みにくさを確認して、元画像とは別に保存します。

仕上がりの例

猫の写真に、斜めに繰り返す文字の透かしを加えた例です。

加工前・加工後
左はソファに座る茶トラの愛猫の写真。右は猫と背景に半透明の文字を繰り返し重ねた写真。

加工前・加工後

左はソファに座る茶トラの愛猫の写真。右は猫と背景に半透明の文字を繰り返し重ねた写真。

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

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

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

猫の写真全体に、半透明の「@猫の手」の文字を斜めに繰り返し配置した例です。

記録の入力画像
800×1207px (JPEG)
記録の出力画像
800×1207px (JPEG)

この作例には操作値の記録がないため、同じ設定で再現できるとは断定しません。本文の数値は現行の実装仕様です。

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

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

仕組みを読み進めるときは、Canvas APIと画像処理(画像寸法、drawImage、画素と透明度の扱い)、File APIとObject URL(選んだ画像の読み込みとBlob URLの解放)が参考になります。

1. 画像全体へ文字を置く「タイル配置」アルゴリズム

「タイル状の敷き詰め」は、画像の広い範囲に文字を重ねる配置です。AI 学習や透かしの除去を技術的に防ぐ保証はありません。本ツールでは、画像を回転させた状態でも隙間なく文字を埋め尽くすため、座標系の変換を用いた数学的なアプローチをとっています。

具体的には、Canvasの中心を軸にコンテキストを回転させ、画像の対角線長(diagonal)を基準にした広範囲なループ処理を行うことで、どのようなアスペクト比の画像でも、画面外から画面外まで均一にテキストを流し込むことが可能です。

回転するタイルの描画範囲を決める対角線長です。実装では中心を原点にして −30° 回転して描きます。

function watermarkSpacing(ctx, text, width, height, fontSize) {
  return { diagonal: Math.hypot(width, height),
    stepX: ctx.measureText(text).width * 2, stepY: fontSize * 4 };
}

2. 視認性を担保する「動的コントラスト・シャドウ」

透かし文字は、背景が白でも黒でも認識できる必要があります。本ツールでは、ユーザーが選択した文字色に応じて、反対色のシャドウをリアルタイムで生成しています。

さらに工夫した点は、シャドウの強さ(shadowBlur)を画像サイズに比例させて動的に計算している点です。これにより、小さなサムネイル画像から巨大なイラストまで、文字の周りに反対色の影を描きます。背景の模様や文字の長さによっては読みづらくなるため、結果を確認します。

3. 高解像度画像への耐性とブラウザメモリの保護

昨今のスマートフォンで撮影された写真は非常に高解像度であり、そのままCanvasで処理するとブラウザのメモリ不足によるクラッシュ(特にiOS)を招く恐れがあります。

本ツールでは、長辺 2500px の上限を設け、読み込み時にアスペクト比を維持したまま、処理可能な上限サイズへダウンスケールを行っています。このハックにより、後続の描画に使う画素数を減らします。読み込みや変換が必ず成功するという意味ではありません。

出力の仕様と確認する点

位置は中央・右下・全体の敷き詰めを選べます。不透明度は 0.5 固定、文字サイズは長辺に対して中央 8%、右下 5%、全体 4%。任意の位置へドラッグする機能や画像ロゴの読み込みはありません。

全体配置は文字幅の2倍を横間隔、文字サイズの4倍を縦間隔にします。長い文字ほど間隔も広がり、中央・右下では画像端からはみ出す場合があります。空欄は @Sample として扱います。

出力は長辺最大 2500px の JPEG(品質指定 0.95)。透かしは画素に焼き付く文字であり、無断利用・学習・切り抜き・除去を阻止する仕組みではありません。元画像とは別に保存して使ってください。