Algorithm & UI/UX
ブラウザ完結型ウォーターマーク合成の裏側:AI学習対策とパフォーマンスの両立
クリエイターの権利を守るための「透かし合成ツール」。その実装には、単なる画像合成に留まらない、ブラウザ負荷への配慮と高度な自衛技術が詰め込まれています。
1. AI学習を阻害する「タイル配置」アルゴリズム
昨今のAI学習対策として有効な「タイル状の敷き詰め」は、単純なグリッド描画では不十分です。本ツールでは、画像を回転させた状態でも隙間なく文字を埋め尽くすため、座標系の変換を用いた数学的なアプローチをとっています。
具体的には、Canvasの中心を軸にコンテキストを回転させ、画像の対角線長(diagonal)を基準にした広範囲なループ処理を行うことで、どのようなアスペクト比の画像でも、画面外から画面外まで均一にテキストを流し込むことが可能です。
// タイル状にテキストを敷き詰めるコアロジックの概要
function drawTileWatermark(ctx, text, w, h) {
const diagonal = // 画像の対角線長を計算
ctx.save();
ctx.translate(w / 2, h / 2);
ctx.rotate(// 独自のチューニングされた回転角);
for (let x = -diagonal; x < diagonal; x += // テキスト幅に基づく独自のステップ値) {
for (let y = -diagonal; y < diagonal; y += // フォントサイズに基づく独自のステップ値) {
ctx.fillText(text, x, y);
}
}
ctx.restore();
} 2. 視認性を担保する「動的コントラスト・シャドウ」
透かし文字は、背景が白でも黒でも認識できる必要があります。本ツールでは、ユーザーが選択した文字色に応じて、反対色のシャドウをリアルタイムで生成しています。
さらに工夫した点は、シャドウの強さ(shadowBlur)を画像サイズに比例させて動的に計算している点です。これにより、小さなサムネイル画像から巨大なイラストまで、常に最適な視認性を維持できるよう調整しています。
// 文字色に応じた影の最適化処理
ctx.shadowColor = selectedColor === '#ffffff' ?
'rgba(0,0,0, 独自のアルファ値)' :
'rgba(255,255,255, 独自のアルファ値)';
// 画像サイズ(w)に比例したシャドウの強さ設定
ctx.shadowBlur = Math.max(4, Math.floor(w * // 独自の補正係数));
ctx.shadowOffsetX = 0;
ctx.shadowOffsetY = 0; 3. 高解像度画像への耐性とブラウザメモリの保護
昨今のスマートフォンで撮影された写真は非常に高解像度であり、そのままCanvasで処理するとブラウザのメモリ不足によるクラッシュ(特にiOS)を招く恐れがあります。
本ツールでは、内部的な「安全閾値」を設け、読み込み時にアスペクト比を維持したまま、処理可能な上限サイズへダウンスケールを行っています。このハックにより、ユーザーにエラーを感じさせることなく、スムーズな編集体験を提供しています。
// ブラウザ負荷を抑えるためのリサイズ処理
const SAFE_LIMIT = // 端末負荷を考慮した独自の最大ピクセル数;
let w = loadedImageObj.width;
let h = loadedImageObj.height;
if (w > SAFE_LIMIT || h > SAFE_LIMIT) {
const scale = SAFE_LIMIT / Math.max(w, h);
// アスペクト比を維持した縮小サイズの計算
w = Math.floor(w * scale);
h = Math.floor(h * scale);
}
previewCanvas.width = w;
previewCanvas.height = h; Developer's Note
このツールの最大の特徴は、すべての処理が「あなたのデバイス内」で完結することです。画像をサーバーに一切送信しないというプライバシーポリシーを貫くため、これまでサーバーサイドで行っていたような高度な合成処理を、すべてブラウザ上のJavaScriptとCanvas APIに落とし込みました。
特に「全体に敷き詰める」機能は、クリエイターの方々が自身の作品を無断学習から守るための「盾」になるよう、文字の密度や回転角を何度も微調整して現在の形に辿り着きました。シンプルながらも、エンジニアとしてのこだわりが詰まった自慢のロジックです。