前言
由于项目要求,需要用 Qt 做一个Android 程序用于扫描二维码并获取扫码内容,之前参考了很多资料,很多都是基于桌面端的二维码识别,如一去丶二三里大神的Qt之二维码扫描,原理是直接导入一张二维码图片然后进行识别,而移动端会稍微麻烦一点点,并且关于 Qt 来做一个 Android 程序扫描二维码的资料太少,最终通过各种尝试,采用 QML+QZXing 的结合来实现该功能,这里做一个简单的总结。
原理
程序实现原理大概分为几个步骤:
1.Camera启动手机摄像头
2.VideoOutput获取一个摄像头的预览视频帧
3.QZXing对视频帧进行解析并返回内容
效果图
界面做得很简陋,但是功能实现,后期只要提供界面图标来重新实现界面就完美了。
左边是程序界面,中间的扫描线是动态的,右边是扫描后的效果,content 是扫描到的二维码内容,Detected count是检测次数。
源码
来看看 QML 端关键的代码
import QtQuick 2.6
import QtQuick.Window 2.0
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.1
import QtMultimedia 5.5
import QZXing 2.3
ApplicationWindow
{
id: window
visible: true
width: 1080
height: 1920
title: "Qt QZXing Filter Test"
property int detectedTags: 0
property string lastTag: ""
property int nWidth: Math.min(width,height)
Rectangle
{
id: bgRect
color: "white"
anchors.fill: videoOutput
}
Label
{
id: text1
wrapMode: Text.Wrap
color:"white"
z: 50
text: "Detected count: " + detectedTags
}
Camera
{
id:camera
focus {
focusMode: CameraFocus.FocusContinuous
focusPointMode: CameraFocus.FocusPointAuto
}
}
VideoOutput
{
id: videoOutput
source: camera
anchors.fill: parent
autoOrientation: true
fillMode: VideoOutput.Stretch
filters: [ zxingFilter ]
MouseArea {
anchors.fill: parent
onClicked: {
camera.focus.customFocusPoint = Qt.point(mouse.x / width, mouse.y / height);
camera.focus.focusMode = CameraFocus.FocusMacro;
camera.focus.focusPointMode = CameraFocus.FocusPointCustom;
}
}
Rectangle {
id: captureZone
width: nWidth*0.6
height: width
anchors.centerIn: parent
color:"transparent"
border.color: "lightgreen"
border.width: 3
Rectangle{
id:line
width: parent.width*0.9
height: 12
color: "lightgreen"
anchors.horizontalCenter: parent.horizontalCenter
radius: 8
PropertyAnimation{
id:ani
target:line
properties: "y"
duration: 1500
from:0
running: true
to:captureZone.height
onStopped: {
y=0
ani.start()
}
}
}
}
}
QZXingFilter
{
id: zxingFilter
captureRect: {
// setup bindings
videoOutput.contentRect;
videoOutput.sourceRect;
//识别的区域,这里稍微比扫描框大一些
return videoOutput.mapRectToSource(videoOutput.mapNormalizedRectToItem(Qt.rect(
0.2, 0.2, 0.6, 0.6
)));
}
decoder {
enabledDecoders: QZXing.DecoderFormat_EAN_13 | QZXing.DecoderFormat_CODE_39 | QZXing.DecoderFormat_QR_CODE
onTagFound: {
console.log(tag + " | " + decoder.foundedFormat() + " | " + decoder.charSet());
window.detectedTags++;
window.lastTag = tag;
}
tryHarder: false
}
onDecodingStarted:
{
console.log("started");
}
property int framesDecoded: 0
property real timePerFrameDecode: 0
onDecodingFinished:
{
timePerFrameDecode = (decodeTime + framesDecoded * timePerFrameDecode) / (framesDecoded + 1);
framesDecoded++;
console.log("frame finished: " + succeeded, decodeTime, timePerFrameDecode, framesDecoded);
}
}
Label
{
wrapMode: Text.Wrap
color:"white"
anchors.bottom: parent.bottom
z: 50
text: "content: " + lastTag
}
}
权限
在 Android 上运行,开启摄像头需要先添加权限,在 AndroidManifest.xml文件中添加:
<uses-permission android:name="android.permission.CAMERA"/>
关于 QZXing
QML 中用到的二维码解码库,需要去官网下载源码并导入到工程中, 官网:QZXing ,详情请参考官网介绍,这里不再赘述。
源码
鉴于有好几位童鞋遇到问题,在开始玩 GitHub 后,就整理了一份完整的代码,有疑问的可以直接直接下载源码进行编译。
代码地址:https://github.com/luoyayun361/QML-Android-ScanCode
欢迎大家提出自己更好的想法,共同进步和交流。