diff --git a/.github/workflows/build-docs.yml b/.github/workflows/build-docs.yml index 07714b0..37cf8e5 100644 --- a/.github/workflows/build-docs.yml +++ b/.github/workflows/build-docs.yml @@ -6,8 +6,8 @@ on: branches: [main] jobs: build_doxygen: - uses: EddyTheCo/Common/.github/workflows/build-docs.yml@main - if: ${{ (github.event.pull_request.merged == true) && (startsWith(github.base_ref, 'main')) }} + uses: EddyTheCo/Common/.github/workflows/build-docs.yml@v0.1.1 + if: ${{ (github.event.pull_request.merged == true) && (startsWith(github.base_ref, 'main')) }} permissions: pages: write id-token: write diff --git a/.github/workflows/build-test-install.yml b/.github/workflows/build-test-install.yml index e0ff548..d1570c9 100644 --- a/.github/workflows/build-test-install.yml +++ b/.github/workflows/build-test-install.yml @@ -13,14 +13,15 @@ jobs: matrix: os: [ubuntu-latest,macos-latest,windows-latest] - uses: EddyTheCo/Common/.github/workflows/build-test-install.yml@main + uses: EddyTheCo/Common/.github/workflows/build-test-install.yml@v0.1.1 permissions: contents: write with: os: ${{ matrix.os }} sharedLib: true qtVersion: '6.6.0' - qtModules: 'qtshadertools qtmultimedia' + qtModules: 'qtshadertools qtmultimedia' + test: false release: if: startsWith(github.ref, 'refs/tags/v') needs: build_test_package diff --git a/CMakeLists.txt b/CMakeLists.txt index 9a50659..f5a7d87 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,16 +15,6 @@ version_from_git( ) project(qrCode VERSION ${VERSION} DESCRIPTION "library for qr code manipulation" LANGUAGES CXX) -set(default_build_type "Release") -if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) - message(STATUS "Setting build type to '${default_build_type}' as none was specified.") - set(CMAKE_BUILD_TYPE "${default_build_type}" CACHE - STRING "Choose the type of build." FORCE) - # Set the possible values of build type for cmake-gui - set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS - "Debug" "Release" "MinSizeRel" "RelWithDebInfo") -endif() - set_property(GLOBAL PROPERTY USE_FOLDERS ON) set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD_REQUIRED ON) @@ -32,39 +22,40 @@ set(CMAKE_CXX_EXTENSIONS OFF) set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON) include(GNUInstallDirs) +add_subdirectory(QrDec) add_subdirectory(QrGen) +add_subdirectory(QtQrDec) add_subdirectory(QtQrGen) -add_subdirectory(QrDec) -add_subdirectory(QtQrDec) -install(EXPORT qrCodeTargets - FILE qrCodeTargets.cmake - NAMESPACE qrCode:: - DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/qrCode - COMPONENT qrCode +install(EXPORT ${PROJECT_NAME}-config + FILE ${PROJECT_NAME}-config.cmake + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/Esterv + NAMESPACE ${PROJECT_NAME}:: + COMPONENT ${PROJECT_NAME} ) include(CMakePackageConfigHelpers) configure_package_config_file(${CMAKE_CURRENT_SOURCE_DIR}/Config.cmake.in - "${CMAKE_CURRENT_BINARY_DIR}/qrCodeConfig.cmake" - INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/qrCode + "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake" + INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/Esterv ) write_basic_package_version_file( - "${CMAKE_CURRENT_BINARY_DIR}/qrCodeConfigVersion.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake" VERSION ${VERSION} COMPATIBILITY SameMajorVersion ) install(FILES - ${CMAKE_CURRENT_BINARY_DIR}/qrCodeConfig.cmake - ${CMAKE_CURRENT_BINARY_DIR}/qrCodeConfigVersion.cmake - DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/qrCode + ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake + ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/Esterv ) -export(EXPORT qrCodeTargets - FILE "${CMAKE_CURRENT_BINARY_DIR}/qrCodeTargets.cmake" +export(EXPORT ${PROJECT_NAME}-config + FILE "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}-config.cmake" ) + if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME) - set(CPACK_PACKAGE_CONTACT "estervtech") + set(CPACK_PACKAGE_CONTACT "estervtech") include(CTest) set(CPACK_PACKAGE_FILE_NAME "${PROJECT_NAME}-v${SEMVER}-${CMAKE_SYSTEM_NAME}_${CMAKE_SYSTEM_VERSION}-${CMAKE_SYSTEM_PROCESSOR}-${CMAKE_CXX_COMPILER_ID}") if(NOT BUILD_SHARED_LIBS) diff --git a/Config.cmake.in b/Config.cmake.in index 5083de2..b55dd42 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.4 REQUIRED CONFIG) +find_dependency(EstervDesigns 1.0 COMPONENTS SimpleStyle CustomControls CONFIG) include ( "${CMAKE_CURRENT_LIST_DIR}/qrCodeTargets.cmake" ) diff --git a/QrDec/CMakeLists.txt b/QrDec/CMakeLists.txt index 7a46843..9f0b506 100755 --- a/QrDec/CMakeLists.txt +++ b/QrDec/CMakeLists.txt @@ -47,20 +47,21 @@ endif() if(OpenCV_FOUND) add_library(QrDec qrcodedec.cpp) + add_library(${PROJECT_NAME}::QrDec ALIAS QrDec) target_include_directories(QrDec PUBLIC $) target_link_libraries(QrDec PUBLIC ${OpenCV_LIBS}) target_include_directories(QrDec PUBLIC $ - "$") + "$") install(TARGETS QrDec - EXPORT qrCodeTargets + EXPORT ${PROJECT_NAME}-config DESTINATION ${CMAKE_INSTALL_LIBDIR} - COMPONENT Qr + COMPONENT QrDec ) install(DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/include/ - DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/qrCode - COMPONENT Qr + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/Esterv/${PROJECT_NAME} + COMPONENT QrDec ) else() - message(STATUS "OpenCV was not found") + message(STATUS "The QRCODE decoding library will not be built") endif(OpenCV_FOUND) diff --git a/QrDec/Config.cmake.in b/QrDec/Config.cmake.in deleted file mode 100644 index c32b57b..0000000 --- a/QrDec/Config.cmake.in +++ /dev/null @@ -1,3 +0,0 @@ -@PACKAGE_INIT@ - -include ( "${CMAKE_CURRENT_LIST_DIR}/QrDecTargets.cmake" ) diff --git a/QrDec/README.md b/QrDec/README.md index 2b1763e..8a1a3ca 100644 --- a/QrDec/README.md +++ b/QrDec/README.md @@ -1,11 +1,21 @@ -# QrGen +# QrDec This repo detect and decode a Qr code in a image. -The compiled library depend on [opencv](https://opencv.org/) - -CMake produce the target 'QrDec' so one can link to this library like +The detection and decoding is performed by [OpenCV](https://opencv.org/) libraries. +In case OpenCV is not found on your system CMake will download pre compiled libraries from [my action releases](https://github.com/EddyTheCo/install-OpenCV-action). + +## Adding the libraries to your CMake project ``` -target_link_libraries( QrDec) +include(FetchContent) +FetchContent_Declare( + qrCode + GIT_REPOSITORY https://github.com/EddyTheCo/qrCode.git + GIT_TAG v1.0.0 + FIND_PACKAGE_ARGS 1.0 COMPONENTS QrDec CONFIG +) +FetchContent_MakeAvailable(qrCode) + +target_link_libraries( qrCode::QrDec) ``` diff --git a/QrDec/tests/CMakeLists.txt b/QrDec/tests/CMakeLists.txt deleted file mode 100755 index 6e31857..0000000 --- a/QrDec/tests/CMakeLists.txt +++ /dev/null @@ -1,15 +0,0 @@ -cmake_minimum_required(VERSION 3.11 FATAL_ERROR) - -project(module_test VERSION 0.1 DESCRIPTION "diferent tests for the library" LANGUAGES CXX) - - - -add_executable(load_from_file load_from_file.cpp) -target_link_libraries(load_from_file PRIVATE QrDec) -add_test(NAME load_from_file COMMAND load_from_file ${CMAKE_CURRENT_BINARY_DIR}/qrcode-feature.jpg) - - -target_include_directories(load_from_file PRIVATE ${OpenCV_INCLUDE_DIRS}) -target_link_libraries(load_from_file PRIVATE ${OpenCV_LIBS}) -file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/qrcode-feature.jpg - DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) diff --git a/QrDec/tests/load_from_file.cpp b/QrDec/tests/load_from_file.cpp deleted file mode 100644 index e6fd009..0000000 --- a/QrDec/tests/load_from_file.cpp +++ /dev/null @@ -1,21 +0,0 @@ -#include"qrcodedec.hpp" -#include -#undef NDEBUG -#include - -using namespace qrcodedec; - -using namespace cv; - -int main(int argc, char** argv) -{ - Mat img = imread(argv[1]); - Mat gray; - - cv::cvtColor(img, gray, cv::COLOR_BGR2GRAY); - - assert(decode_grey(gray.data,gray.rows,gray.cols)=="http://LearnOpenCV.com"); - - return 0; - -} diff --git a/QrDec/tests/qrcode-feature.jpg b/QrDec/tests/qrcode-feature.jpg deleted file mode 100644 index f660111..0000000 Binary files a/QrDec/tests/qrcode-feature.jpg and /dev/null differ diff --git a/QrGen/CMakeLists.txt b/QrGen/CMakeLists.txt index 2824ed0..7cd2870 100755 --- a/QrGen/CMakeLists.txt +++ b/QrGen/CMakeLists.txt @@ -1,23 +1,19 @@ add_library(QrGen src/qrcodegen.cpp src/utils.cpp) +add_library(${PROJECT_NAME}::QrGen ALIAS QrGen) set_target_properties(QrGen PROPERTIES POSITION_INDEPENDENT_CODE ON) -target_compile_features(QrGen PUBLIC cxx_std_11) target_include_directories(QrGen PUBLIC $ - "$") + "$") -install(TARGETS QrGen - EXPORT qrCodeTargets +install(TARGETS QrGen + EXPORT ${PROJECT_NAME}-config DESTINATION ${CMAKE_INSTALL_LIBDIR} - COMPONENT Qr + COMPONENT QrGen ) install(DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/include/ - DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/qrCode - COMPONENT Qr + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/Esterv/${PROJECT_NAME} + COMPONENT QrGen ) -if(BUILD_DOCS) - get_target_property(build_docs cmake_build_docs SOURCES) - include(${build_docs}) -endif() diff --git a/QrGen/README.md b/QrGen/README.md index 304c388..897b479 100644 --- a/QrGen/README.md +++ b/QrGen/README.md @@ -1,9 +1,19 @@ # QrGen The code is based on [QR Code generator library](https://github.com/nayuki/QR-Code-generator) and produce a library for the generation of a QR code of certain data. -CMake produce the target 'QrGen' so one can link to this library like + +## Adding the libraries to your CMake project ``` -target_link_libraries( QrGen) +include(FetchContent) +FetchContent_Declare( + qrCode + GIT_REPOSITORY https://github.com/EddyTheCo/qrCode.git + GIT_TAG v1.0.0 + FIND_PACKAGE_ARGS 1.0 COMPONENTS QrGen CONFIG +) +FetchContent_MakeAvailable(qrCode) + +target_link_libraries( qrCode::QrGen) ``` diff --git a/QtQrDec/CMakeLists.txt b/QtQrDec/CMakeLists.txt index c8e3f36..6199552 100644 --- a/QtQrDec/CMakeLists.txt +++ b/QtQrDec/CMakeLists.txt @@ -1,51 +1,89 @@ -find_package(Qt6 REQUIRED COMPONENTS Core Gui Qml Quick OPTIONAL_COMPONENTS Multimedia) +if(EMSCRIPTEN) + find_package(Qt6 COMPONENTS Core Gui Qml Quick ShaderTools) +else() + find_package(Qt6 COMPONENTS Core Gui Qml Quick ShaderTools Multimedia) +endif(EMSCRIPTEN) + FetchContent_Declare( - MyDesigns - GIT_REPOSITORY https://github.com/EddyTheCo/MyDesigns.git - GIT_TAG v0.4.1 - FIND_PACKAGE_ARGS 0.4 CONFIG - ) -FetchContent_MakeAvailable(MyDesigns) + EstervDesigns + GIT_REPOSITORY https://github.com/EddyTheCo/MyDesigns.git + GIT_TAG v1.0.0 + FIND_PACKAGE_ARGS 1.0 COMPONENTS SimpleStyle CustomControls CONFIG +) +FetchContent_MakeAvailable(EstervDesigns) + + if (Qt6_FOUND AND TARGET QrDec) - qt_standard_project_setup() - qt6_add_qml_module(QtQrDec - URI QtQrDec - VERSION 1.0 - SOURCES Qrimagedecoder.cpp include/Qrimagedecoder.hpp - QML_FILES - qml/QrQmlCamera.qml - qml/QrCam.qml - qml/QrTextCamPop.qml - RESOURCE_PREFIX - "/esterVtech.com/imports" - OUTPUT_TARGETS out_targets_var - OUTPUT_DIRECTORY - ${CMAKE_BINARY_DIR}/QtQrDec - IMPORT_PATH ${CMAKE_BINARY_DIR} - ) - - target_include_directories(QtQrDec PUBLIC $ - "$") - - target_link_libraries(QtQrDec PUBLIC Qt6::Gui Qt6::Quick QrDec $ MyDesigns - $<$,STATIC_LIBRARY>:MyDesignsplugin>) - - install(TARGETS QtQrDec QtQrDecplugin ${out_targets_var} - EXPORT qrCodeTargets - DESTINATION ${CMAKE_INSTALL_LIBDIR} - COMPONENT QtQr - ) - install(DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/include/ - DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/qrCode - COMPONENT QtQr - ) - install(DIRECTORY ${CMAKE_BINARY_DIR}/QtQrDec/ - DESTINATION ${CMAKE_INSTALL_LIBDIR}/QMLPlugins/QtQrDec - COMPONENT QtQr - ) - - if(EMSCRIPTEN) - target_compile_definitions(QtQrDec PRIVATE USE_EMSCRIPTEN) - endif(EMSCRIPTEN) + qt_standard_project_setup() + qt6_add_qml_module(QtQrDec + URI Esterv.CustomControls.QrDec + VERSION 1.0 + SOURCES Qrimagedecoder.cpp include/Qrimagedecoder.hpp + QML_FILES + "qml/QrCam.qml" + "qml/QrDecPop.qml" + "qml/QrTextField.qml" + RESOURCE_PREFIX + "/esterVtech.com/imports" + OUTPUT_TARGETS out_targets_var + OUTPUT_DIRECTORY + ${CMAKE_BINARY_DIR}/Esterv/CustomControls/QrDec + IMPORT_PATH ${CMAKE_BINARY_DIR} ${CMAKE_INSTALL_LIBDIR} + ) + +add_library(${PROJECT_NAME}::QtQrDec ALIAS QtQrDec) +add_library(${PROJECT_NAME}::QtQrDecplugin ALIAS QtQrDecplugin) + + +qt6_add_shaders(QtQrDec "esterVtech.com.imports.QtQrDec.shaders" + BATCHABLE + PRECOMPILE + OPTIMIZED + OUTPUT_TARGETS out_targets_var2 + PREFIX + "/esterVtech.com/imports/Designs" + FILES + "frag/qrscanner.frag" +) +target_include_directories(QtQrDec PUBLIC $ + "$") +if(EMSCRIPTEN) + target_compile_definitions(QtQrDec PRIVATE USE_EMSCRIPTEN) +else() + target_link_libraries(QtQrDec PUBLIC Qt6::Multimedia) +endif(EMSCRIPTEN) +target_link_libraries(QtQrDec PUBLIC Qt6::Gui Qt6::Quick QrDec Qt6::Multimedia + EstervDesigns::SimpleStyle EstervDesigns::customControls + $<$,STATIC_LIBRARY>:EstervDesigns::SimpleStyleplugin> + $<$,STATIC_LIBRARY>:EstervDesigns::customControlsplugin>) + +install(TARGETS QtQrDec ${out_targets_var} ${out_targets_var2} + EXPORT ${PROJECT_NAME}-config + DESTINATION ${CMAKE_INSTALL_LIBDIR} + COMPONENT QtQrDec +) +install(DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/include/ + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/Esterv/${PROJECT_NAME} + COMPONENT QtQrDec +) +install(DIRECTORY ${CMAKE_BINARY_DIR}/Esterv/CustomControls/QrDec + DESTINATION ${CMAKE_INSTALL_LIBDIR}/Esterv/CustomControls + COMPONENT QtQrDec +) + +install(TARGETS QtQrDecplugin + EXPORT ${PROJECT_NAME}-config + DESTINATION ${CMAKE_INSTALL_LIBDIR}/Esterv/CustomControls/QrDec + COMPONENT QtQrDec +) + +if(EMSCRIPTEN) + target_compile_definitions(QtQrDec PRIVATE USE_EMSCRIPTEN) +endif(EMSCRIPTEN) +if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME) + add_subdirectory(examples) +endif(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME) +else(Qt6_FOUND AND TARGET QrDec) + message(STATUS "The QML Module for QRCODE decoding will not be built") endif(Qt6_FOUND AND TARGET QrDec) diff --git a/QtQrDec/Config.cmake.in b/QtQrDec/Config.cmake.in deleted file mode 100644 index 22c2283..0000000 --- a/QtQrDec/Config.cmake.in +++ /dev/null @@ -1,3 +0,0 @@ -@PACKAGE_INIT@ - -include ( "${CMAKE_CURRENT_LIST_DIR}/QtQrGenTargets.cmake" ) diff --git a/QtQrDec/Qrimagedecoder.cpp b/QtQrDec/Qrimagedecoder.cpp index b93a0df..e514591 100644 --- a/QtQrDec/Qrimagedecoder.cpp +++ b/QtQrDec/Qrimagedecoder.cpp @@ -5,71 +5,71 @@ #include - +QRImageDecoder* QRImageDecoder::m_instance=nullptr; #ifdef USE_EMSCRIPTEN #include #include -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("instance", &QRImageDecoder::instance, 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) => { - 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 () { - ctx.drawImage(video, 0, 0, canvas.width, canvas.height); - const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height); - const sourceBuffer = imageData.data; - const buffer = _malloc(sourceBuffer.byteLength); - HEAPU8.set(sourceBuffer, buffer); - Module.QRImageDecoder.getdecoder().reload(buffer,video.width,video.height); - _free(buffer); - if(window.localStream.active) - { - requestAnimationFrame(processFrame); - } - else - { - ctx.clearRect(0, 0, canvas.width, canvas.height); - } - }; - processFrame(); - - - }).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 () { + ctx.drawImage(video, 0, 0, canvas.width, canvas.height); + const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height); + const sourceBuffer = imageData.data; + const buffer = _malloc(sourceBuffer.byteLength); + HEAPU8.set(sourceBuffer, buffer); + Module.QRImageDecoder.instance().reload(buffer,video.width,video.height); + _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, (), { - if(window.localStream)window.localStream.getVideoTracks()[0].stop(); - }); + if(window.localStream)window.localStream.getVideoTracks()[0].stop(); +}); #else #if QT_CONFIG(permissions) #include @@ -77,144 +77,146 @@ 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); + + } } #endif - +QRImageDecoder* QRImageDecoder::instance() +{ + if (!m_instance) m_instance=new QRImageDecoder(); + return m_instance; +} 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; -#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(); - } - } - }); - connect(this,&QRImageDecoder::useTorchChanged,this,[=](){ - if(m_camera->isActive()&&m_useTorch) - m_camera->setTorchMode(QCamera::TorchOn); - else - m_camera->setTorchMode(QCamera::TorchOff); - }); +#ifndef USE_EMSCRIPTEN + captureSession->setVideoOutput(videoSink); + QObject::connect(videoSink,&QVideoSink::videoFrameChanged,this,[=](const QVideoFrame & Vframe) + { + + if(m_camera&&m_camera->isActive()&&Vframe.isValid()){ + 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(); + clear(); + 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; - emit text_changed(); - } - m_state=QRImageDecoder::Ready; + 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!="") + { + emit decodedQR(qstr); + } + 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) { @@ -228,16 +230,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(); 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; + m_source="qrimage"+QString::number(index); + emit sourceChanged(); + index++; } diff --git a/QtQrDec/README.md b/QtQrDec/README.md index bb4ebb3..16dfb32 100644 --- a/QtQrDec/README.md +++ b/QtQrDec/README.md @@ -1,63 +1,63 @@ # QtQrDec -This repo produce a library that can detect and decode QRCODEs. +This repo produce a QML Module with custom types that can detect and decode QRCODEs. + +The types should be style independent, but the colors used relies on the [EstervDesigns](https://github.com/EddyTheCo/MyDesigns) +Simple style. +If you want to change the colors in your top qml file one can do +``` +import Esterv.Styles.Simple +... + +Component.onCompleted: +{ +Style.frontColor1= (Style.theme)?LightThemeColor:DarkThemeColor//Like control.palette.text + +Style.frontColor2= ... +Style.frontColor3= ... + +Style.backColor1= ... +Style.backColor2= ... +Style.backColor3= ... +} + +``` The detection and decoding is performed by [OpenCV](https://opencv.org/) libraries. -In case OpenCV is not found on your system CMake will download precompiled libraries from [my action releases](https://github.com/EddyTheCo/install-OpenCV-action). +In case OpenCV is not found on your system CMake will download pre compiled libraries from [my action releases](https://github.com/EddyTheCo/install-OpenCV-action). The library use [QtMultimedia](https://doc.qt.io/qt-6/qtmultimedia-index.html) if not compiling for wasm. If compiling for wasm the library creates a custom ImageProvider that communicates with the browser. You can play with the decoder on [this page](https://eddytheco.github.io/qmlonline/?example_url=qt_qr_dec) -An example on how to add the decoder to your project can be found on [this repository](https://github.com/EddyTheCo/qmlonline) (Only the parts enclosed in the USE_QtQr macros). -In general CMake produce the target 'QtQrDec' so one can link to this library like +## Adding the module to your CMake project ``` -target_link_libraries( QtQrDec) +include(FetchContent) +FetchContent_Declare( + qrCode + GIT_REPOSITORY https://github.com/EddyTheCo/qrCode.git + GIT_TAG v1.0.0 + FIND_PACKAGE_ARGS 1.0 COMPONENTS QtQrDec CONFIG +) +FetchContent_MakeAvailable(qrCode) + +target_link_libraries( qrCode::QtQrDec) ``` -## Using the decoder on QML aplications will be as simple as -``` - QrTextArea - { - id:popup_ - width:300 - height:425 - anchors.centerIn: Overlay.overlay - - description: "Get data from QRCODE" - } -``` +## Examples -For this to work one has to add the custom ImageProvider to the QML engine like in the following main.cpp -``` -#include -#include -#include "Qrimageprovider.hpp" +The [examples](examples) folder shows the use of the different custom types provided by the QML module. -int main(int argc, char *argv[]) -{ - QGuiApplication app(argc, argv); - - QQmlApplicationEngine engine; -#ifdef USE_EMSCRIPTEN - engine.addImageProvider(QLatin1String("wasm"), new WasmImageProvider()); -#endif - const QUrl url(u"qrc:/app/main.qml"_qs); - QObject::connect(&engine, &QQmlApplicationEngine::objectCreated, - &app, [url](QObject *obj, const QUrl &objUrl) { - if (!obj && url == objUrl) - QCoreApplication::exit(-1); - }, Qt::QueuedConnection); - engine.load(url); - - return app.exec(); -} -``` +## Contributing +We appreciate any contribution! +You can open an issue or request a feature also. +You can open a PR to the `develop` branch and the CI/CD will take care of the rest. +Make sure to acknowledge your work, ideas when contributing. diff --git a/QtQrDec/examples/CMakeLists.txt b/QtQrDec/examples/CMakeLists.txt new file mode 100644 index 0000000..576e240 --- /dev/null +++ b/QtQrDec/examples/CMakeLists.txt @@ -0,0 +1,68 @@ +if(BUILD_EXAMPLES) + if(EMSCRIPTEN OR ANDROID) + find_package(Qt6 REQUIRED COMPONENTS QuickControls2) + find_package(EstervDesigns 0.4 REQUIRED COMPONENTS FlatControl CONFIG ) + endif(EMSCRIPTEN OR ANDROID) + + foreach(example "qrcam" "qrtext" + ) + qt_add_executable(${example} ${example}.cpp ) + + qt6_add_qml_module(${example} + URI E${example} + VERSION 1.0 + QML_FILES + "qml/${example}.qml" + RESOURCE_PREFIX + "/esterVtech.com/imports" + IMPORT_PATH ${CMAKE_BINARY_DIR} + ) + if(NOT EMSCRIPTEN) + target_link_libraries(${example} PRIVATE Qt6::Multimedia) + endif(NOT EMSCRIPTEN) + target_link_libraries(${example} PRIVATE Qt::Gui Qt::Qml Qt::Quick $ QtQrDec + $<$,STATIC_LIBRARY>:QtQrDecplugin> + ) + + set_target_properties(${example} PROPERTIES + WIN32_EXECUTABLE ON + MACOSX_BUNDLE ON + ) + install(TARGETS ${example} + BUNDLE DESTINATION . + DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ) + if(QTDEPLOY) + qt_generate_deploy_qml_app_script( + TARGET ${example} + OUTPUT_SCRIPT deploy_script + ) + install(SCRIPT ${deploy_script}) + endif(QTDEPLOY) + if(ANDROID) + set_property(TARGET ${example} APPEND PROPERTY QT_ANDROID_MIN_SDK_VERSION 30) + set_property(TARGET ${example} APPEND PROPERTY QT_ANDROID_TARGET_SDK_VERSION 34) + set_property(TARGET ${example} APPEND PROPERTY QT_ANDROID_SDK_BUILD_TOOLS_REVISION 34.0.0) + + FetchContent_Declare( + android_openssl + DOWNLOAD_EXTRACT_TIMESTAMP true + URL https://github.com/KDAB/android_openssl/archive/refs/heads/master.zip + ) + FetchContent_GetProperties(android_openssl) + if(NOT android_openssl_POPULATED) + FetchContent_Populate(android_openssl) + include(${android_openssl_SOURCE_DIR}/android_openssl.cmake) + add_android_openssl_libraries(${example}) + endif(NOT android_openssl_POPULATED) + + endif(ANDROID) + if(EMSCRIPTEN OR ANDROID) + target_link_libraries(${example} PRIVATE EstervDesigns::FlatControl Qt6::QuickControls2 + $<$,STATIC_LIBRARY>:EstervDesigns::FlatControlplugin> + ) + target_compile_definitions(${example} PRIVATE FORCE_STYLE="Esterv.Controls.Flat") + endif(EMSCRIPTEN OR ANDROID) + endforeach() +endif(BUILD_EXAMPLES) diff --git a/QtQrDec/examples/qml/qrcam.qml b/QtQrDec/examples/qml/qrcam.qml new file mode 100644 index 0000000..387667c --- /dev/null +++ b/QtQrDec/examples/qml/qrcam.qml @@ -0,0 +1,72 @@ + +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Esterv.Styles.Simple +import Esterv.CustomControls.QrDec +import Esterv.CustomControls +ApplicationWindow { + visible: true + id:window + + background:Rectangle + { + color:Style.backColor1 + } + ColumnLayout + { + anchors.fill: parent + RowLayout + { + id:rowlayout + Layout.fillHeight: true + Layout.fillWidth: true + Layout.minimumHeight: 70 + Layout.minimumWidth: 300 + ThemeSwitch + { + id:themeswitch + } + Label + { + id:label + Layout.fillHeight: true + Layout.fillWidth: true + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignBottom + text: "" + elide:Text.ElideRight + color:Style.frontColor2 + } + + Switch + { + id:onoff + + onCheckedChanged: + { + (onoff.checked)?QRImageDecoder.start():QRImageDecoder.stop(); + } + } + } + + QrCam + { + Layout.fillHeight: true + Layout.fillWidth: true + Layout.margins: 20 + } + Connections { + target: QRImageDecoder + function onDecodedQR(data) { + label.text=data; + } + } + } + + + + + + +} diff --git a/QtQrDec/examples/qml/qrtext.qml b/QtQrDec/examples/qml/qrtext.qml new file mode 100644 index 0000000..268ba0a --- /dev/null +++ b/QtQrDec/examples/qml/qrtext.qml @@ -0,0 +1,37 @@ +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Esterv.Styles.Simple +import Esterv.CustomControls.QrDec +import Esterv.CustomControls + +ApplicationWindow { + visible: true + id:window + + background:Rectangle + { + color:Style.backColor1 + } + ThemeSwitch + { + id:themeswitch + width:45 + height:width + } + QrTextField + { + anchors.top:themeswitch.bottom + anchors.horizontalCenter:parent.horizontalCenter + width:300 + height:60 + popWidth:Math.max(parent.width*0.5,300) + popHeight:Math.max(parent.height*0.5,500) + } + + + + + + +} diff --git a/QtQrDec/examples/qrcam.cpp b/QtQrDec/examples/qrcam.cpp new file mode 100644 index 0000000..505e8cf --- /dev/null +++ b/QtQrDec/examples/qrcam.cpp @@ -0,0 +1,24 @@ +#include +#include +#include "Qrimagedecoder.hpp" + +#if defined(FORCE_STYLE) +#include +#endif +int main(int argc, char *argv[]) +{ + QGuiApplication app(argc, argv); + +#if defined(FORCE_STYLE) + QQuickStyle::setStyle(FORCE_STYLE); +#endif + QQmlApplicationEngine engine; + engine.addImageProvider(QLatin1String("wasm"), new WasmImageProvider()); + engine.addImportPath("qrc:/esterVtech.com/imports"); + const QUrl url=QUrl("qrc:/esterVtech.com/imports/Eqrcam/qml/qrcam.qml"); + + engine.load(url); + + return app.exec(); +} + diff --git a/QtQrDec/examples/qrtext.cpp b/QtQrDec/examples/qrtext.cpp new file mode 100644 index 0000000..08c613b --- /dev/null +++ b/QtQrDec/examples/qrtext.cpp @@ -0,0 +1,24 @@ +#include +#include +#include "Qrimagedecoder.hpp" + +#if defined(FORCE_STYLE) +#include +#endif +int main(int argc, char *argv[]) +{ + QGuiApplication app(argc, argv); + +#if defined(FORCE_STYLE) + QQuickStyle::setStyle(FORCE_STYLE); +#endif + QQmlApplicationEngine engine; + engine.addImageProvider(QLatin1String("wasm"), new WasmImageProvider()); + engine.addImportPath("qrc:/esterVtech.com/imports"); + const QUrl url=QUrl("qrc:/esterVtech.com/imports/Eqrtext/qml/qrtext.qml"); + + engine.load(url); + + return app.exec(); +} + diff --git a/QtQrDec/frag/qrscanner.frag b/QtQrDec/frag/qrscanner.frag new file mode 100644 index 0000000..be09eea --- /dev/null +++ b/QtQrDec/frag/qrscanner.frag @@ -0,0 +1,80 @@ +#version 440 +#define PI 3.14159265 +layout(location = 0) in vec2 qt_TexCoord0; +layout(location = 0) out vec4 fragColor; + +layout(std140, binding = 0) uniform buf { + mat4 qt_Matrix; + float qt_Opacity; + vec2 pixelStep; + vec4 fcolor; +}; +layout(binding = 1) uniform sampler2D src; + +float sdOrientedBox( in vec2 p, in vec2 a, in vec2 b, float th ) +{ + float l = length(b-a); + vec2 d = (b-a)/l; + vec2 q = (p-(a+b)*0.5); + q = mat2(d.x,-d.y,d.y,d.x)*q; + q = abs(q)-vec2(l,th)*0.5; + return length(max(q,0.0)) + min(max(q.x,q.y),0.0); +} + +float frame(in vec2 uv, in float width ) +{ + float frameH=1.0-smoothstep(0.0,0.0,sdOrientedBox( uv, vec2(1.5,1.0)*width, + vec2(0.3,0.0+width), width)); + float frameV=1.0-smoothstep(0.0,0.0,sdOrientedBox( uv, vec2(1.0,0.5)*width, + vec2(0.0+width,0.3), width)); + + return clamp(frameH+frameV,0.0,1.0); + +} + + +void main( void) +{ + vec2 uv=qt_TexCoord0; + + float width=0.1; + + vec2 uv4=abs(fract(uv+0.5)-0.5); + + float d=frame(uv4,width); + + float b=0.008; + + d+=1.0-smoothstep(0.0,b,sdOrientedBox( uv, vec2(2.5,6.5)*width, + vec2(4.5,6.5)*width, 2.0*width)); + + d+=1.0-smoothstep(0.0,b,sdOrientedBox( uv, vec2(2.5,2.5)*width, + vec2(3.5,2.5)*width, width)); + + d+=1.0-smoothstep(0.0,b,sdOrientedBox( uv, vec2(3.5,3.5)*width, + vec2(4.5,3.5)*width, width)); + + d+=1.0-smoothstep(0.0,b,sdOrientedBox( uv, vec2(4.5,2.5)*width, + vec2(5.5,2.5)*width, width)); + + d+=1.0-smoothstep(0.0,b,sdOrientedBox( uv, vec2(5.5,3.5)*width, + vec2(6.5,3.5)*width, width)); + + d+=1.0-smoothstep(0.0,b,sdOrientedBox( uv, vec2(6.5,2.5)*width, + vec2(7.5,2.5)*width, width)); + + d+=1.0-smoothstep(0.0,b,sdOrientedBox( uv, vec2(6.5,4.5)*width, + vec2(7.5,4.5)*width, width)); + + d+=1.0-smoothstep(0.0,b,sdOrientedBox( uv, vec2(5.5,5.5)*width, + vec2(6.5,5.5)*width, width)); + + d+=1.0-smoothstep(0.0,b,sdOrientedBox( uv, vec2(6.5,6.5)*width, + vec2(7.5,6.5)*width, width)); + + vec4 bcolor=texture(src, uv).rgba; + vec4 color=mix(bcolor,fcolor , d); + + fragColor = color; + +} diff --git a/QtQrDec/include/Qrimagedecoder.hpp b/QtQrDec/include/Qrimagedecoder.hpp index 2c614ab..76c2795 100644 --- a/QtQrDec/include/Qrimagedecoder.hpp +++ b/QtQrDec/include/Qrimagedecoder.hpp @@ -4,6 +4,7 @@ #include #include #include + #ifndef USE_EMSCRIPTEN #include #include @@ -12,20 +13,26 @@ #include #include #endif + #include class QRImageDecoder : public QObject { Q_OBJECT - Q_PROPERTY(QString text READ get_text NOTIFY text_changed) - Q_PROPERTY(QString source READ get_source NOTIFY source_changed) + Q_PROPERTY(QString source READ get_source NOTIFY sourceChanged) Q_PROPERTY(bool useTorch MEMBER m_useTorch NOTIFY useTorchChanged) Q_PROPERTY(bool hasTorch MEMBER m_hasTorch NOTIFY hasTorchChanged) QML_ELEMENT QML_SINGLETON -public: + QRImageDecoder(QObject *parent = nullptr); +public: + static QRImageDecoder* instance(); + static QRImageDecoder *create(QQmlEngine *qmlEngine, QJSEngine *jsEngine) + { + return instance(); + } enum State { Decoding = 0, Ready @@ -33,23 +40,18 @@ 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;} + QString get_source(void)const{return m_source;} + -#ifdef USE_EMSCRIPTEN - static QRImageDecoder* getdecoder(){return m_decoder;}; -#endif void reload(int offset, int width, int height); signals: - void text_changed(); - void source_changed(); + void decodedQR(QString); + void sourceChanged(); void hasTorchChanged(); void useTorchChanged(); private: State m_state; -#ifdef USE_EMSCRIPTEN - static QRImageDecoder* m_decoder; -#else +#ifndef USE_EMSCRIPTEN QCamera* m_camera; QMediaCaptureSession* captureSession; QVideoSink* videoSink; @@ -57,9 +59,10 @@ class QRImageDecoder : public QObject #endif void setid(); void decodePicture(QImage picture); - QString text,source; + QString m_source; QRDecoder detector; bool m_useTorch,m_hasTorch; + static QRImageDecoder* m_instance; }; diff --git a/QtQrDec/qml/QrCam.qml b/QtQrDec/qml/QrCam.qml index a81c820..f12e59a 100644 --- a/QtQrDec/qml/QrCam.qml +++ b/QtQrDec/qml/QrCam.qml @@ -1,13 +1,16 @@ import QtQuick 2.0 import QtQuick.Controls import QtQuick.Layouts -import MyDesigns -import QtQrDec +import Esterv.Styles.Simple -QrQmlCamera +import Esterv.CustomControls.QrDec +Image { - id:qrscanner - property bool showClose:false; + id:control + + + cache : false + source: "image://wasm/"+QRImageDecoder.source Switch { id:useTorch @@ -19,19 +22,8 @@ QrQmlCamera { QRImageDecoder.useTorch=useTorch.checked; } + onVisibleChanged: useTorch.checked=false; + text:qsTr("Torch") } - 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/QrDecPop.qml b/QtQrDec/qml/QrDecPop.qml new file mode 100644 index 0000000..ead87c8 --- /dev/null +++ b/QtQrDec/qml/QrDecPop.qml @@ -0,0 +1,41 @@ +import QtQuick 2.0 +import QtQuick.Controls +import Esterv.Styles.Simple +import Esterv.CustomControls.QrDec +import Esterv.CustomControls + +Popup +{ + id:control + property bool showClose:true; + signal gotData(string data); + onOpened: QRImageDecoder.start() + onClosed: QRImageDecoder.stop() + Connections { + target: QRImageDecoder + function onDecodedQR(data) { + if(control.enabled&&control.visible) + { + control.gotData(data); + control.visible=false; + } + } + } + QrCam + { + anchors.fill: parent + } + CloseButton + { + id:cbutton + anchors.right: parent.right + anchors.top: parent.top + visible: control.showClose + radius:width + flat:true + onClicked: + { + control.visible=false; + } + } +} diff --git a/QtQrDec/qml/QrQmlCamera.qml b/QtQrDec/qml/QrQmlCamera.qml deleted file mode 100644 index 4825128..0000000 --- a/QtQrDec/qml/QrQmlCamera.qml +++ /dev/null @@ -1,31 +0,0 @@ -import QtQuick 2.0 -import QtQuick.Controls -import QtQrDec -Item -{ - id:root - signal gotdata(string data); - implicitWidth: preview.implicitWidth - implicitHeight: preview.implicitHeight - function stop() { - QRImageDecoder.stop(); - } - function start() { - QRImageDecoder.start(); - } - Connections { - target: QRImageDecoder - function onText_changed(boo) { - root.gotdata(QRImageDecoder.text) - QRImageDecoder.clear(); - } - } - Image { - id: preview - anchors.fill: root - cache : false - source: "image://wasm/"+QRImageDecoder.source - } - - -} diff --git a/QtQrDec/qml/QrTextCamPop.qml b/QtQrDec/qml/QrTextCamPop.qml deleted file mode 100644 index f373c91..0000000 --- a/QtQrDec/qml/QrTextCamPop.qml +++ /dev/null @@ -1,82 +0,0 @@ -import QtQuick 2.0 -import QtQuick.Controls -import QtQuick.Layouts -import MyDesigns -import QtQrDec - -Popup -{ - id:popup_ - property alias label:tfield.label; - property alias textField:tfield.textarea; - - signal clicked(string data); - - onClosed: qrscanner.stop(); - onOpened:{ - tfield.textarea.text=""; - qrscanner.visible=false; - } - - background: Rectangle - { - id:bck - color:CustomStyle.backColor1 - border.width:1 - border.color:CustomStyle.frontColor1 - radius:Math.min(width,height)*0.05 - } - ColumnLayout - { - anchors.fill: parent - MyTextArea - { - id:tfield - Layout.alignment: Qt.AlignHCenter - Layout.margins: 20 - Layout.fillWidth: true - Layout.maximumWidth:250 - Layout.maximumHeight: 200 - focus:true - qrfill:true - onFillqr: - { - qrscanner.start(); - qrscanner.visible=true; - - } - } - QrCam - { - id:qrscanner - Layout.alignment: Qt.AlignCenter - Layout.margins: 5 - Layout.fillHeight: true - Layout.fillWidth: true - Layout.minimumWidth:100 - Layout.minimumHeight: 200 - Layout.maximumWidth: 300 - visible:false - showClose:true - onGotdata: (data)=> { - qrscanner.stop(); - qrscanner.visible=false; - tfield.textarea.text=data; - } - } - MyButton - { - id:send - Layout.alignment: Qt.AlignRight - Layout.margins: 15 - enabled: tfield.textarea.text - onClicked: - { - popup_.close(); - popup_.clicked(tfield.textarea.text); - } - text:qsTr("Ok") - } - - } -} diff --git a/QtQrDec/qml/QrTextField.qml b/QtQrDec/qml/QrTextField.qml new file mode 100644 index 0000000..71f40b6 --- /dev/null +++ b/QtQrDec/qml/QrTextField.qml @@ -0,0 +1,50 @@ +import QtQuick 2.0 +import QtQuick.Controls +import QtQuick.Layouts +import Esterv.Styles.Simple +import Esterv.CustomControls.QrDec + +TextField +{ + id:control + property int popWidth:300 + property int popHeight:500 + rightPadding: control.height*0.9 + QrDecPop + { + id:qrpop + visible:false + closePolicy: Popup.CloseOnPressOutside + anchors.centerIn: Overlay.overlay + width:control.popWidth + height:control.popHeight + onGotData: (data) =>{control.text=data;} + + } + + Rectangle { + id:qricon + height:Math.min(parent.height,font.pixelSize) + width:height + anchors.right: parent.right + anchors.verticalCenter: control.verticalCenter + color: "transparent" + visible: !control.text&&control.enabled + ShaderEffect { + id: shader + property var src: qricon; + property color fcolor:Style.frontColor2 + property var pixelStep: Qt.vector2d(1/src.width, 1/src.height) + fragmentShader: "qrc:/esterVtech.com/imports/Designs/frag/qrscanner.frag.qsb" + anchors.fill: parent + } + MouseArea { + anchors.fill: parent + onClicked: { + qrpop.open(); + } + } + } + + +} diff --git a/QtQrGen/CMakeLists.txt b/QtQrGen/CMakeLists.txt index 3c6456f..d443009 100644 --- a/QtQrGen/CMakeLists.txt +++ b/QtQrGen/CMakeLists.txt @@ -1,71 +1,76 @@ 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.4.1 - FIND_PACKAGE_ARGS 0.4 CONFIG - ) -FetchContent_MakeAvailable(MyDesigns) if (Qt6_FOUND) - qt_standard_project_setup() - qt6_add_qml_module(QtQrGen - URI QtQrGen - VERSION 1.0 - SOURCES Qrimageprovider.cpp include/Qrimageprovider.hpp - QML_FILES - qml/AddressQr.qml - qml/PayQrPop.qml - qml/QrLabel.qml - RESOURCE_PREFIX - "/esterVtech.com/imports" - OUTPUT_TARGETS out_targets_var - OUTPUT_DIRECTORY - ${CMAKE_BINARY_DIR}/QtQrGen - IMPORT_PATH ${CMAKE_BINARY_DIR} - ) + qt_standard_project_setup() + qt6_add_qml_module(QtQrGen + URI Esterv.CustomControls.QrGen + VERSION ${VERSION} + SOURCES Qrimageprovider.cpp include/Qrimageprovider.hpp + QML_FILES + "qml/QrGenImage.qml" + "qml/QrGenPop.qml" + "qml/QrText.qml" + RESOURCE_PREFIX + "/esterVtech.com/imports" + OUTPUT_TARGETS out_targets_var + OUTPUT_DIRECTORY + ${CMAKE_BINARY_DIR}/Esterv/CustomControls/QrGen + IMPORT_PATH ${CMAKE_BINARY_DIR} ${CMAKE_INSTALL_LIBDIR} + ) +add_library(${PROJECT_NAME}::QtQrGen ALIAS QtQrGen) +add_library(${PROJECT_NAME}::QtQrGenplugin ALIAS QtQrGenplugin) +qt6_add_shaders(QtQrGen "esterVtech.com.imports.QtQrGen.shaders" + BATCHABLE + PRECOMPILE + OPTIMIZED + OUTPUT_TARGETS out_targets_var2 + PREFIX + "/esterVtech.com/imports/Designs" + FILES + "frag/qrscanner.frag" +) + +target_include_directories(QtQrGen PUBLIC $ + "$") +if(NOT TARGET Qt6::Svg) + FetchContent_Declare( + qtsvg + GIT_REPOSITORY git://code.qt.io/qt/qtsvg.git + GIT_TAG 6.5.0 + ) +FetchContent_MakeAvailable(qtsvg) +endif() - target_include_directories(QtQrGen PUBLIC $ - "$") - if(NOT TARGET Qt6::Svg) - FetchContent_Declare( - qtsvg - GIT_REPOSITORY git://code.qt.io/qt/qtsvg.git - GIT_TAG 6.5.0 - ) - FetchContent_MakeAvailable(qtsvg) - endif() +target_link_libraries(QtQrGen PUBLIC + Qt6::Quick +) +target_link_libraries(QtQrGen PRIVATE QrGen Qt6::Core Qt6::Gui Qt6::Qml Qt6::Svg + EstervDesigns::SimpleStyle EstervDesigns::customControls + $<$,STATIC_LIBRARY>:EstervDesigns::SimpleStyleplugin> + $<$,STATIC_LIBRARY>:EstervDesigns::customControlsplugin>) - target_link_libraries(QtQrGen PUBLIC - Qt6::Quick - ) - target_link_libraries(QtQrGen PRIVATE - QrGen - Qt6::Core - Qt6::Gui - Qt6::Qml - Qt6::Svg - MyDesigns - $<$,STATIC_LIBRARY>:MyDesignsplugin> - ) +install(TARGETS QtQrGen ${out_targets_var} ${out_targets_var2} + EXPORT ${PROJECT_NAME}-config + DESTINATION ${CMAKE_INSTALL_LIBDIR} + COMPONENT QtQrGen +) +install(DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/include/ + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/Esterv/${PROJECT_NAME} + COMPONENT QtQrGen +) +install(DIRECTORY ${CMAKE_BINARY_DIR}/Esterv/CustomControls/QrGen + DESTINATION ${CMAKE_INSTALL_LIBDIR}/Esterv/CustomControls + COMPONENT QtQrGen +) - install(TARGETS QtQrGen QtQrGenplugin ${out_targets_var} - EXPORT qrCodeTargets - DESTINATION ${CMAKE_INSTALL_LIBDIR} - COMPONENT QtQr - ) - install(DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/include/ - DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/qrCode - COMPONENT QtQr - ) - install(DIRECTORY ${CMAKE_BINARY_DIR}/QtQrGen/ - DESTINATION ${CMAKE_INSTALL_LIBDIR}/QMLPlugins/QtQrGen - COMPONENT QtQr - ) +install(TARGETS QtQrGenplugin + EXPORT ${PROJECT_NAME}-config + DESTINATION ${CMAKE_INSTALL_LIBDIR}/Esterv/CustomControls/QrGen + COMPONENT QtQrGen +) +if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME) + add_subdirectory(examples) +endif(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME) endif(Qt6_FOUND) -if(BUILD_DOCS) - get_target_property(build_docs cmake_build_docs SOURCES) - include(${build_docs}) -endif() diff --git a/QtQrGen/Qrimageprovider.cpp b/QtQrGen/Qrimageprovider.cpp index 741ec9f..1664c9e 100644 --- a/QtQrGen/Qrimageprovider.cpp +++ b/QtQrGen/Qrimageprovider.cpp @@ -4,22 +4,23 @@ #include "Qrimageprovider.hpp" #include - - using namespace qrcodegen; QPixmap QRImageProvider::requestPixmap(const QString &id, QSize *size, const QSize &requestedSize) { const int width = 100; - + QStringList strlist=id.split('/'); + const auto color=strlist.front(); + strlist.removeFirst(); + const auto data=strlist.join('/'); const auto max=(requestedSize.width()>requestedSize.height())?requestedSize.width():requestedSize.height(); QPixmap pixmap(max > 0 ? max : width, max> 0 ? max : width); pixmap.fill( Qt::transparent ); *size = pixmap.size(); - const QrCode qr = QrCode::encodeText(id.toStdString().c_str(), static_cast(errC)); - const auto qrSVGstr=toSvgString(qr, color.name().toStdString()); + const QrCode qr = QrCode::encodeText(data.toStdString().c_str(), static_cast(errC)); + const auto qrSVGstr=toSvgString(qr, color.toStdString()); auto qrImage=QSvgRenderer(QByteArray::fromStdString(qrSVGstr)); QPainter Painter; diff --git a/QtQrGen/README.md b/QtQrGen/README.md index b8dcbdd..3e3e8ae 100644 --- a/QtQrGen/README.md +++ b/QtQrGen/README.md @@ -1,45 +1,56 @@ # QtQrGen -This code produce a library with a custom ImageProvider of Qt. The image provider print a QRCODE from a string. -You can play with the resulting ImageProvider on [this page](https://eddytheco.github.io/qmlonline/?example_url=qt_qr_gen). - An example on how to add the ImageProvider to your project can be found on [this repository](https://github.com/EddyTheCo/qmlonline) (Only the parts enclosed in the USE_QtQr macros). +This code produce a QML module with custom types and a custom ImageProvider of Qt. +The custom types are related to the generation and showing of QRCODEs. -In general CMake produce the target 'QtQrGen' so one can link to this library like -``` -target_link_libraries( QtQrGen) + +The types should be style independent, but the colors used relies on the [EstervDesigns](https://github.com/EddyTheCo/MyDesigns) +Simple style. +If you want to change the colors in your top qml file one can do ``` +import Esterv.Styles.Simple +... +Component.onCompleted: +{ +Style.frontColor1= (Style.theme)?LightThemeColor:DarkThemeColor//Like control.palette.text -## Showing the QRCODE on QML aplications will be as simple as -``` -Image { - sourceSize.width: 300 - source: "image://qrcode/https://eddytheco.github.io/" +Style.frontColor2= ... +Style.frontColor3= ... + +Style.backColor1= ... +Style.backColor2= ... +Style.backColor3= ... } -``` -For this to work one has to add the custom ImageProvider to the QML engine like in the following main.cpp -``` -#include -#include -#include "Qrimageprovider.hpp" +``` -int main(int argc, char *argv[]) -{ - QGuiApplication app(argc, argv); - - QQmlApplicationEngine engine; - engine.addImageProvider(QLatin1String("qrCode"), new QRImageProvider("blue",1)); - const QUrl url(u"qrc:/app/main.qml"_qs); - QObject::connect(&engine, &QQmlApplicationEngine::objectCreated, - &app, [url](QObject *obj, const QUrl &objUrl) { - if (!obj && url == objUrl) - QCoreApplication::exit(-1); - }, Qt::QueuedConnection); - engine.load(url); - - return app.exec(); -} +You can play with the ImageProvider on [this page](https://eddytheco.github.io/qmlonline/?example_url=qt_qr_gen). + + +## Adding the module to your CMake project +``` +include(FetchContent) +FetchContent_Declare( + qrCode + GIT_REPOSITORY https://github.com/EddyTheCo/qrCode.git + GIT_TAG v1.0.0 + FIND_PACKAGE_ARGS 1.0 COMPONENTS QtQrGen CONFIG +) +FetchContent_MakeAvailable(qrCode) + +target_link_libraries( qrCode::QtQrGen) ``` +## Examples + +The [examples](examples) folder shows the use of the different custom types provided by the QML module. + +## Contributing + +We appreciate any contribution! + +You can open an issue or request a feature also. +You can open a PR to the `develop` branch and the CI/CD will take care of the rest. +Make sure to acknowledge your work, ideas when contributing. diff --git a/QtQrGen/examples/CMakeLists.txt b/QtQrGen/examples/CMakeLists.txt new file mode 100644 index 0000000..009f3f6 --- /dev/null +++ b/QtQrGen/examples/CMakeLists.txt @@ -0,0 +1,64 @@ +if(BUILD_EXAMPLES) + if(EMSCRIPTEN OR ANDROID) + find_package(Qt6 REQUIRED COMPONENTS QuickControls2) + find_package(EstervDesigns 0.4 REQUIRED COMPONENTS FlatControl CONFIG ) + endif(EMSCRIPTEN OR ANDROID) + + foreach(example "image" "text" + ) + qt_add_executable(${example} ${example}.cpp ) + + qt6_add_qml_module(${example} + URI E${example} + VERSION 1.0 + QML_FILES + "qml/${example}.qml" + RESOURCE_PREFIX + "/esterVtech.com/imports" + IMPORT_PATH ${CMAKE_BINARY_DIR} + ) + target_link_libraries(${example} PRIVATE Qt::Gui Qt::Qml Qt::Quick QtQrGen + $<$,STATIC_LIBRARY>:QtQrGenplugin> + ) + + set_target_properties(${example} PROPERTIES + WIN32_EXECUTABLE ON + MACOSX_BUNDLE ON + ) + install(TARGETS ${example} + BUNDLE DESTINATION . + DESTINATION ${CMAKE_INSTALL_BINDIR} + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ) + if(QTDEPLOY) + qt_generate_deploy_qml_app_script( + TARGET ${example} + OUTPUT_SCRIPT deploy_script + ) + install(SCRIPT ${deploy_script}) + endif(QTDEPLOY) + if(ANDROID) + set_property(TARGET ${example} APPEND PROPERTY QT_ANDROID_MIN_SDK_VERSION 30) + set_property(TARGET ${example} APPEND PROPERTY QT_ANDROID_TARGET_SDK_VERSION 34) + set_property(TARGET ${example} APPEND PROPERTY QT_ANDROID_SDK_BUILD_TOOLS_REVISION 34.0.0) + + FetchContent_Declare( + android_openssl + DOWNLOAD_EXTRACT_TIMESTAMP true + URL https://github.com/KDAB/android_openssl/archive/refs/heads/master.zip + ) + FetchContent_GetProperties(android_openssl) + if(NOT android_openssl_POPULATED) + FetchContent_Populate(android_openssl) + include(${android_openssl_SOURCE_DIR}/android_openssl.cmake) + add_android_openssl_libraries(${example}) + endif(NOT android_openssl_POPULATED) + endif(ANDROID) + if(EMSCRIPTEN OR ANDROID) + target_link_libraries(${example} PRIVATE EstervDesigns::FlatControl Qt6::QuickControls2 + $<$,STATIC_LIBRARY>:EstervDesigns::FlatControlplugin> + ) + target_compile_definitions(${example} PRIVATE FORCE_STYLE="Esterv.Controls.Flat") + endif(EMSCRIPTEN OR ANDROID) + endforeach() +endif(BUILD_EXAMPLES) diff --git a/QtQrGen/examples/image.cpp b/QtQrGen/examples/image.cpp new file mode 100644 index 0000000..ac60319 --- /dev/null +++ b/QtQrGen/examples/image.cpp @@ -0,0 +1,23 @@ +#include +#include +#include "Qrimageprovider.hpp" +#if defined(FORCE_STYLE) +#include +#endif +int main(int argc, char *argv[]) +{ + QGuiApplication app(argc, argv); + +#if defined(FORCE_STYLE) + QQuickStyle::setStyle(FORCE_STYLE); +#endif + QQmlApplicationEngine engine; + engine.addImportPath("qrc:/esterVtech.com/imports"); + engine.addImageProvider(QLatin1String("qrcode"), new QRImageProvider(1)); + const QUrl url=QUrl("qrc:/esterVtech.com/imports/Eimage/qml/image.qml"); + + engine.load(url); + + return app.exec(); +} + diff --git a/QtQrGen/examples/qml/image.qml b/QtQrGen/examples/qml/image.qml new file mode 100644 index 0000000..052414d --- /dev/null +++ b/QtQrGen/examples/qml/image.qml @@ -0,0 +1,40 @@ + +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Esterv.Styles.Simple +import Esterv.CustomControls.QrGen +import Esterv.CustomControls + +ApplicationWindow { + visible: true + id:window + + background:Rectangle + { + color:Style.backColor1 + } + + ThemeSwitch + { + id:themeswitch + } + + QrGenImage + { + anchors.horizontalCenter:parent.horizontalCenter + anchors.top:themeswitch.bottom + width:parent.width*0.5 + height:parent.height*0.5 + textData:"https://eddytheco.github.io/" + } + + + + + + + + + +} diff --git a/QtQrGen/examples/qml/text.qml b/QtQrGen/examples/qml/text.qml new file mode 100644 index 0000000..1b5b649 --- /dev/null +++ b/QtQrGen/examples/qml/text.qml @@ -0,0 +1,40 @@ + +import QtQuick +import QtQuick.Controls +import QtQuick.Layouts +import Esterv.Styles.Simple +import Esterv.CustomControls.QrGen +import Esterv.CustomControls + +ApplicationWindow { + visible: true + id:window + + background:Rectangle + { + color:Style.backColor1 + } + + ThemeSwitch + { + id:themeswitch + } + + QrText + { + anchors.horizontalCenter:parent.horizontalCenter + anchors.top:themeswitch.bottom + text:"smr1qp9rtwlc00ksp0mvet8ugwvqu03ygzr8s3x77w3df9qw9srm3hwk2l0v9kf" + width:parent.width*0.5 + font.pixelSize: 30 + } + + + + + + + + + +} diff --git a/QtQrGen/examples/text.cpp b/QtQrGen/examples/text.cpp new file mode 100644 index 0000000..02dee2a --- /dev/null +++ b/QtQrGen/examples/text.cpp @@ -0,0 +1,23 @@ +#include +#include +#include "Qrimageprovider.hpp" +#if defined(FORCE_STYLE) +#include +#endif +int main(int argc, char *argv[]) +{ + QGuiApplication app(argc, argv); + +#if defined(FORCE_STYLE) + QQuickStyle::setStyle(FORCE_STYLE); +#endif + QQmlApplicationEngine engine; + engine.addImportPath("qrc:/esterVtech.com/imports"); + engine.addImageProvider(QLatin1String("qrcode"), new QRImageProvider(1)); + const QUrl url=QUrl("qrc:/esterVtech.com/imports/Etext/qml/text.qml"); + + engine.load(url); + + return app.exec(); +} + diff --git a/QtQrGen/frag/qrscanner.frag b/QtQrGen/frag/qrscanner.frag new file mode 100644 index 0000000..be09eea --- /dev/null +++ b/QtQrGen/frag/qrscanner.frag @@ -0,0 +1,80 @@ +#version 440 +#define PI 3.14159265 +layout(location = 0) in vec2 qt_TexCoord0; +layout(location = 0) out vec4 fragColor; + +layout(std140, binding = 0) uniform buf { + mat4 qt_Matrix; + float qt_Opacity; + vec2 pixelStep; + vec4 fcolor; +}; +layout(binding = 1) uniform sampler2D src; + +float sdOrientedBox( in vec2 p, in vec2 a, in vec2 b, float th ) +{ + float l = length(b-a); + vec2 d = (b-a)/l; + vec2 q = (p-(a+b)*0.5); + q = mat2(d.x,-d.y,d.y,d.x)*q; + q = abs(q)-vec2(l,th)*0.5; + return length(max(q,0.0)) + min(max(q.x,q.y),0.0); +} + +float frame(in vec2 uv, in float width ) +{ + float frameH=1.0-smoothstep(0.0,0.0,sdOrientedBox( uv, vec2(1.5,1.0)*width, + vec2(0.3,0.0+width), width)); + float frameV=1.0-smoothstep(0.0,0.0,sdOrientedBox( uv, vec2(1.0,0.5)*width, + vec2(0.0+width,0.3), width)); + + return clamp(frameH+frameV,0.0,1.0); + +} + + +void main( void) +{ + vec2 uv=qt_TexCoord0; + + float width=0.1; + + vec2 uv4=abs(fract(uv+0.5)-0.5); + + float d=frame(uv4,width); + + float b=0.008; + + d+=1.0-smoothstep(0.0,b,sdOrientedBox( uv, vec2(2.5,6.5)*width, + vec2(4.5,6.5)*width, 2.0*width)); + + d+=1.0-smoothstep(0.0,b,sdOrientedBox( uv, vec2(2.5,2.5)*width, + vec2(3.5,2.5)*width, width)); + + d+=1.0-smoothstep(0.0,b,sdOrientedBox( uv, vec2(3.5,3.5)*width, + vec2(4.5,3.5)*width, width)); + + d+=1.0-smoothstep(0.0,b,sdOrientedBox( uv, vec2(4.5,2.5)*width, + vec2(5.5,2.5)*width, width)); + + d+=1.0-smoothstep(0.0,b,sdOrientedBox( uv, vec2(5.5,3.5)*width, + vec2(6.5,3.5)*width, width)); + + d+=1.0-smoothstep(0.0,b,sdOrientedBox( uv, vec2(6.5,2.5)*width, + vec2(7.5,2.5)*width, width)); + + d+=1.0-smoothstep(0.0,b,sdOrientedBox( uv, vec2(6.5,4.5)*width, + vec2(7.5,4.5)*width, width)); + + d+=1.0-smoothstep(0.0,b,sdOrientedBox( uv, vec2(5.5,5.5)*width, + vec2(6.5,5.5)*width, width)); + + d+=1.0-smoothstep(0.0,b,sdOrientedBox( uv, vec2(6.5,6.5)*width, + vec2(7.5,6.5)*width, width)); + + vec4 bcolor=texture(src, uv).rgba; + vec4 color=mix(bcolor,fcolor , d); + + fragColor = color; + +} diff --git a/QtQrGen/include/Qrimageprovider.hpp b/QtQrGen/include/Qrimageprovider.hpp index 42b91a2..b455aba 100644 --- a/QtQrGen/include/Qrimageprovider.hpp +++ b/QtQrGen/include/Qrimageprovider.hpp @@ -4,15 +4,14 @@ class QRImageProvider : public QQuickImageProvider { public: - QRImageProvider(QColor col="black",int erc=0) - : QQuickImageProvider(QQuickImageProvider::Pixmap),color(col),errC(erc) + QRImageProvider(int erc=0) + : QQuickImageProvider(QQuickImageProvider::Pixmap),errC(erc) { } QPixmap requestPixmap(const QString &id, QSize *size, const QSize &requestedSize) override; private: - const QColor color; const int errC; }; diff --git a/QtQrGen/qml/AddressQr.qml b/QtQrGen/qml/AddressQr.qml deleted file mode 100644 index 2c541a7..0000000 --- a/QtQrGen/qml/AddressQr.qml +++ /dev/null @@ -1,47 +0,0 @@ -import QtQuick.Controls -import QtQuick -import MyDesigns -import QtQrGen - -Rectangle { - id:root - required property string address - property string url - radius: 10 - - TextClipboard - { - id:tclip - text:root.address - } - - Image { - id:img - anchors.centerIn:parent - sourceSize.width: root.width-10 - source: "image://qrcodeblack/"+root.address - MouseArea { - anchors.fill: img - hoverEnabled :true - onEntered: tooltip.visible=!tooltip.visible - onExited: tooltip.visible=!tooltip.visible - onClicked: - { - - tclip.copy(); - if(root.url) - { - Qt.openUrlExternally(root.url) - } - } - } - } - ToolTip - { - id:tooltip - visible: false - text:qsTr("Copy") - } - - -} diff --git a/QtQrGen/qml/PayQrPop.qml b/QtQrGen/qml/PayQrPop.qml deleted file mode 100644 index 3387041..0000000 --- a/QtQrGen/qml/PayQrPop.qml +++ /dev/null @@ -1,57 +0,0 @@ -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 qrcode:qrcode_; - - background: Rectangle - { - id:bck - color:CustomStyle.backColor1 - border.width:1 - border.color:CustomStyle.frontColor1 - radius:Math.min(width,height)*0.05 - - } - - modal: true - focus: true - - ColumnLayout - { - anchors.fill: parent - spacing:10 - MyTextArea - { - id:tex - Layout.fillWidth: true - Layout.fillHeight: true - Layout.alignment: Qt.AlignTop|Qt.AlignHCenter - Layout.minimumHeight: 100 - label.visible: false - textarea.text: root.description - textarea.readOnly: true - textarea.wrapMode: Text.Wrap - } - - - AddressQr - { - id:qrcode_ - address:root.address - url:root.url - Layout.preferredWidth: tex.width*0.75 - Layout.preferredHeight: width - Layout.alignment: Qt.AlignCenter - } - } - -} - diff --git a/QtQrGen/qml/QrGenImage.qml b/QtQrGen/qml/QrGenImage.qml new file mode 100644 index 0000000..502a275 --- /dev/null +++ b/QtQrGen/qml/QrGenImage.qml @@ -0,0 +1,22 @@ +import QtQuick.Controls +import QtQuick +import QtQml +import Esterv.Styles.Simple + +Control +{ + id:control + required property string textData + implicitWidth: 100 + implicitHeight: 100 + background: Rectangle { + radius: Math.min(width,height)*0.8*Style.roundedScale/Style.Scale.Full + color:Style.backColor3 + } + Image { + id:img + anchors.centerIn:parent + sourceSize.width: Math.min(control.width,control.height)-control.background.radius-10 + source: "image://qrcode/"+Style.frontColor1+"/"+control.textData + } +} diff --git a/QtQrGen/qml/QrGenPop.qml b/QtQrGen/qml/QrGenPop.qml new file mode 100644 index 0000000..bee696e --- /dev/null +++ b/QtQrGen/qml/QrGenPop.qml @@ -0,0 +1,74 @@ +import QtQuick 2.0 +import QtQuick.Controls +import QtQuick.Layouts +import Esterv.CustomControls +import Esterv.Styles.Simple + +Popup { + id: control + required property string textData; + property bool showClose:true; + + ColumnLayout + { + anchors.fill:parent + Item + { + Layout.fillHeight: true + Layout.fillWidth: true + Layout.minimumHeight: 50 + Layout.maximumHeight: 100 + Switch + { + id:showdata + text: qsTr("Show text") + } + CloseButton + { + id:cbutton + anchors.top: parent.top + radius:width + anchors.right: parent.right + visible: control.showClose + + flat:true + onClicked: + { + control.visible=false; + } + } + } + Item + { + Layout.minimumHeight: 100 + Layout.minimumWidth: 200 + Layout.fillWidth: true + Layout.fillHeight: true + ScrollView { + anchors.fill:parent + TextArea + { + id:tex + text: control.textData + readOnly: true + wrapMode: Text.Wrap + + } + } + visible:showdata.checked + } + QrGenImage + { + id:qrgenimage + textData:control.textData + visible:!tex.visible + Layout.fillHeight: true + Layout.fillWidth: true + } + + } + + + +} + diff --git a/QtQrGen/qml/QrLabel.qml b/QtQrGen/qml/QrLabel.qml deleted file mode 100644 index 330db9a..0000000 --- a/QtQrGen/qml/QrLabel.qml +++ /dev/null @@ -1,36 +0,0 @@ -import QtQuick.Controls -import QtQuick -import MyDesigns -import QtQrGen - - - -Text -{ - id:root - property string description:""; - required property string address; - - PayQrPop - { - id:popup_ - address:root.address - description:root.address - visible:false - closePolicy: Popup.CloseOnPressOutside - anchors.centerIn: Overlay.overlay - focus: false - modal:false - width:300 - } - - text:((root.description)?(""+ root.description +': '):'') +' '+ root.address +'' - elide:Text.ElideRight - horizontalAlignment: TextEdit.AlignLeft - fontSizeMode:Text.VerticalFit - color:CustomStyle.frontColor1 - MouseArea { - anchors.fill: parent - onClicked: popup_.visible=true; - } -} diff --git a/QtQrGen/qml/QrText.qml b/QtQrGen/qml/QrText.qml new file mode 100644 index 0000000..0349db9 --- /dev/null +++ b/QtQrGen/qml/QrText.qml @@ -0,0 +1,50 @@ +import QtQuick.Controls +import QtQuick + +import Esterv.Styles.Simple + + +Text +{ + id:control + property int popWidth:300 + property int popHeight:500 + QrGenPop + { + id:qrgenpop + textData:control.text + visible:false + closePolicy: Popup.CloseOnPressOutside + anchors.centerIn: Overlay.overlay + width:control.popWidth + height:control.popHeight + } + color:Style.frontColor1 + elide:Text.ElideRight + horizontalAlignment: TextEdit.AlignLeft + + rightPadding: control.height*0.9 + + Rectangle { + id:qricon + height:Math.min(parent.height,font.pixelSize) + width:height + x: parent.contentWidth + color: "transparent" + ShaderEffect { + id: shader + property var src: qricon; + property color fcolor:Style.frontColor2 + property var pixelStep: Qt.vector2d(1/src.width, 1/src.height) + fragmentShader: "qrc:/esterVtech.com/imports/Designs/frag/qrscanner.frag.qsb" + anchors.fill: parent + } + + } + MouseArea { + anchors.fill: parent + onClicked: { + qrgenpop.open(); + } + } +} diff --git a/README.md b/README.md index c92a1e7..d403460 100644 --- a/README.md +++ b/README.md @@ -1,26 +1,28 @@ # qrCode This repository is intended to provide a library for working with QR codes from c++. The main purpose is to exploit modern CMake and facilitate reuse and develop. -The GUI part will be based on Qt libraries and QML. Examples of this library compiled for WebAssembly can be found on: + +The GUI part will be based on Qt libraries and QML. Examples of this library compiled for Web Assembly can be found on: - [QtQrGen](https://eddytheco.github.io/qmlonline/?example_url=qt_qr_gen) - [QtQrDec](https://eddytheco.github.io/qmlonline/?example_url=qt_qr_dec) -## Adding the libraries to your CMake project will be as easy as +## Adding the libraries to your CMake project ```CMake include(FetchContent) - FetchContent_Declare( - qrCode - GIT_REPOSITORY git@github.com:EddyTheCo/qrCode.git - GIT_TAG v0.1.2 - FIND_PACKAGE_ARGS 0.1 CONFIG - ) +FetchContent_Declare( + qrCode + GIT_REPOSITORY https://github.com/EddyTheCo/qrCode.git + GIT_TAG v1.0.0 + FIND_PACKAGE_ARGS 1.0 CONFIG + ) FetchContent_MakeAvailable(qrCode) -target_link_libraries( QrGen QtQrGen QrDec QtQrDec) +target_link_libraries( qrCode::QrGen qrCode::QtQrGen qrCode::QrDec qrCode::QtQrDec) ``` For more information check - +- [QrGen](QrGen/README.md) +- [QrDec](QrDec/README.md) - [QtQrGen](QtQrGen/README.md) - [QtQrDec](QtQrDec/README.md)