Laravel - QRCODE

# Introduction

Laravel QR code 相關


# QR code 上加入文字

# 產生 QR code

使用 Laravel simple qrcode package 產生 qrcode
這邊的 size 以及 margin 會隨著 text size 而變動, 因為 image 的 size 太小, 可能 text 會看不清楚, 而 margin 太小, text 可能會破版或與 qr code 重疊, 因此視需求調整

<?php
$qrCode = QrCode::format('png')->size($size)->margin($margin)->generate($url);

# 從 image string 產生 PHP image resource

使用 imagecreatefromstring() 輸入 image string 取得 PHP image resource 做後續使用

<?php
$qrCode = imagecreatefromstring($qrCode);

# 取得 font file

會使用 PHP 的 imagettftext(), 因此會用到 font file, 可到網上找一個免費可供商用的 font file

<?php
$fontFile = public_path('webfonts/TaipeiSans.ttf');

# 定義 text color

會使用 PHP 的 imagecolorallocate(), 來取得指定 image 當中的顏色代碼, $qrcode 為要將 text 插入的 image
color 為 RGB 代碼, 會輸出一個專屬於該 image 的 color code

<?php
$color = $input->has(['text-color']) ? $input['text-color'] : [0, 0, 0];
$textColor = imagecolorallocate($qrCode, ...$color);

# 取得 text 座標

使用 imagettfbbox() 來取得該 text 方塊的座標資訊, 即大小
$textSize: 為 text 的大小
$angle: 為傾斜度, 預設為 0, 如果要讓 text 是歪的, 就要調整, value 越大傾斜度越大
$fontFile: 上面取得的 font file
text: 欲顯示的 text string

<?php
$textCoordinates = imagettfbbox($textSize, $angle, $fontFile, $text);

回傳值會是一個 size 8 的 array, 分別為該 text 的座標, 依序為
0 = 左下 x
1 = 左下 y
2 = 右下 x
3 = 右下 y
4 = 右上 x
5 = 右上 y
6 = 左上 x
7 = 左上 y

# 取得 text 方塊的長寬

想像一下, 當我們有了一個長方形的四個點的座標, 是不是就能算出該長方形的長寬

<?php
$textWidth = $textCoordinates[2] - $textCoordinates[0];
$textHeight = $textCoordinates[1] - $textCoordinates[7];

# 取得 image 的長寬

使用 imagesx(), imagesy() 來取得 image 的 height 以及 width

$imageWidth = imagesx($qrCode);
$imageHeight = imagesy($qrCode);

# 計算 text 方塊置於 image 中的位置

PHP imagettftext() 可以定義一個 text 方塊在指定 image 當中的位置, 而我們有了 image 以及 text 方塊的長寬, 就可以透過計算取得 text 方塊應置於 image 當中的座標點
我們的目標, 是要 text 方塊置於 image 的下方且置中
所以 image 的一半寬, 再扣掉 text 方塊的一半寬, 會是 text 方塊放置的 x 座標點
y 座標點則簡單地減去高度即可

x 越小, 則位置在 image 中越靠左, 反之則越靠右
y 越小, 則位置在 image 中越靠上, 反之則越靠下

<?php
$x = ($imageWidth / 2) - ($textWidth / 2);
$y = $imageHeight - $textHeight;

imagettftext($qrCode, $textSize, $angle, $x, $y, $textColor, $fontFile, $text);

# 不儲存圖片直接串流下載

使用 Laravel Response facade 的 streamDownload() 直接印出 image string 觸發下載

<?php
return \Illuminate\Support\Facades\Response::streamDownload(function () use ($qrCode) {
echo imagepng($qrCode);
}, 'qrcode.png');

# 完整 example

<?php
public function download(QrcodeDownloadRequest $request)
{
$input = collect($request->validated());

$margin = $input->has(['margin']) ? $input['margin'] : 4;
$size = $input->has(['size']) ? $input['size'] : config('app.qrcode_size_for_download');
$url = $input['url'];

$qrCode = QrCode::format('png')->size($size)->margin($margin)->generate($url);

$qrCode = imagecreatefromstring($qrCode);

if ($input->has('text')) {
$this->insertText($qrCode, $input);
}

return \Illuminate\Support\Facades\Response::streamDownload(function () use ($qrCode) {
echo imagepng($qrCode);
}, 'qrcode.png');
}

private function insertText($qrCode, Collection $input): void
{
$fontFile = public_path('webfonts/TaipeiSans.ttf');
$text = $input['text'];
$color = $input->has(['text-color']) ? $input['text-color'] : [0, 0, 0];
$angle = $input->has('text-angle') ? $input['text-angle'] : 0;
$textSize = $input->has(['text-size']) ? $input['text-size'] : 8;
$textColor = imagecolorallocate($qrCode, ...$color);

$textCoordinates = imagettfbbox($textSize, $angle, $fontFile, $text);

$imageWidth = imagesx($qrCode);
$imageHeight = imagesy($qrCode);

$textWidth = $textCoordinates[2] - $textCoordinates[0];
$textHeight = $textCoordinates[1] - $textCoordinates[7];

$x = ($imageWidth / 2) - ($textWidth / 2);
$y = $imageHeight - $textHeight;

imagettftext($qrCode, $textSize, $angle, $x, $y, $textColor, $fontFile, $text);
}
Laravel - Packages - Backpack Laravel - Eloquent ORM - Serialization (官方文件原子化翻譯)

留言

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×