猫の手ツール

Algorithm & UI/UX

ブラウザ完結で公的規格を実現する、Canvas画像処理アルゴリズム

パスポートという極めて機微な情報を扱うため、サーバー送信を一切行わない「完全クライアントサイド処理」をいかに実現したか。そして、公的機関の厳しい容量制限とレイアウト規格をどうコードに落とし込んだかを解説します。

1. マイナポータル制約を突破する「動的品質調整ループ」

Web申請(マイナポータル)用データの作成では、画像の鮮明さを保ちつつ、ファイルサイズを厳格な上限値以下に収める必要があります。このツールでは、CanvasからBlobを生成する際に、品質(Quality)を段階的に下げながら規定値に収まるまで再計算を繰り返す再帰的なアルゴリズムを採用しました。

これにより、ユーザーに「画像が大きすぎます」といった警告を出すことなく、裏側で自動的に最適なファイルサイズへチューニングすることを可能にしています。

// Web申請用の容量制限をクリアするためのアルゴリズム(概要)
let quality = INITIAL_QUALITY; // 独自の初期品質値
let dataUrl = canvas.toDataURL('image/jpeg', quality);
let size = calculateSize(dataUrl); // データURLからファイルサイズを推定

// 規定の閾値(例:マイナポータルの上限)を下回るまでループ
const MAX_FILE_SIZE = 550; // 単位: KB (独自のチューニング値)
while (size > MAX_FILE_SIZE && quality > 0.5) {
    quality -= 0.05; // 徐々に品質を下げる
    dataUrl = canvas.toDataURL('image/jpeg', quality);
    size = calculateSize(dataUrl);
}

2. 印刷精度を保証するCanvasマトリックス・レイアウト

「印刷用(L判)」モードでは、単なる画像のリサイズではなく、300dpi相当の解像度を持つ仮想Canvas上に、正確なミリ単位の比率で4枚の写真を配置する必要があります。

ここでは、L判の標準ピクセルサイズに基づき、写真間のマージンやトリミングガイドを数学的に計算して描画しています。単に画像を並べるだけでなく、カット時の目安となる境界線を1px単位で制御することで、コンビニ等のセルフプリント機でも狂いのないサイズで印刷できる工夫を施しています。

// L判プリント用の4面配置ロジック
const canvas = document.createElement('canvas');
// L判(89mm×127mm)を300dpi相当で計算した解像度を設定
canvas.width = L_SIZE_WIDTH;  // 独自の規格値
canvas.height = L_SIZE_HEIGHT; // 独自の規格値

const ctx = canvas.getContext('2d');
// 描画開始位置(startX, startY)をキャンバス中央にオフセット計算
// 2x2のグリッドで配置するための座標計算ループ
for (let row = 0; row < 2; row++) {
    for (let col = 0; col < 2; col++) {
        const x = startX + col * (photoWidth + marginX);
        const y = startY + row * (photoHeight + marginY);
        
        // ユーザーが調整したクロップ画像を配置
        ctx.drawImage(originalCroppedCanvas, x, y, photoWidth, photoHeight);
        
        // 切り取りガイド用の極細線をオーバーレイ
        ctx.strokeStyle = '#e2e8f0';
        ctx.lineWidth = 2; 
        ctx.strokeRect(x, y, photoWidth, photoHeight);
    }
}

3. ブラウザ内HEICデコードとメモリ管理

iPhoneの標準形式であるHEICをそのままブラウザで扱うことは、依然として課題が多い領域です。このツールでは、`heic2any` ライブラリを動的インポートし、Web Workerに近いスレッド処理をシミュレートすることで、巨大なHEIC画像をブラウザのメモリを枯渇させずにJPEGへ変換しています。

また、処理後の `ObjectObjectURL` を即座に `revoke` することで、低スペックなスマートフォン端末でもブラウザのクラッシュを防ぐ徹底したメモリ管理を行っています。

Developer's Note

このツールで最もこだわったのは、実はコードそのものよりも「ガイド線」のUXです。パスポート写真は「顔の長さが全体の約70〜80%」という非常に厳しい規格がありますが、これをユーザーにミリ単位で指定させるのは不可能です。

そこで、編集画面に2本の赤い点線を固定表示し、その間に「頭頂部」と「あご」を合わせてもらうだけで、Canvas上の座標計算によって自動的に規格通りの比率(約34mm相当)で切り抜かれる仕組みにしました。

技術(Canvas/アルゴリズム)を使って、ユーザーの「難しい」を「合わせるだけ」に変換する。それがこのツールの設計思想です。