Yish
Yish
Nov 6, 2017 · 7 min read

前端掃瞄器配置

在先前的專案當中剛好遇到了要用 web scanner 來做 qrcode 掃描的功能,前端的部分我採用了 instascan 這個 html 5 web scanner 來解決,具體做法其實沒有什麼需要注意的項目,但還是說一下步驟:

$ npm install instascan

由於我是使用 webpack (laravel mix) 作為我的編譯工具,因此我先到了 app.js 寫下:

window.Instascan = require('instascan');

但當我編譯時出現錯誤,看起來是 not found fs(file system):

$ npm install fs

然後他還是報錯 Module not found: Error: Cannot resolve module 'fs' 所幸看到關鍵字應該是我在編譯時必須給他個初始值,不然會報錯,所以我到了 webpack.mix.js 寫下:

mix.webpackConfig({
node: {
fs: 'empty'
}
})

trouble shooting

然後就可以了,接下來只要到前端頁面寫下呼叫的 script 和接口:

<!DOCTYPE html>
<html>
<head>
<title>Instascan</title>
<script type="text/javascript" src="instascan.min.js"></script>
</head>
<body>
<video id="preview"></video> <script type="text/javascript">
let scanner = new Instascan.Scanner({ video: document.getElementById('preview') });
scanner.addListener('scan', function (content) {
//把你需要他響應的部分放這裡,這邊我放了 axios 的 api 接口
});
Instascan.Camera.getCameras().then(function (cameras) {
if (cameras.length > 0) {
scanner.start(cameras[0]);
} else {
console.error('No cameras found.');
}
}).catch(function (e) {
console.error(e);
});
</script>
</body>
</html>

然後注意的項目是必須是 https,至此前端的部分就差不多了。

後端功能

接下來來談談後端實作,其實基本上就是由參數來驅動 where 條件並做對應的事情,我們會有兩件事情必須做:

  • 參數接口
  • 產生 QrCode

參數接口的部分其實就相對來說簡單許多,基本上就是由前端傳了一組可以辨識的 token 過來後端後做 where 條件並做相對應的事情,這邊唯一比較好的部分如果你是用 laravel mix 做編譯的話 csrf token 可以不用夾帶過去了,在底層已經幫你做好,詳細請看 bootstrap.js

let token = document.head.querySelector('meta[name="csrf-token"]');

if (token) {
window.axios.defaults.headers.common['X-CSRF-TOKEN'] = token.content;
} else {
console.error('CSRF token not found: https://laravel.com/docs/csrf#csrf-x-csrf-token');
}

上面因應每個人狀態不同就不多做說明,接下來來說說產生 Qrcode 這件事情,我是用 simple-qrcode 這個包,主要是他文件很全,而且他有支援我想要的合成圖片這件事情:

$ composer require simplesoftwareio/simple-qrcode

官方文件

基礎的產生文件和官方有的內容我就不多說了,比較需要注意的是 Error Correction (容錯率)這件事情,因為是透過特徵做辨識,一但你將圖片合成後,必須把容錯率拉高,這樣子才能辨識到圖片裡面的代碼。

舉個例子來說,我現在要把圖片合成,產生出像是這樣子的圖片:

如果是用 default: M 的話是很難掃出來的,如果用 H 就可以比較容易掃出來,詳細可以看官方網站有對於這個做說明。

但現實總是沒那麼單純,我今天除了合成圖之外,我裡面必須放著連結,官方針對放入連結和合成圖片分開說明,但是如果你的思路是先放入連結再合圖會失敗,可以把 generate() 想成是 endpoint,也就是說如果要達到效果必須像是這樣:

<img src="data:image/png;base64, {!! 
base64_encode(
QrCode::format('png') //設定為 png
->errorCorrection('H') //設定高容錯
->size(200) //尺寸
->merge(public_path('images/eat.jpg'),.3, true) //準備合成圖片跟他佔用的百分比,最後一個參數是設定絕對路徑
->generate(route('welcome')) //產生圖片並放入連結
)
!!}">

這樣就可以產生出我想要的合成圖片 + 網址拜訪了。

不過每次這樣寫也確實麻煩,可以寫一個簡單的 helper 把他弄好:

if (! function_exists('qrcode')) {
/**
* That should be generate qrcode.
*
*
@param $token
*
@param int $size
*
@param null $image
*
@param float $radio
*
@return mixed
*/
function
qrcode($token, $size = 500, $image = null, $radio = .3)
{
$code = QrCode::format('png')
->errorCorrection('H')
->size($size);

if (! empty($image)) {
$code->merge($image, $radio, true);
}

return new HtmlString('<img src="data:image/png;base64, '.base64_encode($code->generate($token)).'">');
}
}

Illuminate\Support\HtmlString 裡面有 __toString 也就是說在 echo 的同時可以直接打印出 html:

{!! qrcode('https://medium.com/yish', 300, public_path('images/eat.jpg')) !!}

後記

比較可惜的是前端的 web scanner 每家瀏覽器實作結果都不太一樣,iOS 的部分連開都無法開,android 卻可以,看樣子支援程度還是有落差,如果真的要實作這類的機制我覺得還是 App 靠譜些(直接調用底層)iOS 最近也支援直接用相機可以開 QrCode連結,很方便。

Parenting Engineering

《親子天下雜誌》創刊於2008年8月,為華文圈影響力最大的教育教養品牌,也是最值得信賴的親子社群平台。希望提供給學校和家庭,專業可信賴的教育教養解決方案。從線上(online)到實體(offline),分齡分眾供應華人地區親子家庭最合身體貼的優質內容、活動、產品與服務。

Yish

Written by

Yish

Never stop progressing. https://yish.dev

Parenting Engineering

《親子天下雜誌》創刊於2008年8月,為華文圈影響力最大的教育教養品牌,也是最值得信賴的親子社群平台。希望提供給學校和家庭,專業可信賴的教育教養解決方案。從線上(online)到實體(offline),分齡分眾供應華人地區親子家庭最合身體貼的優質內容、活動、產品與服務。

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade