Algorithm & UI/UX
パスポート写真の切り抜きとCanvasによる印刷用配置
Web 用の写真と L判用の4枚配置を、ブラウザ内で作るツールです。容量調整は実装で定めた目安に合わせる処理で、申請要件すべてを検査するものではありません。ここでは品質を変えるループと出力寸法を説明します。
このツールの入力から出力まで
現行コードの確認日:
- 入力
- 写真を選び、出力の枠内で頭部の位置と大きさを調整します。
- 処理
- 規格寸法を基準にトリミングする範囲を計算し、保存用Canvasへ描きます。
- 出力
- Web 出力は 600×730px に切り抜いた写真を JPEG にし、品質 0.95 から 0.05 ずつ下げて容量を調整します。
まず確認する点:輪郭の欠け、表情、背景の条件は切取りだけで解決しません。発行先の要件を確認してから使用します。
実装の確認箇所:src/pages/passport/photo/index.astro。以下のコード抜粋と出力条件は、この本番実装に基づいて説明します。
仕組みを読み進めるときは、Canvas APIと画像処理(画像寸法、drawImage、画素と透明度の扱い)、File APIとObject URL(選んだ画像の読み込みとBlob URLの解放)が参考になります。
1. 容量を抑える「動的品質調整ループ」
Web申請(マイナポータル)用データの作成では、画像の鮮明さを保ちつつ、ファイルサイズを厳格な上限値以下に収める必要があります。このツールでは、CanvasからBlobを生成する際に、品質(Quality)を段階的に下げながら実装の容量目安または品質の下限に達するまで繰り返すループを採用しました。
これにより、画素数を変えずに JPEG 品質を下げます。下限に達すると容量が目安を超えたまま出力する可能性があり、保存後のサイズ確認が必要です。
品質ループを示した例です。550 はコード内の目安(KiB の概算)で、最新の申請要件を示す値ではありません。
function compressedPassport(canvas) {
let quality = 0.95;
let url = canvas.toDataURL('image/jpeg', quality);
const sizeKiB = value => Math.floor(value.split(',')[1].length * 0.75 / 1024);
while (sizeKiB(url) > 550 && quality > 0.5) {
quality -= 0.05;
url = canvas.toDataURL('image/jpeg', quality);
}
return { url, quality, estimatedKiB: sizeKiB(url) };
} 2. 印刷用の写真を配置するCanvasマトリックス・レイアウト
「印刷用(L判)」モードでは、単なる画像のリサイズではなく、300dpi相当の解像度を持つ仮想Canvas上に、正確なミリ単位の比率で4枚の写真を配置する必要があります。
ここでは、L判の標準ピクセルサイズに基づき、写真間のマージンやトリミングガイドを数学的に計算して描画しています。単に画像を並べるだけでなく、カット時の目安となる境界線を1px単位で制御することで、切り取り位置の目安を描きます。印刷機側の自動拡大は制御しないため、実際の写真の大きさは印刷後に確認してください。
3. ブラウザ内HEICデコードとメモリ管理
iPhoneの標準形式であるHEICをそのままブラウザで扱うことは、依然として課題が多い領域です。このツールでは、heic2any ライブラリを動的インポートし、変換を完了してから編集へ進みます。変換時もメモリを使うため、大きなファイルでは失敗する場合があります。
また、処理後の Object URL を即座に revoke することで、不要になった Blob URL の参照を解放します。画像や Canvas の全メモリを直ちに消す保証ではありません。
出力の仕様と確認する点
入力は長辺 3000px 以下。Web 出力は 600×730px に切り抜いた写真を JPEG にし、品質 0.95 から 0.05 ずつ下げて容量を調整します。浮動小数点の丸めもあるため、品質下限の判定と実際のファイル容量を区別します。
印刷用は 1051×1500px の白いシートに 413×531px の同じ写真を2列×2行で置き、品質指定 0.95 で保存します。頭・あごの目安は上から 9% と 84% の CSS ガイドで、保存画像には含めません。
顔の検出、背景除去、表情や影の適否の判定は行いません。申請経路ごとの最新の寸法・容量・写真条件を提出先で確認してください。ガイドに合わせたことや容量目安以下であることだけで受理が決まるわけではありません。