diff --git a/Config.cmake.in b/Config.cmake.in index 7a9dc54..5083de2 100644 --- a/Config.cmake.in +++ b/Config.cmake.in @@ -2,5 +2,5 @@ include(CMakeFindDependencyMacro) find_dependency(Qt6 REQUIRED COMPONENTS Core Gui Qml Quick Svg OPTIONAL_COMPONENTS Multimedia ) find_dependency(OpenCV REQUIRED COMPONENTS core objdetect ) -find_dependency(MyDesigns 0.3 REQUIRED CONFIG) +find_dependency(MyDesigns 0.4 REQUIRED CONFIG) include ( "${CMAKE_CURRENT_LIST_DIR}/qrCodeTargets.cmake" ) diff --git a/QrDec/CMakeLists.txt b/QrDec/CMakeLists.txt index 9faa6b2..7a46843 100755 --- a/QrDec/CMakeLists.txt +++ b/QrDec/CMakeLists.txt @@ -1,5 +1,7 @@ find_package(OpenCV COMPONENTS core objdetect imgproc flann features2d calib3d ) -if(NOT OpenCV_FOUND ) + +option(OpenCV_DOWNLOAD "On or off" ON) +if(NOT OpenCV_FOUND AND OpenCV_DOWNLOAD) set(builturl "https://github.com/EddyTheCo/install-OpenCV-action/releases/latest/download/OpenCV-ubuntu-latest-wasm_false-android_none.tar") if(WIN32) set(builturl "https://github.com/EddyTheCo/install-OpenCV-action/releases/latest/download/OpenCV-windows-latest-wasm_false-android_none.tar") diff --git a/QtQrDec/CMakeLists.txt b/QtQrDec/CMakeLists.txt index aea4747..d5c3dae 100644 --- a/QtQrDec/CMakeLists.txt +++ b/QtQrDec/CMakeLists.txt @@ -1,15 +1,12 @@ find_package(Qt6 REQUIRED COMPONENTS Core Gui Qml Quick OPTIONAL_COMPONENTS Multimedia) - FetchContent_Declare( MyDesigns GIT_REPOSITORY https://github.com/EddyTheCo/MyDesigns.git - GIT_TAG v0.3.1 - FIND_PACKAGE_ARGS 0.3 CONFIG + GIT_TAG v0.4.1 + FIND_PACKAGE_ARGS 0.4 CONFIG ) FetchContent_MakeAvailable(MyDesigns) - - if (Qt6_FOUND AND TARGET QrDec) qt_standard_project_setup() qt6_add_qml_module(QtQrDec @@ -17,8 +14,9 @@ if (Qt6_FOUND AND TARGET QrDec) VERSION 1.0 SOURCES Qrimagedecoder.cpp include/Qrimagedecoder.hpp QML_FILES - qml/QrTextArea.qml qml/QrQmlCamera.qml + qml/QrCam.qml + qml/QrTextCamPop.qml RESOURCE_PREFIX "/esterVtech.com/imports" OUTPUT_TARGETS out_targets_var @@ -29,14 +27,9 @@ if (Qt6_FOUND AND TARGET QrDec) target_include_directories(QtQrDec PUBLIC $ "$") - target_link_libraries(QtQrDec PUBLIC Qt6::Gui Qt6::Quick QrDec) - target_link_libraries(QtQrDec PRIVATE MyDesigns - $<$,STATIC_LIBRARY>:MyDesignsplugin> - ) + target_link_libraries(QtQrDec PUBLIC Qt6::Gui Qt6::Quick QrDec $ MyDesigns + $<$,STATIC_LIBRARY>:MyDesignsplugin>) - if(TARGET Qt6::Multimedia) - target_link_libraries(QtQrDec PUBLIC Qt6::Multimedia) - endif(TARGET Qt6::Multimedia) install(TARGETS QtQrDec QtQrDecplugin ${out_targets_var} EXPORT qrCodeTargets DESTINATION ${CMAKE_INSTALL_LIBDIR} diff --git a/QtQrDec/Qrimagedecoder.cpp b/QtQrDec/Qrimagedecoder.cpp index 6489ccf..868d42c 100644 --- a/QtQrDec/Qrimagedecoder.cpp +++ b/QtQrDec/Qrimagedecoder.cpp @@ -14,66 +14,65 @@ QRImageDecoder* QRImageDecoder::m_decoder=nullptr; EMSCRIPTEN_BINDINGS(qrdecoder) { - emscripten::class_("QRImageDecoder") - .function("reload", &QRImageDecoder::reload,emscripten::allow_raw_pointers()) - .class_function("getdecoder", &QRImageDecoder::getdecoder, emscripten::allow_raw_pointers()); + emscripten::class_("QRImageDecoder") + .function("reload", &QRImageDecoder::reload,emscripten::allow_raw_pointers()) + .class_function("getdecoder", &QRImageDecoder::getdecoder, emscripten::allow_raw_pointers()); } EM_JS(void, js_start, (), { - if ('mediaDevices' in navigator && 'getUserMedia' in navigator.mediaDevices) { - stream = navigator.mediaDevices.getUserMedia({ video: { facingMode: 'environment' }, audio: false }).then((stream) => { - let settings = stream.getVideoTracks()[0].getSettings(); - let width = settings.width; - let height = settings.height; - - if(document.querySelector("#qrvideo")=== null) - { - var elemDiv = document.createElement('div'); - elemDiv.style.cssText = 'display:none; position:absolute;width:100%;height:100%;'; - elemDiv.innerHTML += ''; - document.body.appendChild(elemDiv); - } - let video = document.querySelector("#qrvideo"); - let canvas = document.querySelector("#qrcanvas"); - - video.srcObject = stream; - window.localStream = stream; - getimage=setInterval(function() { - //You need to define qtQR module when loading the module of the qt application. - canvas.getContext('2d').drawImage(video, 0, 0, canvas.width, canvas.height); - let imageData = canvas.getContext('2d').getImageData(0, 0, canvas.width, canvas.height); - var data=imageData.data.buffer; - var uint8Arr = new Uint8Array(data); - const numBytes = uint8Arr.length * uint8Arr.BYTES_PER_ELEMENT; - const dataPtr = qtQR.module()._malloc(numBytes); - const dataOnHeap = new Uint8Array(qtQR.module().HEAPU8.buffer, dataPtr, numBytes); - dataOnHeap.set(uint8Arr); - - qtQR.module().QRImageDecoder.getdecoder().reload(dataOnHeap.byteOffset,video.width,video.height); - qtQR.module()._free(dataPtr); - }, 100); - - }).catch(alert); - - - } - - - + if ('mediaDevices' in navigator && 'getUserMedia' in navigator.mediaDevices) { + stream = navigator.mediaDevices.getUserMedia({ video: { facingMode: 'environment' }, audio: false }).then((stream) => { + const settings = stream.getVideoTracks()[0].getSettings(); + const width = settings.width; + const height = settings.height; + + if(document.querySelector("#qrvideo")=== null) + { + let elemDiv = document.createElement('div'); + elemDiv.style.cssText = 'display:none; position:absolute;width:100%;height:100%;'; + elemDiv.innerHTML += ''; + document.body.appendChild(elemDiv); + } + const video = document.querySelector("#qrvideo"); + video.srcObject = stream; + window.localStream = stream; + + let canvas = document.querySelector("#qrcanvas"); + let ctx=canvas.getContext("2d"); + const processFrame = function () { + //You need to define qtQR module when loading the module of the qt application. + ctx.drawImage(video, 0, 0, canvas.width, canvas.height); + const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height); + const sourceBuffer = imageData.data; + if (qtQR.module() != null) { + const buffer = qtQR.module()._malloc(sourceBuffer.byteLength); + qtQR.module().HEAPU8.set(sourceBuffer, buffer); + qtQR.module().QRImageDecoder.getdecoder().reload(buffer,video.width,video.height); + qtQR.module()._free(buffer); + } + if(window.localStream.active) + { + requestAnimationFrame(processFrame); + } + else + { + ctx.clearRect(0, 0, canvas.width, canvas.height); + } + }; + processFrame(); + + + }).catch(alert); + + + } }); EM_JS(void, js_stop, (), { - try { - getimage; - clearInterval(getimage); - localStream.getVideoTracks()[0].stop(); - }catch(e) { - e; // => ReferenceError - console.log('getimage is not defined'); - } -}); + if(window.localStream)window.localStream.getVideoTracks()[0].stop(); + }); #else #if QT_CONFIG(permissions) #include @@ -81,29 +80,29 @@ EM_JS(void, js_stop, (), { void QRImageDecoder::getCamera(void) { - const QList cameras = QMediaDevices::videoInputs(); - if(cameras.size()) - { - QCameraDevice best=cameras.front(); - for (const QCameraDevice &cameraDevice : cameras) { - - if (cameraDevice.position() == QCameraDevice::BackFace) - { - best=cameraDevice; - } - } - m_camera=new QCamera(best,this); - auto bvF=best.videoFormats().at(0); - for (const QCameraFormat &format : best.videoFormats()) - { - if(abs(format.resolution().width()*1.0-format.resolution().height())setCameraFormat(bvF); - - } + const QList cameras = QMediaDevices::videoInputs(); + if(cameras.size()) + { + QCameraDevice best=cameras.front(); + for (const QCameraDevice &cameraDevice : cameras) { + + if (cameraDevice.position() == QCameraDevice::BackFace) + { + best=cameraDevice; + } + } + m_camera=new QCamera(best,this); + auto bvF=best.videoFormats().at(0); + for (const QCameraFormat &format : best.videoFormats()) + { + if(abs(format.resolution().width()*1.0-format.resolution().height())setCameraFormat(bvF); + + } } @@ -111,117 +110,119 @@ void QRImageDecoder::getCamera(void) QRImageDecoder::QRImageDecoder(QObject *parent):QObject(parent),m_useTorch(false),m_hasTorch(false), #ifndef USE_EMSCRIPTEN - m_camera(nullptr),captureSession(new QMediaCaptureSession(this)),videoSink(new QVideoSink(this)), + m_camera(nullptr),captureSession(new QMediaCaptureSession(this)),videoSink(new QVideoSink(this)), #endif - m_state(Ready) + m_state(Ready) { #ifdef USE_EMSCRIPTEN - m_decoder=this; + m_decoder=this; #else - captureSession->setVideoOutput(videoSink); - QObject::connect(videoSink,&QVideoSink::videoFrameChanged,this,[=](const QVideoFrame & Vframe) - { - - if(m_camera&&m_camera->isActive()){ - auto picture=Vframe.toImage(); - WasmImageProvider::img=picture; - setid(); - if(m_state) - { - auto var = std::thread(&QRImageDecoder::decodePicture, this,picture); - var.detach(); - } - - - } - WasmImageProvider::restart(); - }); - connect(this,&QRImageDecoder::useTorchChanged,this,[=](){ - if(m_camera->isActive()&&m_useTorch) - m_camera->setTorchMode(QCamera::TorchOn); - else - m_camera->setTorchMode(QCamera::TorchOff); - }); + captureSession->setVideoOutput(videoSink); + QObject::connect(videoSink,&QVideoSink::videoFrameChanged,this,[=](const QVideoFrame & Vframe) + { + + if(m_camera&&m_camera->isActive()){ + auto picture=Vframe.toImage(); + WasmImageProvider::img=picture; + setid(); + if(m_state) + { + auto var = std::thread(&QRImageDecoder::decodePicture, this,picture); + var.detach(); + } + } + }); + connect(this,&QRImageDecoder::useTorchChanged,this,[=](){ + if(m_camera->isActive()&&m_useTorch) + m_camera->setTorchMode(QCamera::TorchOn); + else + m_camera->setTorchMode(QCamera::TorchOff); + }); #endif }; void QRImageDecoder::stop(){ #ifdef USE_EMSCRIPTEN - js_stop(); + js_stop(); #else - if(m_camera)m_camera->stop(); + if(m_camera)m_camera->stop(); #endif }; void QRImageDecoder::start() { #ifdef USE_EMSCRIPTEN - js_start(); + js_start(); #elif QT_CONFIG(permissions) - QCameraPermission cPermission; - switch (qApp->checkPermission(cPermission)) { - case Qt::PermissionStatus::Undetermined: - qApp->requestPermission(cPermission, this, - &QRImageDecoder::start); - return; - case Qt::PermissionStatus::Denied: - return; - case Qt::PermissionStatus::Granted: - if(!m_camera) - { - getCamera(); - if(m_camera) - { - captureSession->setCamera(m_camera); - QObject::connect(m_camera,&QCamera::activeChanged,[=](bool var) - { - - if(var&&m_camera->isTorchModeSupported(QCamera::TorchOn)) - { - m_hasTorch=true; - emit hasTorchChanged(); - - } - - }); - - QObject::connect(m_camera,&QCamera::errorOccurred,[](QCamera::Error error, const QString &errorString) - { - qDebug()<<"Camera Error:"<start(); - } - - return; - } + QCameraPermission cPermission; + switch (qApp->checkPermission(cPermission)) { + case Qt::PermissionStatus::Undetermined: + qApp->requestPermission(cPermission, this, + &QRImageDecoder::start); + return; + case Qt::PermissionStatus::Denied: + return; + case Qt::PermissionStatus::Granted: + if(!m_camera) + { + getCamera(); + if(m_camera) + { + captureSession->setCamera(m_camera); + QObject::connect(m_camera,&QCamera::activeChanged,[=](bool var) + { + + if(var&&m_camera->isTorchModeSupported(QCamera::TorchOn)) + { + m_hasTorch=true; + emit hasTorchChanged(); + + } + + }); + + QObject::connect(m_camera,&QCamera::errorOccurred,[](QCamera::Error error, const QString &errorString) + { + qDebug()<<"Camera Error:"<start(); + } + + return; + } #endif } void QRImageDecoder::decodePicture(QImage picture) { - m_state=QRImageDecoder::Decoding; - picture.convertTo(QImage::Format_Grayscale8); - const auto str = detector.decode_grey(picture.bits(), picture.height(),picture.bytesPerLine()); - const auto qstr=QString::fromStdString(str); - if(qstr!="") - { - text=qstr; + m_state=QRImageDecoder::Decoding; + picture.convertTo(QImage::Format_Grayscale8); + const auto str = detector.decode_grey(picture.bits(), picture.height(),picture.bytesPerLine()); + const auto qstr=QString::fromStdString(str); + if(qstr!="") + { + text=qstr; emit text_changed(); - } - m_state=QRImageDecoder::Ready; + } + m_state=QRImageDecoder::Ready; } QImage WasmImageProvider::img=QImage(); QImage WasmImageProvider::requestImage(const QString &id, QSize *size, const QSize &requestedSize) { - return img; + return img; +} +void QRImageDecoder::clear(void) +{ + WasmImageProvider::restart(); + setid(); } void WasmImageProvider::restart(void) { @@ -230,16 +231,16 @@ void WasmImageProvider::restart(void) } void QRImageDecoder::reload(int offset, int width, int height) { - auto imgarr = reinterpret_cast(offset); - WasmImageProvider::img=QImage(imgarr,width,height,QImage::Format_RGBA8888); + auto imgarr = reinterpret_cast(offset); + WasmImageProvider::img=QImage(imgarr,width,height,QImage::Format_RGBA8888); setid(); - decodePicture(WasmImageProvider::img); + if(m_state)decodePicture(WasmImageProvider::img); } void QRImageDecoder::setid() { - static quint8 index=0; - source="qrimage"+QString::number(index); - emit source_changed(); - index++; + static quint8 index=0; + source="qrimage"+QString::number(index); + emit source_changed(); + index++; } diff --git a/QtQrDec/include/Qrimagedecoder.hpp b/QtQrDec/include/Qrimagedecoder.hpp index bf0f475..2c614ab 100644 --- a/QtQrDec/include/Qrimagedecoder.hpp +++ b/QtQrDec/include/Qrimagedecoder.hpp @@ -32,7 +32,7 @@ class QRImageDecoder : public QObject }; Q_INVOKABLE void start(); Q_INVOKABLE void stop(); - + Q_INVOKABLE void clear(); QString get_text(void)const{return text;} QString get_source(void)const{return source;} diff --git a/QtQrDec/qml/QrCam.qml b/QtQrDec/qml/QrCam.qml new file mode 100644 index 0000000..a81c820 --- /dev/null +++ b/QtQrDec/qml/QrCam.qml @@ -0,0 +1,37 @@ +import QtQuick 2.0 +import QtQuick.Controls +import QtQuick.Layouts +import MyDesigns +import QtQrDec + +QrQmlCamera +{ + id:qrscanner + property bool showClose:false; + + Switch { + id:useTorch + opacity: checked ? 0.75 : 0.25 + anchors.bottom: parent.bottom + anchors.horizontalCenter: parent.horizontalCenter + visible:QRImageDecoder.hasTorch + onCheckedChanged: + { + QRImageDecoder.useTorch=useTorch.checked; + } + } + CloseButton + { + id:cbutton + anchors.right: parent.right + anchors.top: parent.top + width: parent.width*0.15 + height:width + visible: qrscanner.showClose + onClicked: + { + qrscanner.stop(); + qrscanner.visible=false; + } + } +} diff --git a/QtQrDec/qml/QrQmlCamera.qml b/QtQrDec/qml/QrQmlCamera.qml index e619d8d..4825128 100644 --- a/QtQrDec/qml/QrQmlCamera.qml +++ b/QtQrDec/qml/QrQmlCamera.qml @@ -1,21 +1,23 @@ import QtQuick 2.0 import QtQuick.Controls -import MyDesigns import QtQrDec Item { - id:root signal gotdata(string data); + implicitWidth: preview.implicitWidth + implicitHeight: preview.implicitHeight function stop() { QRImageDecoder.stop(); - startcamera.visible=true; } - + function start() { + QRImageDecoder.start(); + } Connections { target: QRImageDecoder function onText_changed(boo) { root.gotdata(QRImageDecoder.text) + QRImageDecoder.clear(); } } Image { @@ -23,29 +25,7 @@ Item anchors.fill: root cache : false source: "image://wasm/"+QRImageDecoder.source - visible: !startcamera.visible - } - Switch { - id:useTorch - opacity: checked ? 0.75 : 0.25 - anchors.bottom: preview.bottom - anchors.horizontalCenter: preview.horizontalCenter - visible:!startcamera.visible&&QRImageDecoder.hasTorch - onCheckedChanged: - { - QRImageDecoder.useTorch=useTorch.checked; - } - } - MyButton - { - id:startcamera - anchors.centerIn: root - text:qsTr("Scan Qr") - onClicked: - { - QRImageDecoder.start(); - startcamera.visible=false; - } } + } diff --git a/QtQrDec/qml/QrTextArea.qml b/QtQrDec/qml/QrTextCamPop.qml similarity index 66% rename from QtQrDec/qml/QrTextArea.qml rename to QtQrDec/qml/QrTextCamPop.qml index 94752ed..f373c91 100644 --- a/QtQrDec/qml/QrTextArea.qml +++ b/QtQrDec/qml/QrTextCamPop.qml @@ -3,17 +3,19 @@ import QtQuick.Controls import QtQuick.Layouts import MyDesigns import QtQrDec + Popup { id:popup_ - property string description; - property string placeholder; + property alias label:tfield.label; + property alias textField:tfield.textarea; + signal clicked(string data); onClosed: qrscanner.stop(); onOpened:{ - qrscanner.stop(); - recaddress.textarea.text=""; + tfield.textarea.text=""; + qrscanner.visible=false; } background: Rectangle @@ -29,19 +31,22 @@ Popup anchors.fill: parent MyTextArea { - id:recaddress - label.text: (popup_.description)?popup_.description:"" - textarea.placeholderText: (popup_.placeholder)?popup_.placeholder:"" + id:tfield Layout.alignment: Qt.AlignHCenter Layout.margins: 20 Layout.fillWidth: true - Layout.fillHeight: true - Layout.maximumWidth:400 + Layout.maximumWidth:250 Layout.maximumHeight: 200 - Layout.minimumHeight: 100 focus:true + qrfill:true + onFillqr: + { + qrscanner.start(); + qrscanner.visible=true; + + } } - QrQmlCamera + QrCam { id:qrscanner Layout.alignment: Qt.AlignCenter @@ -50,9 +55,13 @@ Popup Layout.fillWidth: true Layout.minimumWidth:100 Layout.minimumHeight: 200 + Layout.maximumWidth: 300 + visible:false + showClose:true onGotdata: (data)=> { qrscanner.stop(); - recaddress.textarea.text=data; + qrscanner.visible=false; + tfield.textarea.text=data; } } MyButton @@ -60,15 +69,14 @@ Popup id:send Layout.alignment: Qt.AlignRight Layout.margins: 15 - enabled: recaddress.textarea.text!=="" + enabled: tfield.textarea.text onClicked: { popup_.close(); - popup_.clicked(recaddress.textarea.text); + popup_.clicked(tfield.textarea.text); } text:qsTr("Ok") } } } - diff --git a/QtQrGen/CMakeLists.txt b/QtQrGen/CMakeLists.txt index fd462b8..3c6456f 100644 --- a/QtQrGen/CMakeLists.txt +++ b/QtQrGen/CMakeLists.txt @@ -2,8 +2,8 @@ find_package(Qt6 COMPONENTS Core Gui Qml Quick OPTIONAL_COMPONENTS Svg) FetchContent_Declare( MyDesigns GIT_REPOSITORY https://github.com/EddyTheCo/MyDesigns.git - GIT_TAG v0.3.1 - FIND_PACKAGE_ARGS 0.3 CONFIG + GIT_TAG v0.4.1 + FIND_PACKAGE_ARGS 0.4 CONFIG ) FetchContent_MakeAvailable(MyDesigns) diff --git a/QtQrGen/qml/AddressQr.qml b/QtQrGen/qml/AddressQr.qml index 2630b11..2c541a7 100644 --- a/QtQrGen/qml/AddressQr.qml +++ b/QtQrGen/qml/AddressQr.qml @@ -1,6 +1,7 @@ import QtQuick.Controls import QtQuick import MyDesigns +import QtQrGen Rectangle { id:root diff --git a/QtQrGen/qml/PayQrPop.qml b/QtQrGen/qml/PayQrPop.qml index ea329bf..3387041 100644 --- a/QtQrGen/qml/PayQrPop.qml +++ b/QtQrGen/qml/PayQrPop.qml @@ -2,13 +2,13 @@ import QtQuick 2.0 import QtQuick.Controls import QtQuick.Layouts import MyDesigns +import QtQrGen Popup { id: root required property string address; property string url; required property string description; - property alias textarea:tex property alias qrcode:qrcode_; background: Rectangle @@ -41,6 +41,7 @@ Popup { textarea.wrapMode: Text.Wrap } + AddressQr { id:qrcode_ @@ -48,12 +49,9 @@ Popup { url:root.url Layout.preferredWidth: tex.width*0.75 Layout.preferredHeight: width - Layout.alignment: Qt.AlignCenter } } - - } diff --git a/QtQrGen/qml/QrLabel.qml b/QtQrGen/qml/QrLabel.qml index 353cfd7..330db9a 100644 --- a/QtQrGen/qml/QrLabel.qml +++ b/QtQrGen/qml/QrLabel.qml @@ -1,6 +1,8 @@ import QtQuick.Controls import QtQuick import MyDesigns +import QtQrGen + Text