猫の手ツール

Algorithm & UI/UX

厳格な規格をブラウザで完結させる:マイナンバー写真生成の技術解剖

マイナンバーカードの写真は、顔の占める割合が「70〜80%」という非常に厳しい規定があります。本ツールが、サーバーに画像を一切送信せず、どのようにして高い精度とユーザー体験を両立させているのか、その裏側のロジックを解説します。

1. CSS Pseudo-elements による「対話型規格ガイド」

ユーザーに「顔の割合を70〜80%にしてください」と伝えても、目測で調整するのは困難です。本ツールでは、クロップUIの内部にCSSの擬似要素を用いて、物理的な規定に基づいた「頭頂部」と「あご」のラインを動的に重畳させています。

なぜこの実装にしたのか

Canvasにガイドラインを描画する手法に比べ、DOM要素としてガイドを定義することで、Cropper.jsによるズームやリサイズに完全に同期させることができます。また、pointer-events: none を指定することで、UIの操作性を損なうことなく、視覚的な補助のみを提供できるのがメリットです。

/* クロップ領域に重畳するガイドラインの設計 */
.cropper-view-box::before {
    content: '--- 頭頂部 ---';
    position: absolute;
    top: // 独自のチューニング値;
    width: 100%;
    /* ユーザーの視認性を高めるスタイリング */
    z-index: 10;
    pointer-events: none;
}

.cropper-view-box::after {
    content: '--- あご ---';
    position: absolute;
    top: // 独自のチューニング値;
    /* 規定の顔サイズ(70-80%)を担保する配置 */
}

2. L判印刷用タイリングと座標計算アルゴリズム

「印刷用(L判)」モードでは、1枚のL判写真用紙(89mm × 127mm)に、規定サイズ(35mm × 45mm)の写真を正確に4枚配置します。ここでは、コンビニプリント等の「フチなし印刷」による拡大を考慮したマージン計算を行っています。

なぜこの実装にしたのか

一般的な証明写真プリントサービスは高価ですが、L判の「通常の写真」として出力すれば、30円程度のコストで済みます。Canvas上でミリメートル単位をDPI換算してピクセル座標に落とし込むことで、家庭用プリンタやコンビニ機でもサイズが狂わない高精度な出力シートを生成しています。

async function renderPrintSheet(mode) {
    const canvas = document.createElement('canvas');
    // L判 300dpi 相当の解像度を設定
    canvas.width = // 独自のチューニング値;
    canvas.height = // 独自のチューニング値;
    
    // グリッド配置のロジック
    for (let row = 0; row < 2; row++) {
        for (let col = 0; col < 2; col++) {
            // ここに各写真の精密な配置座標(x, y)の計算処理が入ります
            // 切り取りやすさを考慮したガイド線の描画
            ctx.drawImage(croppedImage, x, y, targetWidth, targetHeight);
        }
    }
}

3. クライアントサイドでのHEIC変換とメモリ最適化

iPhoneで撮影された写真はHEIC形式であることが多く、そのままではブラウザのCanvasで扱えません。本ツールでは、heic2any を用いた動的変換と、巨大な画像を扱う際のメモリパンクを防ぐためのリサイズ処理をフロントエンドのみで完結させています。

なぜこの実装にしたのか

マイナンバーカードという極めて機密性の高い写真を扱う以上、サーバーへのアップロードは避けなければなりません。HEIC変換から編集用の一時リサイズまでをすべてブラウザ上(Blob URL)で行うことで、「利便性」と「究極のプライバシー保護」を両立させています。

async function handleImageFile(file) {
    let blob = file;
    
    // HEIC形式の判定と変換
    if (isHeicFormat(file)) {
        blob = await convertHeicToJpeg(file);
    }

    // 編集のパフォーマンスを維持するためのプレリサイズ
    const limit = // 動作安定のためのしきい値;
    blob = await resizeImageIfNeeded(blob, limit);
    
    // クロップエディタへ渡す
    imageElement.src = URL.createObjectURL(blob);
}

Developer's Note

マイナンバーカードの申請で最も多い「差し戻し」の理由は、写真の不備です。特に顔の割合が小さすぎたり、大きすぎたりするケースが目立ちます。

このツールを開発する際、最もこだわったのは「赤い点線」の絶妙な配置です。ユーザーは何も考えず、ただ赤い線に頭頂部とあごを合わせるだけで、役所の厳しい審査をパスできる。そんな「技術によるユーザーの思考のショートカット」を目指しました。また、iPhoneユーザーがダウンロード後に画像を見失わないよう、独自のガイドモーダルを実装するなど、エンジニアリングだけでなくUXの細部にも魂を込めています。