本文詳細比較兩種主流二維碼生成方案:後端使用 phpqrcode、前端使用 qrcode.js,並提供完整實作代碼與架構選型建議。
<?php
require_once 'phpqrcode/phpqrcode.php';
$value = $url; // 二維碼內容
$errorCorrectionLevel = 'L'; // 容錯等級:L(7%) M(15%) Q(25%) H(30%)
$matrixPointSize = $size; // 圖片大小(模組像素)
// 1. 生成無 Logo 二維碼
$qrPath = 'public_files/code/qrcode.png';
QRcode::png($value, $qrPath, $errorCorrectionLevel, $matrixPointSize, 2);
// 2. 疊加 Logo
$logoPath = $tar_path; // 上傳的 Logo 路徑
if ($logoPath !== FALSE) {
$QR = imagecreatefromstring(file_get_contents($qrPath));
$logo = imagecreatefromstring(file_get_contents($logoPath));
$QR_width = imagesx($QR);
$QR_height = imagesy($QR);
$logo_width = imagesx($logo);
$logo_height = imagesy($logo);
// Logo 寬度佔二維碼 1/5,等比縮放
$logo_qr_width = $QR_width / 5;
$scale = $logo_width / $logo_qr_width;
$logo_qr_height = $logo_height / $scale;
// 置中座標
$from_width = ($QR_width - $logo_qr_width) / 2;
// 重採樣複製合成
imagecopyresampled(
$QR, $logo,
$from_width, $from_width,
0, 0,
$logo_qr_width, $logo_qr_height,
$logo_width, $logo_height
);
// 輸出最終圖片
$name = time();
$finalPath = 'public_files/code/' . $name . '.png';
imagepng($QR, $finalPath);
imagedestroy($QR);
imagedestroy($logo);
}
?>
| 等級 | 容錯率 | 適用場景 |
|---|---|---|
| L | 7% | 無 Logo、純文字、空間受限 |
| M | 15% | 一般用途、小型 Logo |
| Q | 25% | 帶 Logo、較複雜圖案 |
| H | 30% | 大型 Logo、藝術二維碼、惡劣環境 |
建議:帶 Logo 時至少使用 Q 等級,確保掃描成功率。
<div id="code_img"></div>
<img id="image" style="display:none;" />
<input type="file" id="file_input" accept="image/*" />
<script src="jquery.min.js"></script>
<script src="qrcode.js"></script>
<script>
var size = 200; // 二維碼尺寸
var length = size * 80;
length = parseInt(length);
$("#code_img").qrcode({
render: "canvas", // canvas 模式效能優於 table
text: "https://example.com", // 內容
width: length,
height: length,
background: "#ffffff",
foreground: "#000000"
});
</script>
// 讀取本地圖片轉 Base64
var input = document.getElementById("file_input");
if (typeof FileReader === 'undefined') {
input.setAttribute('disabled', 'disabled');
} else {
input.addEventListener('change', readFile, false);
}
function readFile() {
var file = this.files[0];
if (!/image\/\w+/.test(file.type)) {
alert("請選擇圖片檔案!");
return false;
}
var reader = new FileReader();
reader.readAsDataURL(file); // 轉為 Base64 Data URL
reader.onload = function(e) {
$('#image').attr('src', this.result);
regenerateQR(); // 重新生成含 Logo 的二維碼
};
}
function regenerateQR() {
$("#code_img").empty().qrcode({
render: "canvas",
text: "https://example.com",
width: length,
height: length,
background: "#ffffff",
foreground: "#000000",
src: $('#image').attr('src') // 關鍵:指定 Logo 來源
});
}
| 維度 | phpqrcode (後端) | qrcode.js (前端) |
|---|---|---|
| 運算資源 | 佔用伺服器 CPU/記憶體 | 客戶端裝置運算 |
| 儲存需求 | 需儲存圖片、定期清理 | 無實體檔案、無儲存壓力 |
| Logo 上傳 | 需上傳至伺服器 | 本地讀取、Base64 傳遞 |
| 離線支援 | 不可 | 可(Service Worker 快取) |
| 相容性 | 全瀏覽器相容 | 需 Canvas 支援(IE9+) |
| 適用場景 | 需永久保存、列印、API 提供 | 即時生成、使用者自訂、臨時使用 |
前端使用 qrcode.js 即時預覽、使用者調整參數;確認後前端將參數傳給後端,由 phpqrcode 生成高解析度最終版本並儲存。
toDataURL() 失敗,需設定 crossOrigin="anonymous" 或代理圖片matrixPointSize 或 canvas 尺寸,匯出時指定高 DPI