Algorithm & UI/UX
ブラウザ完結で実現する
高速スキャン風・2値化アルゴリズム
「スマホで撮った写真をスキャナー風に見せる」というシンプルな体験の裏側では、Canvas APIによる画素操作と、ユーザーがストレスを感じないための非同期・軽量化処理が組み合わされています。サーバーを介さないプライバシー重視の設計思想も紹介します。
1. 輝度に基づく高精度2値化アルゴリズム
単に白か黒かに分けるだけではなく、人間が「文字」として認識しやすいコントラストを保つため、まずカラー画像をグレースケール化する際に独自の輝度計算を行っています。RGB各色に対して人間の視覚特性に合わせた係数を適用することで、背景の影の影響を最小限に抑えつつ、文字の輪郭を際立たせています。
// 2値化コアロジックの概要
for (let i = 0; i < data.length; i += 4) {
const r = data[i];
const g = data[i + 1];
const b = data[i + 2];
// 視覚特性を考慮した輝度(グレースケール)の計算
// 独自のチューニング値を適用
const brightness = (r * RATIO_R) + (g * RATIO_G) + (b * RATIO_B);
// しきい値判定により白(255)か黒(0)を決定
const color = brightness >= threshold ? 255 : 0;
data[i] = data[i + 1] = data[i + 2] = color;
} この処理により、スライダーを動かすたびにリアルタイムで画像が変化し、最適な「クッキリ感」をユーザーが直感的に調整できるようになっています。
2. 「ダブルキャンバス」によるUXの最適化
最新のスマホで撮影した写真は非常に高解像度ですが、その全画素をスライダー操作に合わせてリアルタイム処理すると、ブラウザがフリーズしたり、動作がカクついたりします。これを防ぐため、本ツールでは「プレビュー用」と「書き出し用」の2つのCanvasを使い分けるハックを採用しています。
- プレビュー用: UI表示に合わせ、一定の解像度(// 軽量化のための制限値)にリサイズした画像に対して処理を行います。これにより低スペック端末でも滑らかな操作が可能です。
- 書き出し用: ユーザーが「保存」を押した瞬間のみ、元の解像度(最大 // 独自のサイズ制限)で重い処理を実行します。
// 表示領域に合わせたスケーリング処理のコンセプト
function proceedToPreview(targetImg) {
let pw = targetImg.width;
let ph = targetImg.height;
// 軽量表示用のスケーリングロジック
if (pw > MAX_DISPLAY_SIZE) {
const scale = MAX_DISPLAY_SIZE / pw;
pw = MAX_DISPLAY_SIZE;
ph = Math.floor(ph * scale);
}
// 軽量Canvasに描画し、リアルタイム処理の対象とする
// ここに描画とメモリ解放の処理が入ります
} Developer's Note
このツールの開発で最もこだわったのは、「完全なオフライン・プライバシー保護」です。スキャンする書類には機密情報や個人情報が含まれることが多いため、1bitのデータも外部サーバーに送信しない設計を徹底しました。
技術的には、iPhone固有のHEIC形式への対応や、メモリ使用量の抑制など、ブラウザという限られた環境でどこまで「アプリのような快適さ」を提供できるかに挑戦しました。CanvasのgetImageDataは重い処理ですが、処理対象を賢く絞ることで、Webツールならではの気軽さと実用性を両立させています。