個人ブログにQRフォトメーカーを作った話【つまずきポイントと解決まで】


目次

最近ツール開発にハマっているえふてぃです。

「ブログって、記事を書くだけじゃなくて、何か使えるものも置けたら面白くない?」

ふとそんなことを思って、個人ブログに ツールページ を作ってみました。
で、最初に何を作ろうかと考えた結果、「QRフォトメーカー」というやつに着手。
背景写真の上にQRコードを半透明で重ねて、写真が透けて見えるQRコードを生成できるWebツールです。

きっかけの一つは、技術イベントに参加したときの体験。
会場のWi-Fi情報がホワイトボードや紙に書いてあって、一文字ずつ打ち込むんだけど…これが地味に面倒。
「ならQRにしたら一発じゃん」って思ったのが始まりです。

この記事では、企画から実装、そして直した点を中心に振り返ります。

まずはQRフォトメーカーとは何か

QRフォトメーカーは、ブラウザ上で完結するQRコード生成ツールです。

普通のQRコードって、白と黒の四角が並んだだけで味気ないなぁと思っていて。
このツールでは、背景に好きな写真や色を設定して、その上にQRコードを半透明で重ねることで、 写真が透けて見えるQRコード を作れるようにしました。

主な機能はこんな感じ。

  • URLモード: URLを入力すると、スキャンでWebサイトに遷移するQRコードを生成
  • Wi-Fiモード: SSID・パスワード・暗号化方式を入力すると、スキャンでWi-Fiに自動接続
  • 背景設定: 画像アップロード、単色、グラデーションの3種類から選択
  • カスタマイズ: ドットの色、QRサイズ、透過度、マージンを自由に調整
  • PNG / JPG ダウンロード対応

技術スタックと設計判断

技術スタックは以下の通り。

項目選定
フレームワークAstro(既存ブログサイトに組み込み)
言語TypeScript
QR生成qr-code-styling
画像合成Canvas API(ブラウザ標準)
処理方式全てクライアントサイド完結
検証環境

Astro 5.x / qr-code-styling 1.9.2 で動作確認しています。

QR生成ライブラリは EasyQRCodeJSQRCode.js などいくつか候補があったんだけど、最終的に qr-code-styling にしました。
決め手は、コミュニティが大きくて情報が見つかりやすかったのと、透明背景が公式でサポートされていたこと。
「これなら写真との合成もやりやすそうだな」と。

もう一つこだわったのは、 処理を全てブラウザ内で完結 させたこと。
そもそもAstroはコンテンツ駆動のフレームワークなので、現状はDBやバックエンドは持ちたくない。
それに、Wi-FiモードではSSIDやパスワードを扱うわけで、サーバーにデータが飛ばない方がプライバシー的にも安心できる。
開いてすぐサッと使える、そういうツールにしたかったし。

実装のポイント:半透明QRと背景合成

さて、このツールの核心は「半透明のQRドットを写真の上に重ねる」部分。

qr-code-stylingの dotsOptions.color にrgba文字列を渡せば半透明ドットになるのか、正直やってみるまで確信が持てなかった。
ドキュメントにも明確には書いてなくて、「まぁ試すか」の精神でやってみたら…あっさりいけた。
拍子抜けするくらいシンプルに収まりました。

const rgbaColor = `rgba(${r}, ${g}, ${b}, ${opacity})`;

const qrCode = new QRCodeStyling({
  dotsOptions: {
    color: rgbaColor, // rgbaで半透明ドットが実現できた
    type: 'rounded',
  },
  backgroundOptions: {
    color: 'transparent', // 背景は透明に
  },
  qrOptions: {
    errorCorrectionLevel: 'H', // 背景と合成するので最高レベルに
  },
});

合成の流れは、qr-code-stylingで透明背景のQRを生成 → Canvasに背景を描画 → その上にQRを重ねる、というもの。
ここはすんなりいって正直ホッとした。

誤り訂正レベルはHが必須

背景との合成ではQRドットの一部が見えにくくなるため、誤り訂正レベルは最高の 'H' に設定しています。
これにより約30%のデータ欠損に耐えられます。透過度を下げすぎると読み取れなくなるので、最低値にも制限をかけています。

つまずきポイント:Wi-Fiモードの落とし穴

ここからが本番(というか苦労話)。

Wi-Fiモードでは、入力されたSSIDとパスワードから WIFI:T:WPA;S:MySSID;P:password;; という形式の文字列を生成してQRコードにします。

で、普通のパスワードなら問題ないんだけど、パスワードに ;:" などの特殊文字が含まれていると…フォーマットが壊れる。
これ、テスト中に気づいてちょっと焦りました。
パスワードに特殊文字を使うのはよくある話だし、ここは対応必須。

対策として、Wi-Fi QRコードの仕様で定められた特殊文字をエスケープする関数を追加しました。

function escapeWifiValue(value: string): string {
  return value.replace(/([\\;,:"'])/g, '\\$1');
}

function getQRData(): string {
  if (currentMode === 'wifi') {
    const ssid = escapeWifiValue(ssidInput.value);
    const password = escapeWifiValue(passwordInput.value);
    const encryption = encryptionSelect.value;
    return `WIFI:T:${encryption};S:${ssid};P:${password};;`;
  }
  return urlInput.value;
}

地味だけど、こういう「普通に使ってたら踏む罠」を潰しておくのは大事。

UXを良くするのが地味に大変だった

技術的な問題を片付けた後、一番時間がかかったのが UXの改善 でした。
正直、ここが一番しんどかった。

マージンUIの変遷

QRコード周囲の余白(マージン)の調整、最初はスライダーにしてたんです。
でも冷静に考えると、細かい数値を触らせてもユーザーにとっては意味がない。「マージン37pxです」とか言われても困るでしょう。

で、最終的に 「なし / 小 / 大」の3択ボタン に落ち着きました。
Webツールとしてサッと使ってもらうには、選択肢を絞って迷わせないのが正解だなと。

WEP削除の判断

Wi-Fiの暗号化方式は、最初「WPA/WPA2」「WEP」「なし」の3択で作ってました。
ただ、私自身WEPが何なのかよくわかってなくて(おい)、調べてみたら過去に脆弱性が見つかって以降、今はほぼ使われていないらしい。

なので削って「WPA/WPA2(推奨)」「なし(フリーWi-Fi)」の2択に。
ユーザーが迷う選択肢を一つ減らせたのは良かった。

QR未入力時の「壊れてる?」問題

これ、地味にハマったやつ。
背景画像を設定したのにURLをまだ入力していないと、プレビューが真っ白のまま。
ユーザーからすると「背景設定したのに何も表示されない…壊れてる?」ってなるわけです。

対策として、 QRデータ未入力でも背景だけはプレビューに表示 されるようにしました。
「ちゃんと背景は設定できてますよ」という安心感を与える、地味だけど大事な改善。

ちなみにこの状態ではQRコード自体は生成されていないので、ダウンロードボタンも無効のままにしています。

まとめ:個人ブログにツールを置く面白さ

個人ブログに「使えるツール」を置くのは、なかなか面白い体験でした。
記事を書くのとは違う頭の使い方をするし、「自分のサイトにツールがある」というのが地味にテンション上がる。

今回やってみて一番感じたのは、技術的な実装よりもUXの調整に時間がかかるということ。
スライダーを3択ボタンにしたり、使われない規格を削ったり…こういう「ユーザーが迷わない形にする」作業が意外と奥深い。

今後も何かツールを作ってみたいなぁと思っています。
興味がある方は、ぜひ QRフォトメーカー を試してみてください。


読んでくれてありがとう。よかったらシェアやフォロー押してってください。Xで雑に絡んでくれるのも普通に嬉しい。