猫の手ツール

Security & Canvas Logic

復元不可能な「純黒」上書きと
高精度座標マッピングの技術

モザイクによる秘匿は、AIによる復元リスクを孕みます。本ツールが採用した「ピクセルデータの完全破壊」を支える座標変換アルゴリズムと、メモリ効率を両立した履歴管理の仕組みを解説します。

1. 解像度に依存しない動的座標スケーリング

スマホで撮影した写真は3000pxを超える高解像度であることが一般的ですが、ブラウザの画面表示(CSS上のサイズ)は数百px程度です。本ツールでは、表示用のコンテナサイズと、実際のキャンバスピクセルサイズの差異を動的に算出し、タップ位置を正確に元画像のピクセルへマッピングしています。

メリット: ユーザーが画面上で「ここを隠したい」と直感的に操作した位置が、たとえ4K画像であっても1ピクセルの狂いもなく黒塗りされます。これにより、意図しない「塗り漏らし」を防ぎ、高い秘匿性を担保しています。

// 表示サイズと実ピクセルサイズの比率から正確な座標を算出
function getPos(evt) {
    const rect = canvasContainer.getBoundingClientRect();
    
    // 独自の計算ロジック:表示上の座標を取得
    const clientX = // タッチまたはマウスのX座標算出処理;
    const clientY = // タッチまたはマウスのY座標算出処理;

    // キャンバスの実解像度と表示サイズの比率(スケール係数)
    const scaleX = mainCanvas.width / rect.width;
    const scaleY = mainCanvas.height / rect.height;
    
    // スケール係数を乗算して、実ピクセル座標に変換
    return {
        x: (clientX - rect.left) * scaleX,
        y: (clientY - rect.top) * scaleY
    };
}

2. メモリ効率を考慮したスタック型履歴管理

Canvas操作において「1つ戻る(Undo)」を実現するには、直前の描画状態(ImageData)をメモリに保持する必要があります。しかし、高解像度画像のImageDataは1枚数MBに達することもあり、単純に全てを保存するとブラウザがクラッシュします。本ツールでは、履歴数を制限しつつ古いデータから破棄するスタック型管理を導入しています。

メリット: モバイル端末の限られたメモリ環境でも動作を安定させつつ、ユーザーが試行錯誤できる利便性を提供しています。

// 履歴管理スタックの制御
let historyStates = [];

function saveState() {
    // 独自のチューニング値に基づき、履歴数を制限
    if (historyStates.length >= // 最大保持数) {
        historyStates.shift(); // 最も古い状態を破棄してメモリを解放
    }
    
    // 現在のキャンバス状態をキャプチャしてスタックに追加
    historyStates.push(ctx.getImageData(0, 0, canvas.width, canvas.height));
}

// Undo処理
function undo() {
    if (historyStates.length > 0) {
        const previousState = historyStates.pop();
        ctx.putImageData(previousState, 0, 0);
    }
}

3. クライアントサイドHEIC変換による完全オフライン化

iPhoneの標準形式であるHEICは、通常ブラウザでは表示・加工ができません。本ツールでは、`heic2any` ライブラリを動的に読み込み、ブラウザ内でJPEGへ変換するパイプラインを構築しています。

メリット: サーバーサイドに画像を送信して変換する工程を完全に排除。給与明細のような極めて機密性の高い情報を扱うため、「一度も通信を介さない」というセキュリティ要件をフロントエンド技術のみで完結させています。

// HEIC変換パイプラインの概要
async function processImage(file) {
    let targetBlob = file;

    // ファイル拡張子を判定
    if (file.name.match(/\.(heic|heif)$/i)) {
        // 独自の動的インポート処理
        const converted = await heic2any({
            blob: file,
            toType: "image/jpeg",
            quality: // 独自の画質パラメータ
        });
        targetBlob = Array.isArray(converted) ? converted[0] : converted;
    }

    // 以降、生成されたBlobをCanvasへ展開
    // ...
}

Developer's Note

このツールの開発で最もこだわったのは、名前の通り「完全」であることです。

世の中には多くの「顔隠しアプリ」がありますが、その多くが半透明のぼかしやモザイクを採用しています。しかし、統計的なアプローチやAI補完を用いれば、それらは容易に推測可能になります。個人情報を守るために必要なのは「かっこよさ」ではなく「情報の消去」だと考えました。

「黒塗りの画像は、どんなに頑張っても元のピクセルデータが 0(純黒)に置き換わっているので、物理的に復元できない」という安心感こそが、このツールの本質です。