├── .gitignore ├── .gitmodules ├── LICENSE ├── LICENSE.Qt ├── README.md ├── assets ├── Group 1.png ├── Qt-service-partner-badge.png ├── SCodes.png ├── buildWithQt.png ├── generator.gif ├── iso 13485.png ├── iso 9001.png └── scanner.gif ├── doc └── detailsQt6.md ├── examples ├── QmlBarcodeGenerator │ ├── .gitignore │ ├── CMakeLists.txt │ ├── ColorController.cpp │ ├── ColorController.h │ ├── QmlBarcodeGenerator.pro │ ├── android.7z │ ├── android │ │ ├── AndroidManifest.xml │ │ ├── build.gradle │ │ ├── gradle.properties │ │ ├── gradle │ │ │ └── wrapper │ │ │ │ ├── gradle-wrapper.jar │ │ │ │ └── gradle-wrapper.properties │ │ ├── gradlew │ │ ├── gradlew.bat │ │ └── res │ │ │ ├── drawable-hdpi │ │ │ └── icon.png │ │ │ ├── drawable-ldpi │ │ │ └── icon.png │ │ │ ├── drawable-mdpi │ │ │ └── icon.png │ │ │ ├── drawable-xhdpi │ │ │ └── icon.png │ │ │ ├── drawable-xxhdpi │ │ │ └── icon.png │ │ │ ├── drawable-xxxhdpi │ │ │ └── icon.png │ │ │ └── values │ │ │ └── libs.xml │ ├── cmake │ │ └── Locations.cmake │ ├── main.cpp │ ├── qml.qrc │ └── qml │ │ ├── CButton.qml │ │ ├── CComboBox.qml │ │ ├── CTextField.qml │ │ ├── GeneratorPage.qml │ │ └── Theme.qml └── QmlBarcodeReader │ ├── .gitignore │ ├── CMakeLists.txt │ ├── QmlBarcodeReader.pro │ ├── Qt5qml.qrc │ ├── Qt6qml.qrc │ ├── android │ ├── AndroidManifest.xml │ ├── build.gradle │ ├── gradle.properties │ ├── gradle │ │ └── wrapper │ │ │ ├── gradle-wrapper.jar │ │ │ └── gradle-wrapper.properties │ ├── gradlew │ ├── gradlew.bat │ └── res │ │ ├── drawable-hdpi │ │ └── icon.png │ │ ├── drawable-ldpi │ │ └── icon.png │ │ ├── drawable-mdpi │ │ └── icon.png │ │ ├── drawable-xhdpi │ │ └── icon.png │ │ ├── drawable-xxhdpi │ │ └── icon.png │ │ ├── drawable-xxxhdpi │ │ └── icon.png │ │ └── values │ │ └── libs.xml │ ├── cmake │ └── Locations.cmake │ ├── main.cpp │ ├── qml │ ├── Qt5ScannerOverlay.qml │ ├── Qt5ScannerPage.qml │ ├── Qt6ScannerOverlay.qml │ ├── Qt6ScannerPage.qml │ └── Theme.qml │ └── qrScanner │ ├── QrDecoder.cpp │ ├── QrDecoder.h │ ├── QrScannerFilter.cpp │ └── QrScannerFilter.h └── src ├── CMakeLists.txt ├── SBarcodeDecoder.cpp ├── SBarcodeDecoder.h ├── SBarcodeFilter.cpp ├── SBarcodeFilter.h ├── SBarcodeFormat.cpp ├── SBarcodeFormat.h ├── SBarcodeGenerator.cpp ├── SBarcodeGenerator.h ├── SBarcodeScanner.cpp ├── SBarcodeScanner.h ├── SCodes.pri ├── private └── debug.h └── qvideoframeconversionhelper_p.h /.gitignore: -------------------------------------------------------------------------------- 1 | # This file is used to ignore files which are generated 2 | # ---------------------------------------------------------------------------- 3 | 4 | *~ 5 | *.autosave 6 | *.a 7 | *.core 8 | *.moc 9 | *.o 10 | *.obj 11 | *.orig 12 | *.rej 13 | *.so 14 | *.so.* 15 | *_pch.h.cpp 16 | *_resource.rc 17 | *.qm 18 | .#* 19 | *.*# 20 | core 21 | examples/build* 22 | !core/ 23 | tags 24 | .DS_Store 25 | .directory 26 | *.debug 27 | Makefile* 28 | *.prl 29 | *.app 30 | moc_*.cpp 31 | ui_*.h 32 | qrc_*.cpp 33 | Thumbs.db 34 | *.res 35 | *.rc 36 | /.qmake.cache 37 | /.qmake.stash 38 | 39 | # qtcreator generated files 40 | *.pro.user* 41 | *.txt.user* 42 | build-* 43 | build 44 | 45 | # xemacs temporary files 46 | *.flc 47 | 48 | # Vim temporary files 49 | .*.swp 50 | 51 | # Visual Studio generated files 52 | *.ib_pdb_index 53 | *.idb 54 | *.ilk 55 | *.pdb 56 | *.sln 57 | *.suo 58 | *.vcproj 59 | *vcproj.*.*.user 60 | *.ncb 61 | *.sdf 62 | *.opensdf 63 | *.vcxproj 64 | *vcxproj.* 65 | 66 | # MinGW generated files 67 | *.Debug 68 | *.Release 69 | 70 | # Python byte code 71 | *.pyc 72 | 73 | # Binaries 74 | # -------- 75 | *.dll 76 | *.exe 77 | 78 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "src/zxing-cpp"] 2 | path = src/zxing-cpp 3 | url = https://github.com/nu-book/zxing-cpp.git 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | 203 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![SCodes ](/assets/SCodes.png) 2 | # SCodes 3 | 4 | This project is Qt & Qml wrapper for [ZXing-C++ Library](https://github.com/nu-book/zxing-cpp) that is used for decoding and generating 1D and 2D barcodes. This particular C++ ZXing port is one of the most recent C++ versions of popular ZXing library using modern compilers. 5 | 6 | Thanks to SCodes you can start scanning barcodes in few steps. We used Qt 5.15.2 and Qt 6.3.0 to built wrapper and example applications, but it's compatible with older Qt versions as well. 7 | 8 | Implementation of same method for both Qt version does not seems possible([check why](#porting)). We have ported the SCodes wrapper to Qt6 by following the multimedia [changes](https://doc-snapshots.qt.io/qt6-6.3/qtmultimedia-changes-qt6.html). 9 | 10 | --- 11 | 12 | [![Somco Software](./assets/Group%201.png)](https://somcosoftware.com) 13 | 14 | [![Built with Qt](./assets/buildWithQt.png)](https://qt.io) 15 | 16 | --- 17 | 18 | ## Supported Formats 19 | 20 | There are plenty of supported formats and we constantly work on adding new. 21 | 22 | ## Supported 1D Formats 23 | 24 | | Format | Supports scanning | Supports generating 25 | | ---------------- | ------------------------ | ------------------- 26 | | UPC-A |
✔️
|
✔️
27 | | UPC-E |
✔️
|
✔️
28 | | EAN-8 |
✔️
|
✔️
29 | | EAN-13 |
✔️
|
✔️
30 | | DataBar |
✔️
|
31 | | DataBar Expanded |
|
32 | | Code 39 |
✔️
|
✔️
33 | | Code 93 |
✔️
|
✔️
34 | | Code 128 |
✔️
|
✔️
35 | | Codabar |
✔️
|
✔️
36 | | ITF |
|
✔️
37 | 38 | ## Supported 2D Formats 39 | 40 | | Format | Supports scanning | Supports generating 41 | | ------------ | ------------------------ | ------------------- 42 | | QR Code |
✔️
|
✔️
43 | | DataMatrix |
✔️
|
✔️
44 | | Aztec |
✔️
|
✔️
45 | | PDF417 |
✔️
|
✔️
46 | | MaxiCode |
|
47 | 48 | 49 | # How to use wrapper? 50 | ![SCodes Scanner Preview](/assets/scanner.gif)![SCodes Generator Preview](/assets/generator.gif) 51 | 52 | ## Using 53 | 54 | Feel free to read ["How to scan barcodes in Qt Qml application" blog post](https://somcosoftware.com/en/blog/how-to-scan-barcodes-in-qt-qml-application) if you are interested in the details behind scanning mechanism. Also you can try out the QmlReaderExample in order to see how it is working. 55 | 56 | SCodes supports generating barcodes as well. It is covered in ["How to generate barcode in Qt Qml" application blog post](https://somcosoftware.com/en/blog/how-to-generate-barcode-in-qt-qml-application). Also you can try out the QmlGeneratorExample in order to see how it is working. 57 | 58 | Above blog posts contains step by step tutorial on how to do that for Qt5 version. For Qt6 ([see here](#porting)). 59 | 60 | ### qmake 61 | All you need to do is to follow these steps. 62 | 63 | 1. Add SCodes as submodule, by typing `git submodule add git@github.com:scytheStudio/SCodes.git` 64 | 2. Update submodule `git submodule update --recursive --init` (you can also put wrapper files to your project manually without adding submodule) 65 | 3. Add `include(scodes/src/SCodes.pri)` to your .pro file 66 | 4. If you want to use barcode reader functionality you need to register `SBarcodeFilter` class for Qt5 or `SBarcodeScanner` class for Qt6. For both version, separate them with if directive to register as we did in barcode reader example([how to register reader class](#register-reader)). As for barcode generator functionality you just need to register `SBarcodeGenerator` class([how to register generator class](#register-generator)). 67 | 5. Import SCodes in your Qml file `import com.scythestudio.scodes 1.0` 68 | 6. Import multimedia module `import QtMultimedia 5.15` for Qt5 or `import QtMultimedia` for Qt6. 69 | 7. If build fails, try to add `CONFIG += c++17` to your .pro file 70 | 8. You are done. Get inspired by [Qt5 QML Barcode Reader demo](https://github.com/scytheStudio/SCodes/blob/master/examples/QmlBarcodeReader/qml/Qt5ScannerPage.qml) or [Qt6 QML Barcode Reader demo](https://github.com/scytheStudio/SCodes/blob/master/examples/QmlBarcodeReader/qml/Qt6ScannerPage.qml) to test wrapper. 71 | 72 | ### CMake 73 | 74 | 1. Add SCodes as submodule, by typing `git submodule add git@gitlab.com:scythestudio/scodes.git` 75 | 2. Update submodule `git submodule update --recursive --init` (you can also put wrapper files to your project manually without adding submodule) 76 | 3. Add to your project SCodes library 77 | 78 | ```CMake 79 | add_subdirectory(SCodes) 80 | ``` 81 | 82 | 4. Link SCodes library to your library or executable. 83 | 84 | ```CMake 85 | target_link_libraries(${PROJECT_NAME} PUBLIC SCodes) 86 | ``` 87 | 88 | 5. Import SCodes in your Qml file 89 | 90 | ```qml 91 | import com.scythestudio.scodes 1.0 92 | ``` 93 | 94 | 6. You are done. Get inspired by [QML Barcode Reader demo](https://github.com/scytheStudio/SCodes/blob/master/examples/QmlBarcodeReader/qml/ScannerPage.qml) to test wrapper. 95 | 96 | 97 | ### How to do 98 | Registering the barcode reader classes with if directive: 99 | 100 | ```c++ 101 | #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 102 | qmlRegisterType("com.scythestudio.scodes", 1, 0, "SBarcodeScanner"); 103 | #else 104 | qmlRegisterType("com.scythestudio.scodes", 1, 0, "SBarcodeScanner"); 105 | #endif 106 | ``` 107 | 108 | Registering the barcode generator class with associated enum: 109 | ```c++ 110 | qmlRegisterType("com.scythestudio.scodes", 1, 0, "SBarcodeGenerator"); 111 | qmlRegisterUncreatableMetaObject(SCodes::staticMetaObject, "com.scythestudio.scodes", 1, 0, "SCodes", "Error: only enums"); 112 | ``` 113 | 114 | 115 | ### Implementation details in Qt6 116 | 117 | Qt's multimedia library has major changes. The most importants are, changes in QML `VideoOutput`, absence of `QVideoFilterRunnable` and `QAbstractVideoFilter` classes in Qt6. 118 | 119 | SCodes library is using `SBarcodeFilter` class for Qt5 and `SBarcodesScanner` class for Qt6 version. 120 | 121 | If you want to read more about implementation details of the library in Qt6 read the document: [Implementation Details in Qt6](https://github.com/scytheStudio/SCodes/blob/master/doc/detailsQt6.md) 122 | 123 | 124 | ### Trying various formats 125 | `SBarcodeFilter` is a class that you need to use for scanning case. By default it scans only specific basic formats of code (Code 39, Code 93, Code 128, QR Code and DataMatrix.). 126 | The goal of that is to limit number of possible formats and improve performance. 127 | 128 | To specify formats that should be accepted by the `SBarcodeFilter` instance, you need to set it's `format` property accordingly. This property allows setting multiple enum values as it's for flags. Add the following to your `SBarcodeFilter` item in Qml code: 129 | ```qml 130 | Component.onCompleted: { 131 | barcodeFilter.format = SCodes.OneDCodes 132 | } 133 | ``` 134 | See the enumeration values that represent supported formats in [SBarcodeFormat.h](https://github.com/scytheStudio/SCodes/blob/master/src/SBarcodeFormat.h) 135 | To accept all supported formats use `SCodes.Any`. 136 | 137 | ## Note 138 | 139 | Both build systems have their examples located in same directory. All you need to do is to just open proper file(CMakeLists.txt or *.pro file) for different build system to be used. 140 | 141 | 142 | ### The examples tested on below kits: 143 | 144 | #### Qt5.15.2 or less, 145 | 146 | | PROJECT | BUILD SYSTEM | WINDOWS-MinGW | WINDOWS-MSVC | LINUX-GCC | ANDROID | 147 | | ------ | ------ | ------ | ------ | ------ | ------ | 148 | | QmlBarcodeReader | qmake |
✔️
|
✔️
|
✔️
|
✔️
| 149 | | QmlBarcodeGenerator | qmake |
✔️
|
✔️
|
✔️
|
✔️
| 150 | | QmlBarcodeReader | CMake |
|
✔️
|
✔️
|
✔️
| 151 | | QmlBarcodeGenerator | CMake |
|
✔️
|
✔️
|
✔️
| 152 | 153 | #### Qt6.3.0, 154 | 155 | | PROJECT | BUILD SYSTEM | WINDOWS-MinGW | WINDOWS-MSVC | LINUX-GCC | ANDROID | 156 | | ------ | ------ | ------ | ------ | ------ | ------ | 157 | | QmlBarcodeReader | qmake |
✔️
|
✔️
|
✔️
|
✔️
| 158 | | QmlBarcodeGenerator | qmake |
✔️
|
✔️
|
✔️
|
✔️
| 159 | | QmlBarcodeReader | CMake |
✔️
|
✔️
|
✔️
|
✔️
| 160 | | QmlBarcodeGenerator | CMake |
✔️
|
✔️
|
✔️
|
✔️
| 161 | 162 | Please ensure that proper Java & NDK version installed on your system. This examples tested w/ Java 11 and 22.1.7171670 Android NDK version. 163 | 164 | ## About Somco Software (previously Scythe Studio) 165 | We’re a team of **Qt and C++ enthusiasts** dedicated to helping businesses build great cross-platform applications. As an official Qt Service Partner, we’ve earned the trust of companies across various industries by delivering high-quality, reliable solutions. With years of experience in **Qt and QML development**, we know how to turn ambitious ideas into outstanding products. 166 | 167 | 168 | 169 | 175 | 181 | 186 | 191 | 192 |
170 | 171 | 173 | 174 | 176 | 177 | 179 | 180 | 182 | 183 | 184 | 185 | 187 | 188 | 189 | 190 |
193 | 194 | We offer a wide range of services—from brainstorming ideas to delivering polished applications—always tailored to our clients’ needs. By combining deep knowledge of Qt modules and modern technologies with a practical, cost-effective approach, we create solutions that truly make a difference. 195 | 196 | ## Professional Support 197 | Need help with anything? We’ve got you covered. Our professional support services are here to assist you with. For more details about support options and pricing, just drop us a line at https://somcosoftware.com/en/contact. 198 | 199 | ## Follow us 200 | 201 | Check out those links if you want to see Somco Software in action and follow the newest trends saying about Qt Qml development. 202 | 203 | * 🌐 [Somco Software Website](https://somcosoftware.com/en/) 204 | * ✍️ [Somco Software Blog Website](https://somcosoftware.com/en/blog) 205 | * 👔 [Somco Software LinkedIn Profile](https://www.linkedin.com/company/scythestudio/mycompany/) 206 | * 👔 [Somco Software Facebook Page](https://www.facebook.com/ScytheStudiio) 207 | * 🎥 [Somco Software Youtube Channel](https://www.youtube.com/channel/UCf4OHosddUYcfmLuGU9e-SQ/featured) 208 | -------------------------------------------------------------------------------- /assets/Group 1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/somcosoftware/SCodes/c0647299d6be021ac59f57e031c794bd58757efe/assets/Group 1.png -------------------------------------------------------------------------------- /assets/Qt-service-partner-badge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/somcosoftware/SCodes/c0647299d6be021ac59f57e031c794bd58757efe/assets/Qt-service-partner-badge.png -------------------------------------------------------------------------------- /assets/SCodes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/somcosoftware/SCodes/c0647299d6be021ac59f57e031c794bd58757efe/assets/SCodes.png -------------------------------------------------------------------------------- /assets/buildWithQt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/somcosoftware/SCodes/c0647299d6be021ac59f57e031c794bd58757efe/assets/buildWithQt.png -------------------------------------------------------------------------------- /assets/generator.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/somcosoftware/SCodes/c0647299d6be021ac59f57e031c794bd58757efe/assets/generator.gif -------------------------------------------------------------------------------- /assets/iso 13485.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/somcosoftware/SCodes/c0647299d6be021ac59f57e031c794bd58757efe/assets/iso 13485.png -------------------------------------------------------------------------------- /assets/iso 9001.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/somcosoftware/SCodes/c0647299d6be021ac59f57e031c794bd58757efe/assets/iso 9001.png -------------------------------------------------------------------------------- /assets/scanner.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/somcosoftware/SCodes/c0647299d6be021ac59f57e031c794bd58757efe/assets/scanner.gif -------------------------------------------------------------------------------- /doc/detailsQt6.md: -------------------------------------------------------------------------------- 1 | # Implementation details in Qt 6 2 | VideoOutput QML element has major changes and it is not possible to use same QML files for both version. If you want to implement barcode reader functionality for both version you need to create two separate QML file too(that's because of QML VideoOutput changes in multimedia module of Qt6). Check our [QmlBarcodeReader example](https://github.com/scytheStudio/SCodes/tree/master/examples/QmlBarcodeReader) for more details. 3 | 4 | `SBarcodeFilter.cpp` and `SBarcodesScanner.cpp` files included/excluded according to the Qt version in the [SCodes CMakeLists file](https://github.com/scytheStudio/SCodes/blob/master/src/CMakeLists.txt). The idea of excluding the related class according to Qt version is prevent to get error from not existing libraries when you compile the project for Qt6(e.g. QVideoFilterRunnable, QAbstractVideoFilter). Likewise in Qt5 for QVideoSink. 5 | 6 | SBarcodeScanner class is inherited from QVideoSink class. It's initiated in 2 phases: First, the constructor sets up the connections to processing threads. Then, after QmlEngine sets up properties, `forwardVideoSink` and `camera`, a `componentComplete()` function is called that instantiates a default `QCamera` if none is set. 7 | 8 | This allows to set camera object in QML: 9 | ```qml 10 | SBarcodeScanner { 11 | ... 12 | camera: Camera { 13 | ... 14 | } 15 | } 16 | 17 | ``` 18 | 19 | Also, in the constructor, `Worker` object that dependent on scanner variable passed to workerThread instance. So, we can access to resources of the scanner object. 20 | ```c++ 21 | worker->moveToThread(&workerThread); 22 | ``` 23 | `VideoOutput` has a `forwardVideoSink` property in Qt6 which allows to pass the videoframes further to a `VideoOutput` sink or some other process. 24 | 25 | To handle the frames `QVideoSink::videoFrameChanged` signal connected to `SBarcodeScanner::handleFrameCaptured` slot. 26 | As soon as new frame has came to the handle function; 27 | ```c++ 28 | emit process(QImage &img); 29 | ``` 30 | signal emitted and `imageProcess` function started to run in worker thread. 31 | Also, frame passed to m_videoSink in order to show the frames on the screen. 32 | ```c++ 33 | m_videoSink->setVideoFrame(frame); 34 | ``` 35 | -------------------------------------------------------------------------------- /examples/QmlBarcodeGenerator/.gitignore: -------------------------------------------------------------------------------- 1 | *.pro.user 2 | *.pro.user* 3 | build-* 4 | *DS_Store 5 | -------------------------------------------------------------------------------- /examples/QmlBarcodeGenerator/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.16.3) 2 | 3 | project(QmlBarcodeGenerator LANGUAGES CXX) 4 | 5 | set(CMAKE_INCLUDE_CURRENT_DIR ON) 6 | 7 | set(CMAKE_AUTOMOC ON) 8 | set(CMAKE_AUTORCC ON) 9 | 10 | set(CMAKE_CXX_STANDARD 17) 11 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 12 | 13 | #Check this file for any *_DIR variable definitions and other 14 | include("cmake/Locations.cmake") 15 | 16 | if(Qt${QT_VERSION_MAJOR} STREQUAL Qt5) 17 | qt5_add_resources(RSCS qml.qrc) 18 | else() 19 | qt_add_resources(RSCS qml.qrc) 20 | endif() 21 | 22 | add_subdirectory(${LIB_DIR} ${CMAKE_BINARY_DIR}/SCodes) 23 | 24 | if(ANDROID) 25 | 26 | if(Qt${QT_VERSION_MAJOR} STREQUAL Qt5) 27 | 28 | set(ANDROID_MIN_SDK_VERSION 21) 29 | set(ANDROID_ABI "armeabi-v7a") 30 | set(QT_ANDROID_PACKAGE_SOURCE_DIR ${PROJECT_SOURCE_DIR}/android) 31 | 32 | file(GLOB_RECURSE ANDROID_SOURCES 33 | ${QT_ANDROID_PACKAGE_SOURCE_DIR}/AndroidManifest.xml 34 | ${QT_ANDROID_PACKAGE_SOURCE_DIR}/build.gradle 35 | ${QT_ANDROID_PACKAGE_SOURCE_DIR}/gradle/wrapper/gradle-wrapper.jar 36 | ${QT_ANDROID_PACKAGE_SOURCE_DIR}/gradle/wrapper/gradle-wrapper.properties 37 | ${QT_ANDROID_PACKAGE_SOURCE_DIR}/gradlew 38 | ${QT_ANDROID_PACKAGE_SOURCE_DIR}/res/values/libs.xml 39 | ) 40 | add_library(${PROJECT_NAME} SHARED main.cpp ${RSCS} ${ANDROID_SOURCES}) 41 | 42 | else() 43 | 44 | qt_add_executable(${PROJECT_NAME} MANUAL_FINALIZATION main.cpp ${RSCS}) 45 | 46 | set_target_properties(${PROJECT_NAME} PROPERTIES 47 | QT_ANDROID_PACKAGE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/android" 48 | ) 49 | 50 | endif() 51 | 52 | else() 53 | 54 | add_executable(${PROJECT_NAME} main.cpp ${RSCS} 55 | ColorController.h ColorController.cpp) 56 | 57 | endif() 58 | 59 | target_link_libraries(${PROJECT_NAME} PRIVATE ${REQUIRED_QT_LIBS} SCodes) 60 | 61 | 62 | if(QT_VERSION_MAJOR EQUAL 6) 63 | qt_import_qml_plugins(${PROJECT_NAME}) 64 | qt_finalize_executable(${PROJECT_NAME}) 65 | qt_finalize_project(${PROJECT_NAME}) 66 | endif() 67 | -------------------------------------------------------------------------------- /examples/QmlBarcodeGenerator/ColorController.cpp: -------------------------------------------------------------------------------- 1 | #include "ColorController.h" 2 | 3 | ColorController::ColorController(QObject *parent) 4 | : QObject{parent} 5 | {} 6 | 7 | bool ColorController::checkColor(const QString &color) 8 | { 9 | return QColor(color).isValid(); 10 | } 11 | 12 | QColor ColorController::convertStringToColor(const QString &color) 13 | { 14 | return QColor(color); 15 | } 16 | -------------------------------------------------------------------------------- /examples/QmlBarcodeGenerator/ColorController.h: -------------------------------------------------------------------------------- 1 | #ifndef COLORCONTROLLER_H 2 | #define COLORCONTROLLER_H 3 | 4 | #include 5 | #include 6 | 7 | class ColorController : public QObject 8 | { 9 | Q_OBJECT 10 | public: 11 | explicit ColorController(QObject *parent = nullptr); 12 | Q_INVOKABLE static QColor convertStringToColor(const QString &color); 13 | 14 | public slots: 15 | bool checkColor(const QString &color); 16 | }; 17 | 18 | #endif // COLORCONTROLLER_H 19 | -------------------------------------------------------------------------------- /examples/QmlBarcodeGenerator/QmlBarcodeGenerator.pro: -------------------------------------------------------------------------------- 1 | include("../../src/SCodes.pri") 2 | 3 | QT += quick 4 | CONFIG += c++17 5 | 6 | DEFINES += QT_DEPRECATED_WARNINGS 7 | 8 | SOURCES += \ 9 | main.cpp 10 | 11 | RESOURCES += qml.qrc 12 | 13 | # Default rules for deployment. 14 | qnx: target.path = /tmp/$${TARGET}/bin 15 | else: unix:!android: target.path = /opt/$${TARGET}/bin 16 | !isEmpty(target.path): INSTALLS += target 17 | 18 | android { 19 | DISTFILES += \ 20 | android/AndroidManifest.xml \ 21 | android/build.gradle \ 22 | android/gradle/wrapper/gradle-wrapper.jar \ 23 | android/gradle/wrapper/gradle-wrapper.properties \ 24 | android/gradlew \ 25 | android/gradlew.bat \ 26 | android/res/values/libs.xml 27 | 28 | ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android 29 | 30 | ANDROID_ABIS = armeabi-v7a 31 | } 32 | 33 | -------------------------------------------------------------------------------- /examples/QmlBarcodeGenerator/android.7z: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/somcosoftware/SCodes/c0647299d6be021ac59f57e031c794bd58757efe/examples/QmlBarcodeGenerator/android.7z -------------------------------------------------------------------------------- /examples/QmlBarcodeGenerator/android/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /examples/QmlBarcodeGenerator/android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | google() 4 | mavenCentral() 5 | } 6 | 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:7.0.2' 9 | } 10 | } 11 | 12 | repositories { 13 | google() 14 | mavenCentral() 15 | } 16 | 17 | apply plugin: 'com.android.application' 18 | 19 | dependencies { 20 | implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar']) 21 | } 22 | 23 | android { 24 | /******************************************************* 25 | * The following variables: 26 | * - androidBuildToolsVersion, 27 | * - androidCompileSdkVersion 28 | * - qtAndroidDir - holds the path to qt android files 29 | * needed to build any Qt application 30 | * on Android. 31 | * 32 | * are defined in gradle.properties file. This file is 33 | * updated by QtCreator and androiddeployqt tools. 34 | * Changing them manually might break the compilation! 35 | *******************************************************/ 36 | 37 | compileSdkVersion androidCompileSdkVersion.toInteger() 38 | buildToolsVersion androidBuildToolsVersion 39 | ndkVersion androidNdkVersion 40 | 41 | sourceSets { 42 | main { 43 | manifest.srcFile 'AndroidManifest.xml' 44 | java.srcDirs = [qtAndroidDir + '/src', 'src', 'java'] 45 | aidl.srcDirs = [qtAndroidDir + '/src', 'src', 'aidl'] 46 | res.srcDirs = [qtAndroidDir + '/res', 'res'] 47 | resources.srcDirs = ['resources'] 48 | renderscript.srcDirs = ['src'] 49 | assets.srcDirs = ['assets'] 50 | jniLibs.srcDirs = ['libs'] 51 | } 52 | } 53 | 54 | tasks.withType(JavaCompile) { 55 | options.incremental = true 56 | } 57 | 58 | compileOptions { 59 | sourceCompatibility JavaVersion.VERSION_1_8 60 | targetCompatibility JavaVersion.VERSION_1_8 61 | } 62 | 63 | lintOptions { 64 | abortOnError false 65 | } 66 | 67 | // Do not compress Qt binary resources file 68 | aaptOptions { 69 | noCompress 'rcc' 70 | } 71 | 72 | defaultConfig { 73 | resConfig "en" 74 | minSdkVersion qtMinSdkVersion 75 | targetSdkVersion qtTargetSdkVersion 76 | ndk.abiFilters = qtTargetAbiList.split(",") 77 | 78 | ndk { 79 | abiFilters 'armeabi-v7a' 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /examples/QmlBarcodeGenerator/android/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # For more details on how to configure your build environment visit 3 | # http://www.gradle.org/docs/current/userguide/build_environment.html 4 | # Specifies the JVM arguments used for the daemon process. 5 | # The setting is particularly useful for tweaking memory settings. 6 | org.gradle.jvmargs=-Xmx2500m -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 7 | 8 | # Enable building projects in parallel 9 | org.gradle.parallel=true 10 | 11 | # Gradle caching allows reusing the build artifacts from a previous 12 | # build with the same inputs. However, over time, the cache size will 13 | # grow. Uncomment the following line to enable it. 14 | #org.gradle.caching=true 15 | -------------------------------------------------------------------------------- /examples/QmlBarcodeGenerator/android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/somcosoftware/SCodes/c0647299d6be021ac59f57e031c794bd58757efe/examples/QmlBarcodeGenerator/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /examples/QmlBarcodeGenerator/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /examples/QmlBarcodeGenerator/android/gradlew: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Copyright © 2015-2021 the original authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | # 21 | # Gradle start up script for POSIX generated by Gradle. 22 | # 23 | # Important for running: 24 | # 25 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 26 | # noncompliant, but you have some other compliant shell such as ksh or 27 | # bash, then to run this script, type that shell name before the whole 28 | # command line, like: 29 | # 30 | # ksh Gradle 31 | # 32 | # Busybox and similar reduced shells will NOT work, because this script 33 | # requires all of these POSIX shell features: 34 | # * functions; 35 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 36 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 37 | # * compound commands having a testable exit status, especially «case»; 38 | # * various built-in commands including «command», «set», and «ulimit». 39 | # 40 | # Important for patching: 41 | # 42 | # (2) This script targets any POSIX shell, so it avoids extensions provided 43 | # by Bash, Ksh, etc; in particular arrays are avoided. 44 | # 45 | # The "traditional" practice of packing multiple parameters into a 46 | # space-separated string is a well documented source of bugs and security 47 | # problems, so this is (mostly) avoided, by progressively accumulating 48 | # options in "$@", and eventually passing that to Java. 49 | # 50 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 51 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 52 | # see the in-line comments for details. 53 | # 54 | # There are tweaks for specific operating systems such as AIX, CygWin, 55 | # Darwin, MinGW, and NonStop. 56 | # 57 | # (3) This script is generated from the Groovy template 58 | # https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 59 | # within the Gradle project. 60 | # 61 | # You can find Gradle at https://github.com/gradle/gradle/. 62 | # 63 | ############################################################################## 64 | 65 | # Attempt to set APP_HOME 66 | 67 | # Resolve links: $0 may be a link 68 | app_path=$0 69 | 70 | # Need this for daisy-chained symlinks. 71 | while 72 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 73 | [ -h "$app_path" ] 74 | do 75 | ls=$( ls -ld "$app_path" ) 76 | link=${ls#*' -> '} 77 | case $link in #( 78 | /*) app_path=$link ;; #( 79 | *) app_path=$APP_HOME$link ;; 80 | esac 81 | done 82 | 83 | APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit 84 | 85 | APP_NAME="Gradle" 86 | APP_BASE_NAME=${0##*/} 87 | 88 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 89 | DEFAULT_JVM_OPTS='-Dfile.encoding=UTF-8 "-Xmx64m" "-Xms64m"' 90 | 91 | # Use the maximum available, or set MAX_FD != -1 to use that value. 92 | MAX_FD=maximum 93 | 94 | warn () { 95 | echo "$*" 96 | } >&2 97 | 98 | die () { 99 | echo 100 | echo "$*" 101 | echo 102 | exit 1 103 | } >&2 104 | 105 | # OS specific support (must be 'true' or 'false'). 106 | cygwin=false 107 | msys=false 108 | darwin=false 109 | nonstop=false 110 | case "$( uname )" in #( 111 | CYGWIN* ) cygwin=true ;; #( 112 | Darwin* ) darwin=true ;; #( 113 | MSYS* | MINGW* ) msys=true ;; #( 114 | NONSTOP* ) nonstop=true ;; 115 | esac 116 | 117 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 118 | 119 | 120 | # Determine the Java command to use to start the JVM. 121 | if [ -n "$JAVA_HOME" ] ; then 122 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 123 | # IBM's JDK on AIX uses strange locations for the executables 124 | JAVACMD=$JAVA_HOME/jre/sh/java 125 | else 126 | JAVACMD=$JAVA_HOME/bin/java 127 | fi 128 | if [ ! -x "$JAVACMD" ] ; then 129 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 130 | 131 | Please set the JAVA_HOME variable in your environment to match the 132 | location of your Java installation." 133 | fi 134 | else 135 | JAVACMD=java 136 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 137 | 138 | Please set the JAVA_HOME variable in your environment to match the 139 | location of your Java installation." 140 | fi 141 | 142 | # Increase the maximum file descriptors if we can. 143 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 144 | case $MAX_FD in #( 145 | max*) 146 | MAX_FD=$( ulimit -H -n ) || 147 | warn "Could not query maximum file descriptor limit" 148 | esac 149 | case $MAX_FD in #( 150 | '' | soft) :;; #( 151 | *) 152 | ulimit -n "$MAX_FD" || 153 | warn "Could not set maximum file descriptor limit to $MAX_FD" 154 | esac 155 | fi 156 | 157 | # Collect all arguments for the java command, stacking in reverse order: 158 | # * args from the command line 159 | # * the main class name 160 | # * -classpath 161 | # * -D...appname settings 162 | # * --module-path (only if needed) 163 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 164 | 165 | # For Cygwin or MSYS, switch paths to Windows format before running java 166 | if "$cygwin" || "$msys" ; then 167 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 168 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 169 | 170 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 171 | 172 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 173 | for arg do 174 | if 175 | case $arg in #( 176 | -*) false ;; # don't mess with options #( 177 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 178 | [ -e "$t" ] ;; #( 179 | *) false ;; 180 | esac 181 | then 182 | arg=$( cygpath --path --ignore --mixed "$arg" ) 183 | fi 184 | # Roll the args list around exactly as many times as the number of 185 | # args, so each arg winds up back in the position where it started, but 186 | # possibly modified. 187 | # 188 | # NB: a `for` loop captures its iteration list before it begins, so 189 | # changing the positional parameters here affects neither the number of 190 | # iterations, nor the values presented in `arg`. 191 | shift # remove old arg 192 | set -- "$@" "$arg" # push replacement arg 193 | done 194 | fi 195 | 196 | # Collect all arguments for the java command; 197 | # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of 198 | # shell script including quotes and variable substitutions, so put them in 199 | # double quotes to make sure that they get re-expanded; and 200 | # * put everything else in single quotes, so that it's not re-expanded. 201 | 202 | set -- \ 203 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 204 | -classpath "$CLASSPATH" \ 205 | org.gradle.wrapper.GradleWrapperMain \ 206 | "$@" 207 | 208 | # Use "xargs" to parse quoted args. 209 | # 210 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 211 | # 212 | # In Bash we could simply go: 213 | # 214 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 215 | # set -- "${ARGS[@]}" "$@" 216 | # 217 | # but POSIX shell has neither arrays nor command substitution, so instead we 218 | # post-process each arg (as a line of input to sed) to backslash-escape any 219 | # character that might be a shell metacharacter, then use eval to reverse 220 | # that process (while maintaining the separation between arguments), and wrap 221 | # the whole thing up as a single "set" statement. 222 | # 223 | # This will of course break if any of these variables contains a newline or 224 | # an unmatched quote. 225 | # 226 | 227 | eval "set -- $( 228 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 229 | xargs -n1 | 230 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 231 | tr '\n' ' ' 232 | )" '"$@"' 233 | 234 | exec "$JAVACMD" "$@" 235 | -------------------------------------------------------------------------------- /examples/QmlBarcodeGenerator/android/gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS=-Dfile.encoding=UTF-8 "-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /examples/QmlBarcodeGenerator/android/res/drawable-hdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/somcosoftware/SCodes/c0647299d6be021ac59f57e031c794bd58757efe/examples/QmlBarcodeGenerator/android/res/drawable-hdpi/icon.png -------------------------------------------------------------------------------- /examples/QmlBarcodeGenerator/android/res/drawable-ldpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/somcosoftware/SCodes/c0647299d6be021ac59f57e031c794bd58757efe/examples/QmlBarcodeGenerator/android/res/drawable-ldpi/icon.png -------------------------------------------------------------------------------- /examples/QmlBarcodeGenerator/android/res/drawable-mdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/somcosoftware/SCodes/c0647299d6be021ac59f57e031c794bd58757efe/examples/QmlBarcodeGenerator/android/res/drawable-mdpi/icon.png -------------------------------------------------------------------------------- /examples/QmlBarcodeGenerator/android/res/drawable-xhdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/somcosoftware/SCodes/c0647299d6be021ac59f57e031c794bd58757efe/examples/QmlBarcodeGenerator/android/res/drawable-xhdpi/icon.png -------------------------------------------------------------------------------- /examples/QmlBarcodeGenerator/android/res/drawable-xxhdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/somcosoftware/SCodes/c0647299d6be021ac59f57e031c794bd58757efe/examples/QmlBarcodeGenerator/android/res/drawable-xxhdpi/icon.png -------------------------------------------------------------------------------- /examples/QmlBarcodeGenerator/android/res/drawable-xxxhdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/somcosoftware/SCodes/c0647299d6be021ac59f57e031c794bd58757efe/examples/QmlBarcodeGenerator/android/res/drawable-xxxhdpi/icon.png -------------------------------------------------------------------------------- /examples/QmlBarcodeGenerator/android/res/values/libs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /examples/QmlBarcodeGenerator/cmake/Locations.cmake: -------------------------------------------------------------------------------- 1 | set(COMPANY "Scythe Studio") 2 | set(COPYRIGHT "Copyright (c) 2022 Scythe Studio. Licensed under the Apache License, Version 2.0.") 3 | set(IDENTIFIER "com.scythestudio.scodes.example") 4 | 5 | # ---CONFIGURATION--- 6 | option(USE_QML "Add QML support" ON) 7 | option(USE_LIBS "Use external libraries" ON) 8 | 9 | # Locations - directories in project structure 10 | set(LIB_DIR ${CMAKE_SOURCE_DIR}/../../src) 11 | 12 | set(SRC_DIR ".") 13 | set(RES_DIR ".") 14 | set(QML_DIR "qml") 15 | 16 | # Check Qt version 17 | find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Core) 18 | find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Core) 19 | 20 | # ---PACKAGES SECTION--- 21 | list(APPEND REQUIRED_QT_PACKAGES Core Quick Gui Multimedia) 22 | 23 | if(USE_QML) 24 | list(APPEND REQUIRED_QT_PACKAGES Quick) 25 | list(APPEND QML_IMPORT_PATH "${CMAKE_SOURCE_DIR}/${QML_DIR}") 26 | set(QML_IMPORT_PATH ${QML_IMPORT_PATH} 27 | CACHE STRING "Qt Creator Import Path" 28 | FORCE) 29 | endif() 30 | 31 | foreach(QT_PACKAGE ${REQUIRED_QT_PACKAGES}) 32 | list(APPEND REQUIRED_QT_LIBS Qt${QT_VERSION_MAJOR}::${QT_PACKAGE}) 33 | endforeach() 34 | 35 | find_package(QT NAMES Qt${QT_VERSION_MAJOR} COMPONENTS ${REQUIRED_QT_PACKAGES} REQUIRED) 36 | find_package(Qt${QT_VERSION_MAJOR} COMPONENTS ${REQUIRED_QT_PACKAGES} REQUIRED) 37 | 38 | -------------------------------------------------------------------------------- /examples/QmlBarcodeGenerator/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include "SBarcodeGenerator.h" 5 | #include "ColorController.h" 6 | 7 | int main(int argc, char *argv[]) 8 | { 9 | 10 | #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 11 | QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); 12 | #endif 13 | 14 | QGuiApplication app(argc, argv); 15 | 16 | QQmlApplicationEngine engine; 17 | 18 | qmlRegisterSingletonType(QUrl("qrc:/qml/Theme.qml"), "Theme", 1, 0, "Theme"); 19 | 20 | qmlRegisterType("com.scythestudio.scodes", 1, 0, "SBarcodeGenerator"); 21 | qmlRegisterType("com.scythestudio.scodes", 1, 0, "ColorController"); 22 | 23 | engine.load(QUrl(QStringLiteral("qrc:/qml/GeneratorPage.qml"))); 24 | 25 | if (engine.rootObjects().isEmpty()) { 26 | return -1; 27 | } 28 | 29 | return app.exec(); 30 | } 31 | -------------------------------------------------------------------------------- /examples/QmlBarcodeGenerator/qml.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | qml/GeneratorPage.qml 4 | qml/CButton.qml 5 | qml/CTextField.qml 6 | qml/CComboBox.qml 7 | qml/Theme.qml 8 | 9 | 10 | -------------------------------------------------------------------------------- /examples/QmlBarcodeGenerator/qml/CButton.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.12 2 | import QtQuick.Controls 2.12 3 | import QtQuick.Layouts 1.12 4 | import QtQuick.Window 2.12 5 | 6 | 7 | /*! 8 | Classic push button for configure, generate & save operations. 9 | */ 10 | Button { 11 | id: root 12 | 13 | height: 100 14 | implicitWidth: appWindow.width / 4 15 | 16 | checkable: true 17 | 18 | palette.buttonText: Theme.textColor 19 | 20 | background: Rectangle { 21 | radius: 10 22 | color: root.pressed ? Qt.darker( 23 | Theme.backgroundColor) : Theme.backgroundColor 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /examples/QmlBarcodeGenerator/qml/CComboBox.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.12 2 | import QtQuick.Controls 2.12 3 | 4 | 5 | /*! 6 | Drop-down menu for barcode format selection & save file format extension 7 | */ 8 | ComboBox { 9 | id: root 10 | 11 | background: Rectangle { 12 | radius: 2 13 | 14 | border { 15 | color: Theme.borderColor 16 | width: 1 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /examples/QmlBarcodeGenerator/qml/CTextField.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.12 2 | import QtQuick.Controls 2.12 3 | 4 | 5 | /*! 6 | Field for setting width, height, margin & error correction code level parameters. 7 | */ 8 | TextField { 9 | id: root 10 | 11 | property bool inputIsValid: true 12 | 13 | selectByMouse: true 14 | 15 | leftPadding: 5 16 | 17 | background: Rectangle { 18 | radius: 2 19 | 20 | border { 21 | color: inputIsValid ? Theme.borderColor : Theme.invalidInputBorderColor 22 | width: 1 23 | } 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /examples/QmlBarcodeGenerator/qml/GeneratorPage.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.12 2 | import QtQuick.Controls 2.12 3 | import QtMultimedia 5.12 4 | import QtQuick.Layouts 1.12 5 | import com.scythestudio.scodes 1.0 6 | 7 | 8 | /*! 9 | Barcode generator main page. All QML elements managing from here. 10 | */ 11 | ApplicationWindow { 12 | id: appWindow 13 | 14 | visible: true 15 | 16 | width: 400 17 | height: 800 18 | 19 | MouseArea { 20 | id: hideKeyboard 21 | anchors.fill: parent 22 | onClicked: { 23 | Qt.inputMethod.hide() 24 | } 25 | } 26 | 27 | ColorController { 28 | id: colorController 29 | } 30 | 31 | SBarcodeGenerator { 32 | id: barcodeGenerator 33 | 34 | onForegroundColorChanged: { 35 | image.source = "" 36 | barcodeGenerator.generate(textField.text) 37 | } 38 | 39 | onBackgroundColorChanged: { 40 | image.source = "" 41 | barcodeGenerator.generate(textField.text) 42 | } 43 | 44 | onGenerationFinished: function (error) { 45 | if (error === "") { 46 | console.log(barcodeGenerator.filePath) 47 | image.source = "file:///" + barcodeGenerator.filePath 48 | } else { 49 | generateLabel.text = error 50 | generatePopup.open() 51 | } 52 | } 53 | } 54 | 55 | Rectangle { 56 | id: dashboard 57 | 58 | anchors.fill: parent 59 | 60 | height: parent.height 61 | width: parent.width 62 | 63 | Rectangle { 64 | id: inputRect 65 | z: 100 66 | 67 | height: 40 68 | 69 | anchors { 70 | top: parent.top 71 | left: parent.left 72 | right: parent.right 73 | } 74 | 75 | CTextField { 76 | id: textField 77 | 78 | anchors.fill: parent 79 | 80 | selectByMouse: true 81 | 82 | placeholderText: qsTr("Input") 83 | } 84 | } 85 | 86 | Image { 87 | id: image 88 | 89 | width: parent.width 90 | height: image.width 91 | 92 | anchors { 93 | left: parent.left 94 | right: parent.right 95 | verticalCenter: parent.verticalCenter 96 | } 97 | 98 | cache: false 99 | } 100 | 101 | Rectangle { 102 | id: buttonsRect 103 | 104 | height: 40 105 | 106 | anchors { 107 | bottom: parent.bottom 108 | left: parent.left 109 | right: parent.right 110 | } 111 | 112 | RowLayout { 113 | id: buttonsLayout 114 | 115 | spacing: 5 116 | 117 | anchors.fill: parent 118 | 119 | CButton { 120 | id: settingsButton 121 | 122 | Layout.alignment: Qt.AlignHCenter 123 | Layout.bottomMargin: 10 124 | 125 | text: qsTr("Settings") 126 | 127 | onClicked: { 128 | settingsPopup.open() 129 | } 130 | } 131 | 132 | CButton { 133 | id: generateButton 134 | 135 | Layout.alignment: Qt.AlignHCenter 136 | Layout.bottomMargin: 10 137 | checkable: false 138 | 139 | text: qsTr("Generate") 140 | 141 | onClicked: { 142 | image.source = "" 143 | if (textField.text === "") { 144 | generateLabel.text = "Input is empty" 145 | generatePopup.open() 146 | } else { 147 | barcodeGenerator.generate(textField.text) 148 | } 149 | } 150 | } 151 | 152 | CButton { 153 | id: saveButton 154 | 155 | Layout.alignment: Qt.AlignHCenter 156 | Layout.bottomMargin: 10 157 | 158 | text: qsTr("Save") 159 | 160 | onClicked: { 161 | if (barcodeGenerator.saveImage()) { 162 | saveLabel.text = "File successfully saved" 163 | } else { 164 | saveLabel.text = "There was an error while saving file" 165 | } 166 | 167 | imageSavedPopup.open() 168 | } 169 | } 170 | } 171 | } 172 | 173 | Popup { 174 | id: generatePopup 175 | 176 | anchors.centerIn: parent 177 | 178 | dim: true 179 | 180 | modal: true 181 | 182 | Label { 183 | id: generateLabel 184 | 185 | anchors.centerIn: parent 186 | } 187 | 188 | onClosed: { 189 | generateButton.checked = false 190 | } 191 | } 192 | 193 | Popup { 194 | id: imageSavedPopup 195 | 196 | anchors.centerIn: parent 197 | 198 | dim: true 199 | 200 | modal: true 201 | 202 | Label { 203 | id: saveLabel 204 | 205 | anchors.centerIn: parent 206 | } 207 | 208 | onClosed: { 209 | saveButton.checked = false 210 | } 211 | } 212 | 213 | Popup { 214 | id: settingsPopup 215 | 216 | width: parent.width * 0.6 217 | height: parent.height * 0.6 218 | 219 | anchors.centerIn: parent 220 | 221 | dim: true 222 | 223 | modal: true 224 | 225 | ColumnLayout { 226 | anchors.fill: parent 227 | 228 | spacing: 5 229 | 230 | CTextField { 231 | id: widthField 232 | 233 | implicitWidth: parent.width 234 | implicitHeight: parent.height / 10 235 | 236 | placeholderText: "Current width: " + barcodeGenerator.width 237 | 238 | onEditingFinished: function () { 239 | 240 | var parsedWidth = parseInt(text) 241 | 242 | if (isNaN(parsedWidth) != true && parsedWidth > 0) { 243 | barcodeGenerator.width = parsedWidth 244 | } 245 | } 246 | } 247 | 248 | CTextField { 249 | id: heightField 250 | 251 | implicitWidth: parent.width 252 | implicitHeight: parent.height / 10 253 | 254 | placeholderText: "Current height: " + barcodeGenerator.height 255 | 256 | onEditingFinished: function () { 257 | 258 | var parsedHeight = parseInt(text) 259 | 260 | if (isNaN(parsedHeight) != true && parsedHeight > 0) { 261 | barcodeGenerator.height = parsedHeight 262 | } 263 | } 264 | } 265 | 266 | CTextField { 267 | id: marginField 268 | 269 | implicitWidth: parent.width 270 | implicitHeight: parent.height / 10 271 | 272 | placeholderText: "Current margin: " + barcodeGenerator.margin 273 | 274 | onEditingFinished: function () { 275 | 276 | var parsedMargin = parseInt(text) 277 | 278 | if (isNaN(parsedMargin) != true) { 279 | barcodeGenerator.margin = parsedMargin 280 | } 281 | } 282 | } 283 | 284 | CTextField { 285 | id: eccLevelField 286 | 287 | implicitWidth: parent.width 288 | implicitHeight: parent.height / 10 289 | 290 | placeholderText: "Current ECC Level: " + barcodeGenerator.eccLevel 291 | 292 | onEditingFinished: function () { 293 | barcodeGenerator.eccLevel = text 294 | } 295 | } 296 | 297 | CTextField { 298 | id: foregroundColorField 299 | 300 | implicitWidth: parent.width 301 | implicitHeight: parent.height / 10 302 | 303 | placeholderText: "Current foreground color: " + barcodeGenerator.foregroundColor 304 | 305 | onTextChanged: function () { 306 | foregroundColorField.inputIsValid = colorController.checkColor(foregroundColorField.text) 307 | 308 | if (colorController.checkColor(foregroundColorField.text)) { 309 | barcodeGenerator.setForegroundColor(colorController.convertStringToColor(foregroundColorField.text)) 310 | } 311 | } 312 | } 313 | 314 | CTextField { 315 | id: backgroundColorField 316 | 317 | implicitWidth: parent.width 318 | implicitHeight: parent.height / 10 319 | 320 | placeholderText: "Current background color: " + barcodeGenerator.backgroundColor 321 | 322 | onTextChanged: function () { 323 | backgroundColorField.inputIsValid = colorController.checkColor(backgroundColorField.text) 324 | 325 | if (colorController.checkColor(backgroundColorField.text)) { 326 | barcodeGenerator.setBackgroundColor(colorController.convertStringToColor(backgroundColorField.text)) 327 | } 328 | } 329 | } 330 | 331 | CComboBox { 332 | id: formatDropDown 333 | 334 | implicitWidth: parent.width 335 | implicitHeight: parent.height / 10 336 | 337 | model: ListModel { 338 | id: formats 339 | 340 | ListElement { 341 | text: "Aztec" 342 | } 343 | ListElement { 344 | text: "Codabar" 345 | } 346 | ListElement { 347 | text: "Code39" 348 | } 349 | ListElement { 350 | text: "Code93" 351 | } 352 | ListElement { 353 | text: "Code128" 354 | } 355 | ListElement { 356 | text: "DataMatrix" 357 | } 358 | ListElement { 359 | text: "EAN-8" 360 | } 361 | ListElement { 362 | text: "EAN-13" 363 | } 364 | ListElement { 365 | text: "ITF" 366 | } 367 | ListElement { 368 | text: "PDF417" 369 | } 370 | ListElement { 371 | text: "QRCode" 372 | } 373 | ListElement { 374 | text: "UPC-A" 375 | } 376 | ListElement { 377 | text: "UPC-E" 378 | } 379 | } 380 | onCurrentIndexChanged: function () { 381 | var formatAsText = formats.get(currentIndex).text 382 | // a separate method was used because of qml error 383 | // when try to use it as overloaded setter 384 | barcodeGenerator.setFormat(formatAsText) 385 | } 386 | } 387 | 388 | CComboBox { 389 | id: imageFormat 390 | 391 | implicitWidth: parent.width 392 | implicitHeight: parent.height / 10 393 | 394 | model: ListModel { 395 | id: extensions 396 | 397 | ListElement { 398 | text: "png" 399 | } 400 | 401 | ListElement { 402 | text: "jpg" 403 | } 404 | } 405 | onCurrentIndexChanged: function () { 406 | barcodeGenerator.extension = extensions.get(currentIndex).text 407 | } 408 | } 409 | 410 | CTextField { 411 | id: fileNameField 412 | 413 | text: qsTr(barcodeGenerator.fileName) 414 | 415 | implicitWidth: parent.width 416 | implicitHeight: parent.height / 10 417 | 418 | onEditingFinished: { 419 | barcodeGenerator.fileName = text 420 | } 421 | } 422 | 423 | CTextField { 424 | id: imagePathField 425 | 426 | text: qsTr(barcodeGenerator.imagePath) 427 | 428 | implicitWidth: parent.width 429 | implicitHeight: parent.height / 10 430 | 431 | placeholderText: "Current image path: " + barcodeGenerator.imagePath 432 | 433 | onEditingFinished: { 434 | barcodeGenerator.imagePath = text 435 | } 436 | } 437 | 438 | CTextField { 439 | id: centerImageRatioField 440 | 441 | text: qsTr(barcodeGenerator.centerImageRatio.toString()) 442 | 443 | implicitWidth: parent.width 444 | implicitHeight: parent.height / 10 445 | 446 | placeholderText: "Current center image ratio: " + barcodeGenerator.centerImageRatio 447 | 448 | onEditingFinished: { 449 | barcodeGenerator.centerImageRatio = parseInt(text) 450 | } 451 | } 452 | } 453 | 454 | onClosed: { 455 | settingsButton.checked = false 456 | } 457 | } 458 | } 459 | } 460 | -------------------------------------------------------------------------------- /examples/QmlBarcodeGenerator/qml/Theme.qml: -------------------------------------------------------------------------------- 1 | pragma Singleton 2 | 3 | import QtQuick 2.12 4 | 5 | 6 | /** 7 | Contains common used colors 8 | */ 9 | QtObject { 10 | id: root 11 | 12 | readonly property color backgroundColor: "#218165" 13 | readonly property color textColor: "#bdbdbd" 14 | readonly property color borderColor: "#333" 15 | readonly property color invalidInputBorderColor: "#F00" 16 | } 17 | -------------------------------------------------------------------------------- /examples/QmlBarcodeReader/.gitignore: -------------------------------------------------------------------------------- 1 | *.pro.user 2 | *.pro.user* 3 | build-* 4 | *DS_Store 5 | -------------------------------------------------------------------------------- /examples/QmlBarcodeReader/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.16.3) 2 | 3 | project(QmlBarcodeReader LANGUAGES CXX) 4 | 5 | set(CMAKE_INCLUDE_CURRENT_DIR ON) 6 | 7 | set(CMAKE_AUTOMOC ON) 8 | set(CMAKE_AUTORCC ON) 9 | 10 | set(CMAKE_CXX_STANDARD 17) 11 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 12 | 13 | #Check this file for any *_DIR variable definitions and other 14 | include("cmake/Locations.cmake") 15 | 16 | if(Qt${QT_VERSION_MAJOR} STREQUAL Qt5) 17 | qt5_add_resources(RSCS Qt5qml.qrc) 18 | else() 19 | qt_add_resources(RSCS Qt6qml.qrc) 20 | endif() 21 | 22 | add_subdirectory(${LIB_DIR} ${CMAKE_BINARY_DIR}/SCodes) 23 | 24 | if(ANDROID) 25 | 26 | if(Qt${QT_VERSION_MAJOR} STREQUAL Qt5) 27 | 28 | set(ANDROID_MIN_SDK_VERSION 21) 29 | set(ANDROID_ABI "armeabi-v7a") 30 | set(QT_ANDROID_PACKAGE_SOURCE_DIR ${PROJECT_SOURCE_DIR}/android) 31 | 32 | file(GLOB_RECURSE ANDROID_SOURCES 33 | ${QT_ANDROID_PACKAGE_SOURCE_DIR}/AndroidManifest.xml 34 | ${QT_ANDROID_PACKAGE_SOURCE_DIR}/build.gradle 35 | ${QT_ANDROID_PACKAGE_SOURCE_DIR}/gradle/wrapper/gradle-wrapper.jar 36 | ${QT_ANDROID_PACKAGE_SOURCE_DIR}/gradle/wrapper/gradle-wrapper.properties 37 | ${QT_ANDROID_PACKAGE_SOURCE_DIR}/gradlew 38 | ${QT_ANDROID_PACKAGE_SOURCE_DIR}/res/values/libs.xml 39 | ) 40 | add_library(${PROJECT_NAME} SHARED main.cpp ${RSCS} ${ANDROID_SOURCES}) 41 | 42 | else() 43 | 44 | qt_add_executable(${PROJECT_NAME} MANUAL_FINALIZATION main.cpp ${RSCS}) 45 | set_target_properties(${PROJECT_NAME} PROPERTIES 46 | QT_ANDROID_PACKAGE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/android" 47 | ) 48 | 49 | endif() 50 | 51 | else() 52 | 53 | add_executable(${PROJECT_NAME} main.cpp ${RSCS}) 54 | 55 | endif() 56 | 57 | target_link_libraries(${PROJECT_NAME} PRIVATE ${REQUIRED_QT_LIBS} SCodes) 58 | 59 | 60 | if(QT_VERSION_MAJOR EQUAL 6) 61 | qt_import_qml_plugins(${PROJECT_NAME}) 62 | qt_finalize_executable(${PROJECT_NAME}) 63 | qt_finalize_project(${PROJECT_NAME}) 64 | endif() 65 | -------------------------------------------------------------------------------- /examples/QmlBarcodeReader/QmlBarcodeReader.pro: -------------------------------------------------------------------------------- 1 | include("../../src/SCodes.pri") 2 | 3 | QT += quick 4 | CONFIG += c++17 5 | 6 | DEFINES += QT_DEPRECATED_WARNINGS 7 | 8 | SOURCES += \ 9 | main.cpp 10 | 11 | equals(QT_MAJOR_VERSION, 6) { 12 | RESOURCES += Qt6qml.qrc 13 | } 14 | 15 | equals(QT_MAJOR_VERSION, 5) { 16 | RESOURCES += Qt5qml.qrc 17 | } 18 | 19 | # Default rules for deployment. 20 | qnx: target.path = /tmp/$${TARGET}/bin 21 | else: unix:!android: target.path = /opt/$${TARGET}/bin 22 | !isEmpty(target.path): INSTALLS += target 23 | 24 | android { 25 | DISTFILES += \ 26 | android/AndroidManifest.xml \ 27 | android/build.gradle \ 28 | android/gradle/wrapper/gradle-wrapper.jar \ 29 | android/gradle/wrapper/gradle-wrapper.properties \ 30 | android/gradlew \ 31 | android/gradlew.bat \ 32 | android/res/values/libs.xml 33 | 34 | ANDROID_PACKAGE_SOURCE_DIR = $$PWD/android 35 | 36 | ANDROID_ABIS = armeabi-v7a 37 | } 38 | 39 | -------------------------------------------------------------------------------- /examples/QmlBarcodeReader/Qt5qml.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | qml/Qt5ScannerPage.qml 4 | qml/Qt5ScannerOverlay.qml 5 | qml/Theme.qml 6 | 7 | 8 | -------------------------------------------------------------------------------- /examples/QmlBarcodeReader/Qt6qml.qrc: -------------------------------------------------------------------------------- 1 | 2 | 3 | qml/Qt6ScannerPage.qml 4 | qml/Qt6ScannerOverlay.qml 5 | qml/Theme.qml 6 | 7 | 8 | -------------------------------------------------------------------------------- /examples/QmlBarcodeReader/android/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 64 | 65 | 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /examples/QmlBarcodeReader/android/build.gradle: -------------------------------------------------------------------------------- 1 | buildscript { 2 | repositories { 3 | google() 4 | mavenCentral() 5 | } 6 | 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:7.0.2' 9 | } 10 | } 11 | 12 | repositories { 13 | google() 14 | mavenCentral() 15 | } 16 | 17 | apply plugin: 'com.android.application' 18 | 19 | dependencies { 20 | implementation fileTree(dir: 'libs', include: ['*.jar', '*.aar']) 21 | } 22 | 23 | android { 24 | /******************************************************* 25 | * The following variables: 26 | * - androidBuildToolsVersion, 27 | * - androidCompileSdkVersion 28 | * - qtAndroidDir - holds the path to qt android files 29 | * needed to build any Qt application 30 | * on Android. 31 | * 32 | * are defined in gradle.properties file. This file is 33 | * updated by QtCreator and androiddeployqt tools. 34 | * Changing them manually might break the compilation! 35 | *******************************************************/ 36 | 37 | compileSdkVersion androidCompileSdkVersion.toInteger() 38 | buildToolsVersion androidBuildToolsVersion 39 | ndkVersion '22.1.7171670' 40 | 41 | sourceSets { 42 | main { 43 | manifest.srcFile 'AndroidManifest.xml' 44 | java.srcDirs = [qtAndroidDir + '/src', 'src', 'java'] 45 | aidl.srcDirs = [qtAndroidDir + '/src', 'src', 'aidl'] 46 | res.srcDirs = [qtAndroidDir + '/res', 'res'] 47 | resources.srcDirs = ['resources'] 48 | renderscript.srcDirs = ['src'] 49 | assets.srcDirs = ['assets'] 50 | jniLibs.srcDirs = ['libs'] 51 | } 52 | } 53 | 54 | tasks.withType(JavaCompile) { 55 | options.incremental = true 56 | } 57 | 58 | compileOptions { 59 | sourceCompatibility JavaVersion.VERSION_1_8 60 | targetCompatibility JavaVersion.VERSION_1_8 61 | } 62 | 63 | lintOptions { 64 | abortOnError false 65 | } 66 | 67 | // Do not compress Qt binary resources file 68 | aaptOptions { 69 | noCompress 'rcc' 70 | } 71 | 72 | defaultConfig { 73 | resConfig "en" 74 | minSdkVersion qtMinSdkVersion 75 | targetSdkVersion qtTargetSdkVersion 76 | ndk.abiFilters = qtTargetAbiList.split(",") 77 | 78 | ndk { 79 | abiFilters 'armeabi-v7a' 80 | } 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /examples/QmlBarcodeReader/android/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # For more details on how to configure your build environment visit 3 | # http://www.gradle.org/docs/current/userguide/build_environment.html 4 | # Specifies the JVM arguments used for the daemon process. 5 | # The setting is particularly useful for tweaking memory settings. 6 | org.gradle.jvmargs=-Xmx512m -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 7 | 8 | # Enable building projects in parallel 9 | org.gradle.parallel=true 10 | 11 | # Gradle caching allows reusing the build artifacts from a previous 12 | # build with the same inputs. However, over time, the cache size will 13 | # grow. Uncomment the following line to enable it. 14 | #org.gradle.caching=true 15 | -------------------------------------------------------------------------------- /examples/QmlBarcodeReader/android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/somcosoftware/SCodes/c0647299d6be021ac59f57e031c794bd58757efe/examples/QmlBarcodeReader/android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /examples/QmlBarcodeReader/android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /examples/QmlBarcodeReader/android/gradlew: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # 4 | # Copyright © 2015-2021 the original authors. 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file except in compliance with the License. 8 | # You may obtain a copy of the License at 9 | # 10 | # https://www.apache.org/licenses/LICENSE-2.0 11 | # 12 | # Unless required by applicable law or agreed to in writing, software 13 | # distributed under the License is distributed on an "AS IS" BASIS, 14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | # See the License for the specific language governing permissions and 16 | # limitations under the License. 17 | # 18 | 19 | ############################################################################## 20 | # 21 | # Gradle start up script for POSIX generated by Gradle. 22 | # 23 | # Important for running: 24 | # 25 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is 26 | # noncompliant, but you have some other compliant shell such as ksh or 27 | # bash, then to run this script, type that shell name before the whole 28 | # command line, like: 29 | # 30 | # ksh Gradle 31 | # 32 | # Busybox and similar reduced shells will NOT work, because this script 33 | # requires all of these POSIX shell features: 34 | # * functions; 35 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}», 36 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»; 37 | # * compound commands having a testable exit status, especially «case»; 38 | # * various built-in commands including «command», «set», and «ulimit». 39 | # 40 | # Important for patching: 41 | # 42 | # (2) This script targets any POSIX shell, so it avoids extensions provided 43 | # by Bash, Ksh, etc; in particular arrays are avoided. 44 | # 45 | # The "traditional" practice of packing multiple parameters into a 46 | # space-separated string is a well documented source of bugs and security 47 | # problems, so this is (mostly) avoided, by progressively accumulating 48 | # options in "$@", and eventually passing that to Java. 49 | # 50 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, 51 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; 52 | # see the in-line comments for details. 53 | # 54 | # There are tweaks for specific operating systems such as AIX, CygWin, 55 | # Darwin, MinGW, and NonStop. 56 | # 57 | # (3) This script is generated from the Groovy template 58 | # https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt 59 | # within the Gradle project. 60 | # 61 | # You can find Gradle at https://github.com/gradle/gradle/. 62 | # 63 | ############################################################################## 64 | 65 | # Attempt to set APP_HOME 66 | 67 | # Resolve links: $0 may be a link 68 | app_path=$0 69 | 70 | # Need this for daisy-chained symlinks. 71 | while 72 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path 73 | [ -h "$app_path" ] 74 | do 75 | ls=$( ls -ld "$app_path" ) 76 | link=${ls#*' -> '} 77 | case $link in #( 78 | /*) app_path=$link ;; #( 79 | *) app_path=$APP_HOME$link ;; 80 | esac 81 | done 82 | 83 | APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit 84 | 85 | APP_NAME="Gradle" 86 | APP_BASE_NAME=${0##*/} 87 | 88 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 89 | DEFAULT_JVM_OPTS='-Dfile.encoding=UTF-8 "-Xmx64m" "-Xms64m"' 90 | 91 | # Use the maximum available, or set MAX_FD != -1 to use that value. 92 | MAX_FD=maximum 93 | 94 | warn () { 95 | echo "$*" 96 | } >&2 97 | 98 | die () { 99 | echo 100 | echo "$*" 101 | echo 102 | exit 1 103 | } >&2 104 | 105 | # OS specific support (must be 'true' or 'false'). 106 | cygwin=false 107 | msys=false 108 | darwin=false 109 | nonstop=false 110 | case "$( uname )" in #( 111 | CYGWIN* ) cygwin=true ;; #( 112 | Darwin* ) darwin=true ;; #( 113 | MSYS* | MINGW* ) msys=true ;; #( 114 | NONSTOP* ) nonstop=true ;; 115 | esac 116 | 117 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 118 | 119 | 120 | # Determine the Java command to use to start the JVM. 121 | if [ -n "$JAVA_HOME" ] ; then 122 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 123 | # IBM's JDK on AIX uses strange locations for the executables 124 | JAVACMD=$JAVA_HOME/jre/sh/java 125 | else 126 | JAVACMD=$JAVA_HOME/bin/java 127 | fi 128 | if [ ! -x "$JAVACMD" ] ; then 129 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 130 | 131 | Please set the JAVA_HOME variable in your environment to match the 132 | location of your Java installation." 133 | fi 134 | else 135 | JAVACMD=java 136 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 137 | 138 | Please set the JAVA_HOME variable in your environment to match the 139 | location of your Java installation." 140 | fi 141 | 142 | # Increase the maximum file descriptors if we can. 143 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then 144 | case $MAX_FD in #( 145 | max*) 146 | MAX_FD=$( ulimit -H -n ) || 147 | warn "Could not query maximum file descriptor limit" 148 | esac 149 | case $MAX_FD in #( 150 | '' | soft) :;; #( 151 | *) 152 | ulimit -n "$MAX_FD" || 153 | warn "Could not set maximum file descriptor limit to $MAX_FD" 154 | esac 155 | fi 156 | 157 | # Collect all arguments for the java command, stacking in reverse order: 158 | # * args from the command line 159 | # * the main class name 160 | # * -classpath 161 | # * -D...appname settings 162 | # * --module-path (only if needed) 163 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. 164 | 165 | # For Cygwin or MSYS, switch paths to Windows format before running java 166 | if "$cygwin" || "$msys" ; then 167 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) 168 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) 169 | 170 | JAVACMD=$( cygpath --unix "$JAVACMD" ) 171 | 172 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 173 | for arg do 174 | if 175 | case $arg in #( 176 | -*) false ;; # don't mess with options #( 177 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath 178 | [ -e "$t" ] ;; #( 179 | *) false ;; 180 | esac 181 | then 182 | arg=$( cygpath --path --ignore --mixed "$arg" ) 183 | fi 184 | # Roll the args list around exactly as many times as the number of 185 | # args, so each arg winds up back in the position where it started, but 186 | # possibly modified. 187 | # 188 | # NB: a `for` loop captures its iteration list before it begins, so 189 | # changing the positional parameters here affects neither the number of 190 | # iterations, nor the values presented in `arg`. 191 | shift # remove old arg 192 | set -- "$@" "$arg" # push replacement arg 193 | done 194 | fi 195 | 196 | # Collect all arguments for the java command; 197 | # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of 198 | # shell script including quotes and variable substitutions, so put them in 199 | # double quotes to make sure that they get re-expanded; and 200 | # * put everything else in single quotes, so that it's not re-expanded. 201 | 202 | set -- \ 203 | "-Dorg.gradle.appname=$APP_BASE_NAME" \ 204 | -classpath "$CLASSPATH" \ 205 | org.gradle.wrapper.GradleWrapperMain \ 206 | "$@" 207 | 208 | # Use "xargs" to parse quoted args. 209 | # 210 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed. 211 | # 212 | # In Bash we could simply go: 213 | # 214 | # readarray ARGS < <( xargs -n1 <<<"$var" ) && 215 | # set -- "${ARGS[@]}" "$@" 216 | # 217 | # but POSIX shell has neither arrays nor command substitution, so instead we 218 | # post-process each arg (as a line of input to sed) to backslash-escape any 219 | # character that might be a shell metacharacter, then use eval to reverse 220 | # that process (while maintaining the separation between arguments), and wrap 221 | # the whole thing up as a single "set" statement. 222 | # 223 | # This will of course break if any of these variables contains a newline or 224 | # an unmatched quote. 225 | # 226 | 227 | eval "set -- $( 228 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | 229 | xargs -n1 | 230 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | 231 | tr '\n' ' ' 232 | )" '"$@"' 233 | 234 | exec "$JAVACMD" "$@" 235 | -------------------------------------------------------------------------------- /examples/QmlBarcodeReader/android/gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS=-Dfile.encoding=UTF-8 "-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /examples/QmlBarcodeReader/android/res/drawable-hdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/somcosoftware/SCodes/c0647299d6be021ac59f57e031c794bd58757efe/examples/QmlBarcodeReader/android/res/drawable-hdpi/icon.png -------------------------------------------------------------------------------- /examples/QmlBarcodeReader/android/res/drawable-ldpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/somcosoftware/SCodes/c0647299d6be021ac59f57e031c794bd58757efe/examples/QmlBarcodeReader/android/res/drawable-ldpi/icon.png -------------------------------------------------------------------------------- /examples/QmlBarcodeReader/android/res/drawable-mdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/somcosoftware/SCodes/c0647299d6be021ac59f57e031c794bd58757efe/examples/QmlBarcodeReader/android/res/drawable-mdpi/icon.png -------------------------------------------------------------------------------- /examples/QmlBarcodeReader/android/res/drawable-xhdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/somcosoftware/SCodes/c0647299d6be021ac59f57e031c794bd58757efe/examples/QmlBarcodeReader/android/res/drawable-xhdpi/icon.png -------------------------------------------------------------------------------- /examples/QmlBarcodeReader/android/res/drawable-xxhdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/somcosoftware/SCodes/c0647299d6be021ac59f57e031c794bd58757efe/examples/QmlBarcodeReader/android/res/drawable-xxhdpi/icon.png -------------------------------------------------------------------------------- /examples/QmlBarcodeReader/android/res/drawable-xxxhdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/somcosoftware/SCodes/c0647299d6be021ac59f57e031c794bd58757efe/examples/QmlBarcodeReader/android/res/drawable-xxxhdpi/icon.png -------------------------------------------------------------------------------- /examples/QmlBarcodeReader/android/res/values/libs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /examples/QmlBarcodeReader/cmake/Locations.cmake: -------------------------------------------------------------------------------- 1 | set(COMPANY "Scythe Studio") 2 | set(COPYRIGHT "Copyright (c) 2022 Scythe Studio. Licensed under the Apache License, Version 2.0.") 3 | set(IDENTIFIER "com.scythestudio.scodes.example") 4 | 5 | # ---CONFIGURATION--- 6 | option(USE_QML "Add QML support" ON) 7 | option(USE_LIBS "Use external libraries" ON) 8 | 9 | # Locations - directories in project structure 10 | set(LIB_DIR ${CMAKE_SOURCE_DIR}/../../src) 11 | 12 | set(SRC_DIR ".") 13 | set(RES_DIR ".") 14 | set(QML_DIR "qml") 15 | 16 | # Check Qt version 17 | find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Core) 18 | find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Core) 19 | 20 | # ---PACKAGES SECTION--- 21 | list(APPEND REQUIRED_QT_PACKAGES Core Quick Gui Multimedia) 22 | 23 | if(USE_QML) 24 | list(APPEND REQUIRED_QT_PACKAGES Quick) 25 | list(APPEND QML_IMPORT_PATH "${CMAKE_SOURCE_DIR}/${QML_DIR}") 26 | set(QML_IMPORT_PATH ${QML_IMPORT_PATH} 27 | CACHE STRING "Qt Creator Import Path" 28 | FORCE) 29 | endif() 30 | 31 | foreach(QT_PACKAGE ${REQUIRED_QT_PACKAGES}) 32 | list(APPEND REQUIRED_QT_LIBS Qt${QT_VERSION_MAJOR}::${QT_PACKAGE}) 33 | endforeach() 34 | 35 | find_package(QT NAMES Qt${QT_VERSION_MAJOR} COMPONENTS ${REQUIRED_QT_PACKAGES} REQUIRED) 36 | find_package(Qt${QT_VERSION_MAJOR} COMPONENTS ${REQUIRED_QT_PACKAGES} REQUIRED) 37 | 38 | -------------------------------------------------------------------------------- /examples/QmlBarcodeReader/main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 5 | #include "SBarcodeFilter.h" 6 | #else 7 | #include "SBarcodeScanner.h" 8 | #endif 9 | 10 | int main(int argc, char* argv[]) 11 | { 12 | QCoreApplication::setAttribute(Qt::AA_UseDesktopOpenGL); 13 | 14 | #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 15 | QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); 16 | #endif 17 | QGuiApplication app(argc, argv); 18 | 19 | QQmlApplicationEngine engine; 20 | 21 | qmlRegisterSingletonType(QUrl("qrc:/qml/Theme.qml"), "Theme", 1, 0, "Theme"); 22 | qmlRegisterUncreatableMetaObject( 23 | SCodes::staticMetaObject, "com.scythestudio.scodes", 1, 0, "SCodes", "Error, enum type"); 24 | 25 | #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 26 | qmlRegisterType("com.scythestudio.scodes", 1, 0, "SBarcodeScanner"); 27 | engine.load(QUrl(QStringLiteral("qrc:/qml/Qt5ScannerPage.qml"))); 28 | #else 29 | qmlRegisterType("com.scythestudio.scodes", 1, 0, "SBarcodeScanner"); 30 | engine.load(QUrl(QStringLiteral("qrc:/qml/Qt6ScannerPage.qml"))); 31 | #endif 32 | 33 | if (engine.rootObjects().isEmpty()) { 34 | return -1; 35 | } 36 | 37 | return app.exec(); 38 | } 39 | -------------------------------------------------------------------------------- /examples/QmlBarcodeReader/qml/Qt5ScannerOverlay.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.12 2 | import QtGraphicalEffects 1.12 3 | 4 | /*! 5 | Area for scanning barcodes 6 | */ 7 | Item { 8 | id: root 9 | 10 | property rect captureRect 11 | 12 | Item { 13 | id: captureZoneCorners 14 | 15 | x: root.captureRect.x 16 | y: root.captureRect.y 17 | 18 | width: root.captureRect.width 19 | height: root.captureRect.height 20 | 21 | Rectangle { 22 | id: topLeftCornerH 23 | 24 | anchors { 25 | top: parent.top 26 | left: parent.left 27 | } 28 | 29 | width: 20 30 | height: 5 31 | 32 | color: Theme.borderColor 33 | radius: height / 2 34 | } 35 | 36 | Rectangle { 37 | id: topLeftCornerV 38 | anchors { 39 | top: parent.top 40 | left: parent.left 41 | } 42 | 43 | width: 5 44 | height: 20 45 | 46 | color: Theme.borderColor 47 | radius: width / 2 48 | } 49 | 50 | // ---------------------- 51 | Rectangle { 52 | id: bottomLeftCornerH 53 | 54 | anchors { 55 | bottom: parent.bottom 56 | left: parent.left 57 | } 58 | 59 | width: 20 60 | height: 5 61 | 62 | color: Theme.borderColor 63 | radius: height / 2 64 | } 65 | 66 | Rectangle { 67 | id: bottomLeftCornerV 68 | 69 | anchors { 70 | bottom: parent.bottom 71 | left: parent.left 72 | } 73 | 74 | width: 5 75 | height: 20 76 | 77 | color: Theme.borderColor 78 | radius: width / 2 79 | } 80 | 81 | // ---------------------- 82 | Rectangle { 83 | id: topRightCornerH 84 | 85 | anchors { 86 | top: parent.top 87 | right: parent.right 88 | } 89 | 90 | width: 20 91 | height: 5 92 | 93 | color: Theme.borderColor 94 | radius: height / 2 95 | } 96 | 97 | Rectangle { 98 | id: topRightCornerV 99 | 100 | anchors { 101 | top: parent.top 102 | right: parent.right 103 | } 104 | 105 | width: 5 106 | height: 20 107 | 108 | color: Theme.borderColor 109 | radius: width / 2 110 | } 111 | 112 | // ---------------------- 113 | Rectangle { 114 | id: bottomRightCornerH 115 | 116 | anchors { 117 | bottom: parent.bottom 118 | right: parent.right 119 | } 120 | 121 | width: 20 122 | height: 5 123 | 124 | color: Theme.borderColor 125 | radius: height / 2 126 | } 127 | 128 | Rectangle { 129 | id: bottomRightCornerV 130 | 131 | anchors { 132 | bottom: parent.bottom 133 | right: parent.right 134 | } 135 | 136 | width: 5 137 | height: 20 138 | 139 | color: Theme.borderColor 140 | radius: width / 2 141 | } 142 | 143 | Rectangle { 144 | id: scanIndicator 145 | 146 | //y: captureZoneCorners.height/2 147 | width: parent.width 148 | height: 1 149 | 150 | anchors { 151 | horizontalCenter: parent.horizontalCenter 152 | } 153 | 154 | color: Theme.borderColor 155 | 156 | SequentialAnimation { 157 | id: scanIndicatorAnimation 158 | 159 | loops: Animation.Infinite 160 | 161 | PropertyAnimation { 162 | id: toTopAnimation 163 | target: scanIndicator 164 | property: "y" 165 | duration: 2000 166 | } 167 | 168 | PropertyAnimation { 169 | id: toBottomAnimation 170 | target: scanIndicator 171 | property: "y" 172 | duration: 2000 173 | } 174 | } 175 | } 176 | 177 | RectangularGlow { 178 | id: effect 179 | 180 | width: scanIndicator.width / 2 181 | height: scanIndicator.height 182 | 183 | anchors.centerIn: scanIndicator 184 | 185 | glowRadius: 50 186 | spread: 0.2 187 | color: Theme.borderColor 188 | cornerRadius: glowRadius 189 | } 190 | } 191 | 192 | Text { 193 | id: scanCapsuleText 194 | 195 | anchors { 196 | verticalCenter: captureZoneCorners.bottom 197 | horizontalCenter: captureZoneCorners.horizontalCenter 198 | } 199 | 200 | text: qsTr("Scan barcode") 201 | color: Theme.borderColor 202 | } 203 | 204 | onCaptureRectChanged: { 205 | toTopAnimation.to = 5 206 | toBottomAnimation.to = captureRect.height - 5 207 | scanIndicatorAnimation.start() 208 | } 209 | } 210 | -------------------------------------------------------------------------------- /examples/QmlBarcodeReader/qml/Qt5ScannerPage.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2.12 2 | import QtQuick.Controls 2.12 3 | import QtQuick.Window 2.12 4 | import QtMultimedia 5.12 5 | import com.scythestudio.scodes 1.0 6 | 7 | 8 | /*! 9 | Barcode scanner main page. All QML elements managing from here. 10 | */ 11 | ApplicationWindow { 12 | id: root 13 | 14 | visible: true 15 | 16 | width: Qt.platform.os == "android" 17 | || Qt.platform.os == "ios" ? Screen.width : camera.viewfinder.resolution.width 18 | height: Qt.platform.os == "android" 19 | || Qt.platform.os == "ios" ? Screen.height : camera.viewfinder.resolution.height 20 | 21 | Camera { 22 | id: camera 23 | 24 | focus { 25 | focusMode: CameraFocus.FocusContinuous 26 | focusPointMode: CameraFocus.FocusPointAuto 27 | } 28 | } 29 | 30 | VideoOutput { 31 | id: videoOutput 32 | 33 | anchors.fill: parent 34 | 35 | source: camera 36 | 37 | autoOrientation: true 38 | 39 | fillMode: VideoOutput.PreserveAspectCrop 40 | 41 | // add barcodeScanner to videoOutput's filters to enable catching barcodes 42 | filters: [barcodeScanner] 43 | 44 | onSourceRectChanged: { 45 | barcodeScanner.captureRect = videoOutput.mapRectToSource(videoOutput.mapNormalizedRectToItem(Qt.rect(0.25, 0.25, 0.5, 0.5))) 46 | } 47 | 48 | Qt5ScannerOverlay { 49 | id: scannerOverlay 50 | 51 | anchors.fill: parent 52 | 53 | captureRect: videoOutput.mapRectToItem(barcodeScanner.captureRect) 54 | } 55 | 56 | // used to get camera focus on touched point 57 | MouseArea { 58 | id: focusTouchArea 59 | 60 | anchors.fill: parent 61 | 62 | onClicked: { 63 | camera.focus.customFocusPoint = Qt.point(mouse.x / width, 64 | mouse.y / height) 65 | camera.focus.focusMode = CameraFocus.FocusMacro 66 | camera.focus.focusPointMode = CameraFocus.FocusPointCustom 67 | } 68 | } 69 | } 70 | 71 | SBarcodeScanner { 72 | id: barcodeScanner 73 | 74 | // you can adjust capture rect (scan area) ne changing these Qt.rect() parameters 75 | captureRect: videoOutput.mapRectToSource(videoOutput.mapNormalizedRectToItem(Qt.rect(0.25, 0.25, 0.5, 0.5))) 76 | 77 | onCapturedChanged: { 78 | active = false 79 | console.log("captured: " + captured) 80 | } 81 | } 82 | 83 | Rectangle { 84 | id: resultScreen 85 | 86 | anchors.fill: parent 87 | 88 | visible: !barcodeScanner.active 89 | 90 | Column { 91 | anchors.centerIn: parent 92 | 93 | spacing: 20 94 | 95 | Text { 96 | id: scanResultText 97 | 98 | anchors.horizontalCenter: parent.horizontalCenter 99 | 100 | text: barcodeScanner.captured 101 | } 102 | 103 | Button { 104 | id: scanButton 105 | 106 | anchors.horizontalCenter: parent.horizontalCenter 107 | 108 | text: qsTr("Scan again") 109 | 110 | onClicked: { 111 | barcodeScanner.active = true 112 | } 113 | } 114 | } 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /examples/QmlBarcodeReader/qml/Qt6ScannerOverlay.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2 | import Qt5Compat.GraphicalEffects 3 | 4 | 5 | /*! 6 | Area for scanning barcodes 7 | */ 8 | Item { 9 | id: root 10 | 11 | property rect captureRect 12 | 13 | Item { 14 | id: captureZoneCorners 15 | 16 | x: parent.width * root.captureRect.x 17 | y: parent.height * root.captureRect.y 18 | 19 | width: parent.width * root.captureRect.width 20 | height: parent.height * root.captureRect.height 21 | 22 | Rectangle { 23 | id: topLeftCornerH 24 | 25 | anchors { 26 | top: parent.top 27 | left: parent.left 28 | } 29 | 30 | width: 20 31 | height: 5 32 | 33 | color: Theme.borderColor 34 | radius: height / 2 35 | } 36 | 37 | Rectangle { 38 | id: topLeftCornerV 39 | 40 | anchors { 41 | top: parent.top 42 | left: parent.left 43 | } 44 | 45 | width: 5 46 | height: 20 47 | 48 | color: Theme.borderColor 49 | radius: width / 2 50 | } 51 | 52 | // ---------------------- 53 | Rectangle { 54 | id: bottomLeftCornerH 55 | 56 | anchors { 57 | bottom: parent.bottom 58 | left: parent.left 59 | } 60 | 61 | width: 20 62 | height: 5 63 | 64 | color: Theme.borderColor 65 | radius: height / 2 66 | } 67 | 68 | Rectangle { 69 | id: bottomLeftCornerV 70 | 71 | anchors { 72 | bottom: parent.bottom 73 | left: parent.left 74 | } 75 | 76 | width: 5 77 | height: 20 78 | 79 | color: Theme.borderColor 80 | radius: width / 2 81 | } 82 | 83 | // ---------------------- 84 | Rectangle { 85 | id: topRightCornerH 86 | 87 | anchors { 88 | top: parent.top 89 | right: parent.right 90 | } 91 | 92 | width: 20 93 | height: 5 94 | 95 | color: Theme.borderColor 96 | radius: height / 2 97 | } 98 | 99 | Rectangle { 100 | id: topRightCornerV 101 | 102 | anchors { 103 | top: parent.top 104 | right: parent.right 105 | } 106 | 107 | width: 5 108 | height: 20 109 | 110 | color: Theme.borderColor 111 | radius: width / 2 112 | } 113 | 114 | // ---------------------- 115 | Rectangle { 116 | id: bottomRightCornerH 117 | 118 | anchors { 119 | bottom: parent.bottom 120 | right: parent.right 121 | } 122 | 123 | width: 20 124 | height: 5 125 | 126 | color: Theme.borderColor 127 | radius: height / 2 128 | } 129 | 130 | Rectangle { 131 | id: bottomRightCornerV 132 | 133 | anchors { 134 | bottom: parent.bottom 135 | right: parent.right 136 | } 137 | 138 | width: 5 139 | height: 20 140 | 141 | color: Theme.borderColor 142 | radius: width / 2 143 | } 144 | 145 | Rectangle { 146 | id: scanIndicator 147 | 148 | anchors { 149 | horizontalCenter: parent.horizontalCenter 150 | } 151 | 152 | width: parent.width 153 | height: 1 154 | 155 | color: Theme.borderColor 156 | 157 | SequentialAnimation { 158 | id: scanIndicatorAnimation 159 | 160 | loops: Animation.Infinite 161 | PropertyAnimation { 162 | id: toTopAnimation 163 | 164 | target: scanIndicator 165 | property: "y" 166 | duration: 2000 167 | to: captureZoneCorners.height 168 | } 169 | 170 | PropertyAnimation { 171 | id: toBottomAnimation 172 | 173 | target: scanIndicator 174 | property: "y" 175 | duration: 2000 176 | to: 0 177 | } 178 | } 179 | } 180 | 181 | RectangularGlow { 182 | id: effect 183 | 184 | anchors.centerIn: scanIndicator 185 | 186 | width: scanIndicator.width / 2 187 | height: scanIndicator.height 188 | 189 | glowRadius: 50 190 | spread: 0.2 191 | color: Theme.borderColor 192 | cornerRadius: glowRadius 193 | } 194 | } 195 | 196 | Text { 197 | id: scanCapsuleText 198 | 199 | anchors { 200 | verticalCenter: captureZoneCorners.bottom 201 | horizontalCenter: captureZoneCorners.horizontalCenter 202 | } 203 | 204 | text: qsTr("Scan barcode") 205 | color: Theme.borderColor 206 | } 207 | 208 | onCaptureRectChanged: { 209 | scanIndicatorAnimation.start() 210 | } 211 | } 212 | -------------------------------------------------------------------------------- /examples/QmlBarcodeReader/qml/Qt6ScannerPage.qml: -------------------------------------------------------------------------------- 1 | import QtQuick 2 | import QtQuick.Controls 3 | import QtMultimedia 4 | import com.scythestudio.scodes 1.0 5 | 6 | 7 | /*! 8 | Barcode scanner main page. All QML elements managing from here. 9 | */ 10 | ApplicationWindow { 11 | id: root 12 | 13 | width: Qt.platform.os === "android" 14 | || Qt.platform.os === "ios" ? Screen.width : 1280 15 | height: Qt.platform.os === "android" 16 | || Qt.platform.os === "ios" ? Screen.height : 720 17 | 18 | visible: true 19 | 20 | SBarcodeScanner { 21 | id: barcodeScanner 22 | 23 | forwardVideoSink: videoOutput.videoSink 24 | scanning: !resultScreen.visible 25 | 26 | captureRect: Qt.rect(1 / 4, 1 / 4, 1 / 2, 1 / 2) 27 | 28 | onCapturedChanged: function (captured) { 29 | scanResultText.text = captured 30 | resultScreen.visible = true 31 | } 32 | } 33 | 34 | VideoOutput { 35 | id: videoOutput 36 | 37 | anchors.fill: parent 38 | 39 | width: root.width 40 | 41 | focus: visible 42 | fillMode: VideoOutput.PreserveAspectCrop 43 | } 44 | 45 | Qt6ScannerOverlay { 46 | id: scannerOverlay 47 | 48 | anchors.fill: parent 49 | 50 | captureRect: barcodeScanner.captureRect 51 | } 52 | 53 | Rectangle { 54 | id: resultScreen 55 | 56 | anchors.fill: parent 57 | 58 | visible: false 59 | 60 | Column { 61 | anchors.centerIn: parent 62 | 63 | spacing: 20 64 | 65 | Text { 66 | id: scanResultText 67 | 68 | anchors.horizontalCenter: parent.horizontalCenter 69 | 70 | color: Theme.textColor 71 | } 72 | 73 | Button { 74 | id: scanButton 75 | 76 | anchors.horizontalCenter: parent.horizontalCenter 77 | 78 | implicitWidth: 100 79 | implicitHeight: 50 80 | 81 | Text { 82 | anchors.centerIn: parent 83 | 84 | text: qsTr("Scan again") 85 | color: Theme.textColor 86 | } 87 | 88 | onClicked: { 89 | resultScreen.visible = false 90 | } 91 | } 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /examples/QmlBarcodeReader/qml/Theme.qml: -------------------------------------------------------------------------------- 1 | pragma Singleton 2 | 3 | import QtQuick 2.12 4 | 5 | /** 6 | Contains common used colors 7 | */ 8 | QtObject { 9 | id: root 10 | 11 | readonly property color borderColor: "#218165" 12 | readonly property color textColor: "#000000" 13 | } 14 | -------------------------------------------------------------------------------- /examples/QmlBarcodeReader/qrScanner/QrDecoder.cpp: -------------------------------------------------------------------------------- 1 | #include "QrDecoder.h" 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "ReadBarcode.h" 12 | 13 | #define STB_IMAGE_IMPLEMENTATION 14 | #include "stb_image.h" 15 | 16 | namespace ZXing { 17 | namespace Qt { 18 | using ZXing::DecodeHints; 19 | using ZXing::BarcodeFormat; 20 | using ZXing::BarcodeFormats; 21 | using ZXing::Binarizer; 22 | 23 | template 24 | QDebug operator << (QDebug dbg, const T& v) 25 | { 26 | return dbg.noquote() << QString::fromStdString(ToString(v)); 27 | } 28 | 29 | class Result : private ZXing::Result 30 | { 31 | public: 32 | explicit Result(ZXing::Result&& r) : ZXing::Result(std::move(r)){ } 33 | 34 | using ZXing::Result::format; 35 | using ZXing::Result::isValid; 36 | using ZXing::Result::status; 37 | 38 | inline QString text() const { return QString::fromWCharArray(ZXing::Result::text().c_str()); } 39 | }; 40 | 41 | Result ReadBarcode(const QImage& img, const DecodeHints& hints = { }) 42 | { 43 | auto ImgFmtFromQImg = [](const QImage& img){ 44 | switch (img.format()) { 45 | case QImage::Format_ARGB32: 46 | case QImage::Format_RGB32: 47 | #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN 48 | return ImageFormat::BGRX; 49 | 50 | #else 51 | return ImageFormat::XRGB; 52 | 53 | #endif 54 | case QImage::Format_RGB888: return ImageFormat::RGB; 55 | 56 | case QImage::Format_RGBX8888: 57 | case QImage::Format_RGBA8888: return ImageFormat::RGBX; 58 | 59 | case QImage::Format_Grayscale8: return ImageFormat::Lum; 60 | 61 | default: return ImageFormat::None; 62 | } 63 | }; 64 | 65 | auto exec = [&](const QImage& img){ 66 | return Result(ZXing::ReadBarcode({ img.bits(), img.width(), img.height(), ImgFmtFromQImg(img) }, hints)); 67 | }; 68 | 69 | return ImgFmtFromQImg(img) == ImageFormat::None ? exec(img.convertToFormat(QImage::Format_RGBX8888)) : exec(img); 70 | } 71 | } // namespace Qt 72 | } // namespace ZXing 73 | 74 | using namespace ZXing::Qt; 75 | 76 | std::ostream& operator << (std::ostream& os, const std::vector& points) 77 | { 78 | for (const auto& p : points) { 79 | os << int(p.x() + .5f) << "x" << int(p.y() + .5f) << " "; 80 | } 81 | 82 | return os; 83 | } 84 | 85 | // ! This is linked to the private implementations of Qt. Check, when using a new versino of Qt that it still 86 | // ! works. E.g. by saving the images to disk and visually inspect them 87 | extern QImage qt_imageFromVideoFrame(const QVideoFrame &frame); 88 | 89 | QrDecoder::QrDecoder(QObject *parent) : QObject(parent) 90 | { } 91 | 92 | QString QrDecoder::captured() const 93 | { 94 | return _captured; 95 | } 96 | 97 | void QrDecoder::setCaptured(QString captured) 98 | { 99 | if (_captured == captured) { 100 | return; 101 | } 102 | 103 | _captured = captured; 104 | 105 | emit capturedChanged(_captured); 106 | } 107 | 108 | void QrDecoder::setIsDecoding(bool isDecoding) 109 | { 110 | if (_isDecoding == isDecoding) { 111 | return; 112 | } 113 | 114 | _isDecoding = isDecoding; 115 | 116 | emit isDecodingChanged(_isDecoding); 117 | } 118 | 119 | void QrDecoder::setVideoFrame(const QVideoFrame &videoFrame) 120 | { 121 | _videoFrame = videoFrame; 122 | } 123 | 124 | bool QrDecoder::isDecoding() const 125 | { 126 | return _isDecoding; 127 | } 128 | 129 | void QrDecoder::process(const QImage capturedImage) 130 | { 131 | setIsDecoding(true); 132 | 133 | const auto hints = DecodeHints() 134 | .setFormats(BarcodeFormat::QR_CODE | BarcodeFormat::DATA_MATRIX) 135 | .setTryHarder(true) 136 | .setBinarizer(Binarizer::FixedThreshold); 137 | 138 | const auto result = ReadBarcode(capturedImage, hints); 139 | 140 | if (result.isValid()) { 141 | setCaptured(result.text()); 142 | } 143 | 144 | setIsDecoding(false); 145 | } 146 | 147 | QVideoFrame QrDecoder::videoFrame() const 148 | { 149 | return _videoFrame; 150 | } 151 | 152 | QImage QrDecoder::videoFrameToImage(const QVideoFrame &videoFrame) 153 | { 154 | if (videoFrame.handleType() == QAbstractVideoBuffer::NoHandle) { 155 | const QImage::Format imageFormat = QVideoFrame::imageFormatFromPixelFormat(videoFrame.pixelFormat()); 156 | 157 | QImage image(videoFrame.bits(), 158 | videoFrame.width(), 159 | videoFrame.height(), 160 | videoFrame.bytesPerLine(), 161 | imageFormat); 162 | 163 | // QImage image = qt_imageFromVideoFrame( videoFrame ); 164 | if (image.isNull() ) { 165 | return QImage(); 166 | } 167 | 168 | if (image.format() != QImage::Format_ARGB32) { 169 | image = image.convertToFormat(QImage::Format_ARGB32); 170 | } 171 | 172 | return image; 173 | } 174 | 175 | if (videoFrame.handleType() == QAbstractVideoBuffer::GLTextureHandle) { 176 | QImage image(videoFrame.width(), videoFrame.height(), QImage::Format_ARGB32); 177 | 178 | GLuint textureId = static_cast( videoFrame.handle().toInt() ); 179 | 180 | QOpenGLContext *ctx = QOpenGLContext::currentContext(); 181 | 182 | QOpenGLFunctions *f = ctx->functions(); 183 | 184 | GLuint fbo; 185 | 186 | f->glGenFramebuffers(1, &fbo); 187 | 188 | GLint prevFbo; 189 | 190 | f->glGetIntegerv(GL_FRAMEBUFFER_BINDING, &prevFbo); 191 | f->glBindFramebuffer(GL_FRAMEBUFFER, fbo); 192 | f->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureId, 0); 193 | f->glReadPixels(0, 0, videoFrame.width(), videoFrame.height(), GL_RGBA, GL_UNSIGNED_BYTE, image.bits() ); 194 | f->glBindFramebuffer(GL_FRAMEBUFFER, static_cast( prevFbo ) ); 195 | 196 | return image.rgbSwapped(); 197 | } 198 | 199 | return QImage(); 200 | } // QRDecoder::videoFrameToImage 201 | -------------------------------------------------------------------------------- /examples/QmlBarcodeReader/qrScanner/QrDecoder.h: -------------------------------------------------------------------------------- 1 | #ifndef QR_DECODER_H 2 | #define QR_DECODER_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | /*! 9 | * \brief Class used to convert video frame into image and scan QR code from it. 10 | */ 11 | 12 | class QrDecoder : public QObject 13 | { 14 | Q_OBJECT 15 | Q_PROPERTY(QString captured READ captured WRITE setCaptured NOTIFY capturedChanged) 16 | Q_PROPERTY(bool isDecoding READ isDecoding WRITE setIsDecoding NOTIFY isDecodingChanged) 17 | 18 | public: 19 | 20 | /*! 21 | * \fn explicit QrDecoder(QObject *parent = nullptr) 22 | * \brief Constructor. 23 | * \param QObject *parent - a pointer to the parent object. 24 | */ 25 | explicit QrDecoder(QObject *parent = nullptr); 26 | 27 | /*! 28 | * \fn QString captured() const 29 | * \brief Returns the captured barcode string. 30 | */ 31 | QString captured() const; 32 | 33 | /*! 34 | * \fn bool isDecoding() const 35 | * \brief Returns the decoding state. 36 | */ 37 | bool isDecoding() const; 38 | 39 | /*! 40 | * \fn QVideoFrame videoFrame() const 41 | * \brief Returns the video frame of data. 42 | */ 43 | QVideoFrame videoFrame() const; 44 | 45 | /*! 46 | * \fn void setCtx(QOpenGLContext *ctx) 47 | * \brief Sets OpenGLContext. 48 | * \params QOpenGLContext *ctx - a pointer to opengl context. 49 | */ 50 | void setCtx(QOpenGLContext *ctx); 51 | 52 | /*! 53 | * \fn void setVideoFrame(const QVideoFrame &videoFrame) 54 | * \brief Sets video frame of data. 55 | * \params const QVideoFrame &videoFrame - video frame of data. 56 | */ 57 | void setVideoFrame(const QVideoFrame &videoFrame); 58 | 59 | /*! 60 | * \fn static QImage videoFrameToImage(QVideoFrame &videoFrame) 61 | * \brief Returns image from video frame. 62 | * \param QVideoFrame &videoFrame - frame of video data. 63 | */ 64 | static QImage videoFrameToImage(const QVideoFrame &videoFrame); 65 | 66 | public slots: 67 | 68 | /*! 69 | * \fn void process(const QImage capturedImage) 70 | * \brief Processes the image to scan the given barcode format types. 71 | * \param const QImage capturedImage - captured image. 72 | */ 73 | void process(const QImage capturedImage); 74 | 75 | signals: 76 | 77 | /*! 78 | * \brief This signal is emitted to send captured barcode string to QML. 79 | * \param const QString &captured - captured barcode string. 80 | */ 81 | void capturedChanged(const QString &captured); 82 | 83 | /*! 84 | * \brief This signal is emitted to send decoding state to QML. 85 | * \param bool isDecoding - decoding state. 86 | */ 87 | void isDecodingChanged(bool isDecoding); 88 | 89 | private: 90 | QString _captured = ""; 91 | 92 | QOpenGLContext *_ctx; 93 | 94 | bool _isDecoding = false; 95 | 96 | QVideoFrame _videoFrame; 97 | 98 | /*! 99 | * \fn void setCaptured(const QString &captured) 100 | * \brief Sets captured barcode string. 101 | * \param QString captured - captured barcode string. 102 | */ 103 | void setCaptured(QString captured); 104 | 105 | /*! 106 | * \fn void setIsDecoding(bool isDecoding) 107 | * \brief Sets decoding state. 108 | * \param bool isDecoding - decoding state. 109 | */ 110 | void setIsDecoding(bool isDecoding); 111 | }; 112 | 113 | #endif // QR_DECODER_H 114 | -------------------------------------------------------------------------------- /examples/QmlBarcodeReader/qrScanner/QrScannerFilter.cpp: -------------------------------------------------------------------------------- 1 | #include "QrScannerFilter.h" 2 | #include "QrDecoder.h" 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | void processImage(QrDecoder *decoder, const QImage &image) 13 | { 14 | decoder->process(image); 15 | }; 16 | 17 | /// This is linked to the private implementations of Qt. Check, when using a new versino of Qt that it still 18 | /// works. E.g. by saving the images to disk and visually inspect them 19 | extern QImage qt_imageFromVideoFrame(const QVideoFrame &frame); 20 | class QRRunnable : public QVideoFilterRunnable 21 | { 22 | public: 23 | 24 | /*! 25 | * \fn QrRunnable(QrScannerFilter *filter) 26 | * \brief Constructor. 27 | * \param QrScannerFilter *filter - a pointer to filter. 28 | */ 29 | QRRunnable(QrScannerFilter *filter) 30 | { 31 | _filter = filter; 32 | } 33 | 34 | /*! 35 | * \fn QVideoFrame run(QVideoFrame *input, const QVideoSurfaceFormat &surfaceFormat, QVideoFilterRunnable::RunFlags flags) override 36 | * \brief Run method in order to asynchronously process the input video frame. 37 | * \param QVideoFrame *input - a pointer to frame of video data. 38 | * \param const QVideoSurfaceFormat &surfaceFormat - the stream format of a video presentation surface. 39 | * \param QVideoFilterRunnable::RunFlags flags - typedef for QFlags. 40 | */ 41 | QVideoFrame run(QVideoFrame * input, 42 | const QVideoSurfaceFormat &surfaceFormat, 43 | QVideoFilterRunnable::RunFlags flags) override 44 | { 45 | Q_UNUSED(surfaceFormat); 46 | Q_UNUSED(flags); 47 | 48 | if (_filter->getDecoder()->isDecoding()) { 49 | return *input; 50 | } 51 | 52 | if (_filter->getFutureThread().isRunning()) { 53 | return *input; 54 | } 55 | 56 | _filter->getDecoder()->setVideoFrame(*input); 57 | 58 | QImage captured = QrDecoder::videoFrameToImage(*input); 59 | _filter->getFutureThread() = QtConcurrent::run(processImage, _filter->getDecoder(), captured); 60 | 61 | return *input; 62 | } 63 | 64 | private: 65 | QrScannerFilter *_filter; 66 | }; 67 | 68 | 69 | QrScannerFilter::QrScannerFilter() 70 | { 71 | _decoder = new QrDecoder; 72 | 73 | QObject::connect(_decoder, &QrDecoder::capturedChanged, this, &QrScannerFilter::setCaptured); 74 | } 75 | 76 | QVideoFilterRunnable *QrScannerFilter::createFilterRunnable() 77 | { 78 | return new QRRunnable(this); 79 | } 80 | 81 | QString QrScannerFilter::captured() const 82 | { 83 | return _captured; 84 | } 85 | 86 | void QrScannerFilter::setCaptured(const QString &newValue) 87 | { 88 | if (newValue == _captured) { 89 | return; 90 | } 91 | 92 | _captured = newValue; 93 | 94 | emit capturedChanged(); 95 | } 96 | 97 | QString QrScannerFilter::assayName() const 98 | { 99 | return m_assayName; 100 | } 101 | 102 | QrDecoder *QrScannerFilter::getDecoder() const 103 | { 104 | return _decoder; 105 | } 106 | 107 | bool QrScannerFilter::isDecoding() const 108 | { 109 | return _isDecoding; 110 | } 111 | 112 | void QrScannerFilter::setAssayName(QString assayName) 113 | { 114 | if (m_assayName == assayName) { 115 | return; 116 | } 117 | 118 | m_assayName = assayName; 119 | 120 | emit assayNameChanged(m_assayName); 121 | } 122 | 123 | QFuture QrScannerFilter::getFutureThread() const 124 | { 125 | return _futureThread; 126 | } 127 | -------------------------------------------------------------------------------- /examples/QmlBarcodeReader/qrScanner/QrScannerFilter.h: -------------------------------------------------------------------------------- 1 | #ifndef QRSCANNERFILTER_H 2 | #define QRSCANNERFILTER_H 3 | 4 | #include 5 | #include 6 | 7 | #include "QrDecoder.h" 8 | 9 | /*! 10 | * \brief Filter used to capture QR code from camera 11 | */ 12 | class QrScannerFilter : public QAbstractVideoFilter 13 | { 14 | Q_OBJECT 15 | 16 | Q_PROPERTY(QRectF captureRect MEMBER _captureRect NOTIFY captureRectChanged) 17 | Q_PROPERTY(QString captured READ captured NOTIFY capturedChanged) 18 | Q_PROPERTY(bool isDecoding READ isDecoding NOTIFY isDecodingChanged) 19 | Q_PROPERTY(QString assayName READ assayName WRITE setAssayName NOTIFY assayNameChanged) 20 | 21 | public: 22 | 23 | /*! 24 | * \fn QrScannerFilter() 25 | * \brief Constructor. 26 | */ 27 | QrScannerFilter(); 28 | 29 | /*! 30 | * \fn QString captured() const 31 | * \brief Returns the captured barcode string. 32 | */ 33 | QString captured() const; 34 | 35 | /*! 36 | * \fn QrDecoder *getDecoder() const 37 | * \brief Returns the decoder. 38 | */ 39 | QrDecoder *getDecoder() const; 40 | 41 | /*! 42 | * \fn QFuture getFutureThread() const 43 | * \brief Returns the future thread. 44 | */ 45 | QFuture getFutureThread() const; 46 | 47 | /*! 48 | * \fn bool isDecoding() const 49 | * \brief Returns the decoding state. 50 | */ 51 | bool isDecoding() const; 52 | 53 | /*! 54 | * \fn QVideoFilterRunnable *createFilterRunnable() override 55 | * \brief Returns instance of the SBarcodeFilterRunnable subclass. 56 | */ 57 | QVideoFilterRunnable *createFilterRunnable() override; 58 | 59 | /*! 60 | * \fn QString assayName() const 61 | * \brief Returns the assay name. 62 | */ 63 | QString assayName() const; 64 | 65 | public slots: 66 | 67 | /*! 68 | * \fn void setAssayName(QString assayName); 69 | * \brief Sets the assay name. 70 | * \param QString assayName - assay name. 71 | */ 72 | void setAssayName(QString assayName); 73 | 74 | signals: 75 | 76 | /*! 77 | * \brief This signal is emitted when capture area rectangle changed. 78 | */ 79 | void captureRectChanged(); 80 | 81 | /*! 82 | * \brief This signal is emitted when captured barcode string changed. 83 | */ 84 | void capturedChanged(); 85 | 86 | /*! 87 | * \brief This signal is emitted to send decoding state to QML. 88 | * \param bool isDecoding - decoding state. 89 | */ 90 | void isDecodingChanged(bool isDecoding); 91 | 92 | /*! 93 | * \brief This signal is emitted to send assay name to QML. 94 | * \param QString assayName - assay name. 95 | */ 96 | void assayNameChanged(QString assayName); 97 | 98 | private slots: 99 | 100 | /*! 101 | * \fn void setCaptured(const QString &captured) 102 | * \brief Sets captured barcode string. 103 | * \param const QString &captured - captured barcode string. 104 | */ 105 | void setCaptured(const QString &captured); 106 | 107 | private: 108 | QSharedPointer _mutexP; 109 | 110 | QRectF _captureRect; 111 | 112 | QString _captured; 113 | 114 | // QtEgoo::QtCapsuleQRData _capturedData; 115 | 116 | QrDecoder *_decoder; 117 | 118 | QFuture _futureThread; 119 | 120 | bool _isDecoding; 121 | 122 | QString m_assayName; 123 | }; 124 | 125 | #endif // QRSCANNERFILTER_H 126 | -------------------------------------------------------------------------------- /src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.1) 2 | 3 | project(SCodes LANGUAGES CXX) 4 | option(SCODES_DEBUG OFF) 5 | 6 | 7 | set(CMAKE_INCLUDE_CURRENT_DIR ON) 8 | set(CMAKE_AUTOMOC ON) 9 | set(CMAKE_AUTORCC ON) 10 | set(CMAKE_CXX_STANDARD 17) 11 | set(CMAKE_CXX_STANDARD_REQUIRED ON) 12 | 13 | if (NOT DEFINED BUILD_SHARED_LIBS) 14 | set(BUILD_SHARED_LIBS ON) 15 | endif() 16 | 17 | set(BUILD_UNIT_TESTS OFF) 18 | set(BUILD_BLACKBOX_TESTS OFF) 19 | set(BUILD_EXAMPLES OFF) 20 | add_subdirectory(zxing-cpp) 21 | 22 | find_package(QT NAMES Qt5 Qt6 COMPONENTS Core Multimedia Concurrent Quick REQUIRED) 23 | find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Core Multimedia Concurrent Quick REQUIRED) 24 | 25 | file(GLOB SOURCE_CPP 26 | "*.cpp" 27 | ) 28 | 29 | if(QT_VERSION_MAJOR EQUAL 6) 30 | list(FILTER SOURCE_CPP EXCLUDE REGEX "SBarcodeFilter.cpp") 31 | else() 32 | list(FILTER SOURCE_CPP EXCLUDE REGEX "SBarcodeScanner.cpp") 33 | endif() 34 | 35 | 36 | add_library(${PROJECT_NAME} STATIC ${SOURCE_CPP}) 37 | target_sources(${PROJECT_NAME} PRIVATE private/debug.h) 38 | set_target_properties(${PROJECT_NAME} PROPERTIES 39 | QT_QML_MODULE_VERSION 1.0 40 | QT_QML_MODULE_URI com.scythestudio.scodes 41 | 42 | ) 43 | if(SCODES_DEBUG) 44 | message("${PROJECT_NAME} debug messages enabled: ${SS_SCODES_DEBUG}") 45 | target_compile_definitions(${PROJECT_NAME} PUBLIC SCODES_DEBUG) 46 | endif() 47 | 48 | 49 | target_link_libraries(${PROJECT_NAME} PUBLIC ZXing Qt${QT_VERSION_MAJOR}::Core Qt${QT_VERSION_MAJOR}::Multimedia Qt${QT_VERSION_MAJOR}::Concurrent Qt${QT_VERSION_MAJOR}::Quick) 50 | target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}) 51 | target_include_directories(${PROJECT_NAME} PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/private") 52 | 53 | if (ANDROID) 54 | 55 | if(QT_VERSION_MAJOR EQUAL 5) 56 | find_package(Qt${QT_VERSION_MAJOR} COMPONENTS AndroidExtras REQUIRED) 57 | target_link_libraries(${PROJECT_NAME} PUBLIC Qt${QT_VERSION_MAJOR}::AndroidExtras) 58 | else() 59 | target_link_libraries(${PROJECT_NAME} PUBLIC Qt::CorePrivate) 60 | endif() 61 | 62 | target_link_libraries(${PROJECT_NAME} PUBLIC EGL GLESv2) 63 | endif() 64 | -------------------------------------------------------------------------------- /src/SBarcodeDecoder.cpp: -------------------------------------------------------------------------------- 1 | #include "SBarcodeDecoder.h" 2 | #include "ResultPoint.h" 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | #include 15 | #include "private/debug.h" 16 | 17 | /*! 18 | * \brief Provide an interface to access `ZXing::ReadBarcode` method 19 | */ 20 | namespace ZXing { 21 | namespace Qt { 22 | using ZXing::ReaderOptions; 23 | using ZXing::BarcodeFormat; 24 | using ZXing::BarcodeFormats; 25 | using ZXing::Binarizer; 26 | 27 | template 28 | QDebug operator << (QDebug dbg, const T& v) 29 | { 30 | return dbg.noquote() << QString::fromStdString(ToString(v)); 31 | } 32 | 33 | /*! 34 | * \brief Encapsulates the result of decoding a barcode within an image 35 | */ 36 | class Result : private ZXing::Result 37 | { 38 | public: 39 | /*! 40 | * \fn explicit Result(ZXing::Result&& r) : ZXing::Result(std::move(r)) 41 | * \brief Constructor 42 | * \param ZXing::Result&& r - Result class 43 | */ 44 | explicit Result(ZXing::Result&& r) : ZXing::Result(std::move(r)){ } 45 | 46 | using ZXing::Result::format; 47 | using ZXing::Result::isValid; 48 | 49 | /*! 50 | * \fn inline QString text() const 51 | * \return scanned result human readable text 52 | */ 53 | inline QString text() const { return QString::fromStdString(ZXing::Result::text()); } 54 | }; 55 | 56 | /*! 57 | * \fn Result ReadBarcode(const QImage& img, const ReaderOptions& options = { }) 58 | * \brief Interface for calling ZXing::ReadBarcode method to get result as a text. 59 | * \param const QImage& img - reference of the image to be processed 60 | * \param const ReaderOptions& options - barcode decode hints 61 | */ 62 | Result ReadBarcode(const QImage& img, const ReaderOptions& options = { }) 63 | { 64 | auto ImgFmtFromQImg = [](const QImage& img){ 65 | switch (img.format()) { 66 | case QImage::Format_ARGB32: 67 | case QImage::Format_RGB32: 68 | #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN 69 | return ImageFormat::BGRX; 70 | 71 | #else 72 | return ImageFormat::XRGB; 73 | 74 | #endif 75 | case QImage::Format_RGB888: return ImageFormat::RGB; 76 | 77 | case QImage::Format_RGBX8888: 78 | case QImage::Format_RGBA8888: return ImageFormat::RGBX; 79 | 80 | case QImage::Format_Grayscale8: return ImageFormat::Lum; 81 | 82 | default: return ImageFormat::None; 83 | } 84 | }; 85 | 86 | auto exec = [&](const QImage& img){ 87 | return Result(ZXing::ReadBarcode({ img.bits(), img.width(), img.height(), ImgFmtFromQImg(img) }, options)); 88 | }; 89 | 90 | return ImgFmtFromQImg(img) == ImageFormat::None ? exec(img.convertToFormat(QImage::Format_RGBX8888)) : exec(img); 91 | } 92 | } // Qt namespace 93 | } // ZXing namespace 94 | 95 | using namespace ZXing::Qt; 96 | 97 | std::ostream& operator << (std::ostream& os, const std::vector& points) 98 | { 99 | for (const auto& p : points) { 100 | os << int(p.x() + .5f) << "x" << int(p.y() + .5f) << " "; 101 | } 102 | 103 | return os; 104 | } 105 | 106 | SBarcodeDecoder::SBarcodeDecoder(QObject *parent) : QObject(parent) 107 | { } 108 | 109 | void SBarcodeDecoder::clean() 110 | { 111 | m_captured = ""; 112 | } 113 | 114 | QString SBarcodeDecoder::captured() const 115 | { 116 | return m_captured; 117 | } 118 | 119 | void SBarcodeDecoder::setCaptured(const QString &captured) 120 | { 121 | m_captured = captured; 122 | emit capturedChanged(m_captured); 123 | } 124 | 125 | void SBarcodeDecoder::setIsDecoding(bool isDecoding) 126 | { 127 | if (m_isDecoding == isDecoding) { 128 | return; 129 | } 130 | 131 | m_isDecoding = isDecoding; 132 | 133 | emit isDecodingChanged(m_isDecoding); 134 | } 135 | 136 | bool SBarcodeDecoder:: isDecoding() const 137 | { 138 | return m_isDecoding; 139 | } 140 | 141 | void SBarcodeDecoder::process(const QImage& capturedImage, ZXing::BarcodeFormats formats) 142 | { 143 | // This will set the "isDecoding" to false automatically 144 | auto decodeGuard = qScopeGuard([=](){setIsDecoding(false);}); 145 | SCODES_MEASURE(time); 146 | setIsDecoding(true); 147 | 148 | const auto readerOptions = ReaderOptions() 149 | .setFormats(formats) 150 | .setTryHarder(true) 151 | .setTryRotate(true) 152 | .setIsPure(false) 153 | .setBinarizer(Binarizer::LocalAverage); 154 | 155 | try{ 156 | const auto result = ReadBarcode(capturedImage, readerOptions); 157 | 158 | if (result.isValid()) { 159 | setCaptured(result.text()); 160 | } 161 | } 162 | catch(std::exception& e) { 163 | emit errorOccured("ZXing exception: " + QString::fromLocal8Bit(e.what())); 164 | } 165 | } 166 | 167 | QImage SBarcodeDecoder::videoFrameToImage(const QVideoFrame &videoFrame, const QRect &captureRect) const 168 | { 169 | 170 | #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 171 | 172 | auto handleType = videoFrame.handleType(); 173 | 174 | if (handleType == QAbstractVideoBuffer::NoHandle) { 175 | #if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0)) 176 | QImage image = videoFrame.image(); 177 | #else 178 | 179 | videoFrame.map(QAbstractVideoBuffer::ReadOnly); 180 | QImage image = imageFromVideoFrame(videoFrame); 181 | videoFrame.unmap(); 182 | 183 | #endif 184 | 185 | if (image.isNull()) { 186 | return QImage(); 187 | } 188 | 189 | if (image.format() != QImage::Format_ARGB32) { 190 | image = image.convertToFormat(QImage::Format_ARGB32); 191 | } 192 | 193 | return image.copy(captureRect); 194 | } 195 | 196 | if (handleType == QAbstractVideoBuffer::GLTextureHandle) { 197 | QImage image(videoFrame.width(), videoFrame.height(), QImage::Format_ARGB32); 198 | 199 | GLuint textureId = static_cast(videoFrame.handle().toInt()); 200 | 201 | QOpenGLContext *ctx = QOpenGLContext::currentContext(); 202 | 203 | QOpenGLFunctions *f = ctx->functions(); 204 | 205 | GLuint fbo; 206 | 207 | f->glGenFramebuffers(1, &fbo); 208 | 209 | GLint prevFbo; 210 | 211 | f->glGetIntegerv(GL_FRAMEBUFFER_BINDING, &prevFbo); 212 | f->glBindFramebuffer(GL_FRAMEBUFFER, fbo); 213 | f->glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureId, 0); 214 | f->glReadPixels(0, 0, videoFrame.width(), videoFrame.height(), GL_RGBA, GL_UNSIGNED_BYTE, image.bits()); 215 | f->glBindFramebuffer(GL_FRAMEBUFFER, static_cast( prevFbo ) ); 216 | f->glDeleteFramebuffers(1,&fbo); 217 | 218 | return image.rgbSwapped().copy(captureRect); 219 | } 220 | 221 | #else 222 | // The CPU / GPU buffer check is done internally, or so it seems 223 | return videoFrame.toImage().copy(captureRect).convertToFormat(QImage::Format_ARGB32); 224 | 225 | 226 | #endif // QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 227 | 228 | } 229 | 230 | void SBarcodeDecoder::setResolution(int w, int h) 231 | { 232 | m_resolution = QSize{w,h}; 233 | } 234 | 235 | void SBarcodeDecoder::setResolution(const QSize& newRes) 236 | { 237 | m_resolution = newRes; 238 | } 239 | -------------------------------------------------------------------------------- /src/SBarcodeDecoder.h: -------------------------------------------------------------------------------- 1 | #ifndef QR_DECODER_H 2 | #define QR_DECODER_H 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | #include "SBarcodeFormat.h" 11 | 12 | // Default camera resolution width/height 13 | #define DEFAULT_RES_W 1080 14 | #define DEFAULT_RES_H 1920 15 | 16 | /*! 17 | * \brief The SBarcodeDecoder class for decoding barcodes to human readable string 18 | */ 19 | class SBarcodeDecoder : public QObject 20 | { 21 | Q_OBJECT 22 | 23 | public: 24 | /*! 25 | * \fn explicit SBarcodeDecoder(QObject *parent) 26 | * \brief Constructor. 27 | * \param QObject *parent - a pointer to the parent object. 28 | */ 29 | explicit SBarcodeDecoder(QObject *parent = nullptr); 30 | 31 | /*! 32 | * \fn void clean() 33 | * \brief Sets the captured barcode string to empty. 34 | */ 35 | void clean(); 36 | 37 | /*! 38 | * \fn bool isDecoding() const 39 | * \brief Returns the decoding state. 40 | */ 41 | bool isDecoding() const; 42 | 43 | /*! 44 | * \fn QString captured() const 45 | * \brief Returns the captured barcode string. 46 | */ 47 | QString captured() const; 48 | 49 | /*! 50 | * \fn static QImage videoFrameToImage(QVideoFrame &videoFrame, const QRect &captureRect) 51 | * \brief Returns image from video frame. 52 | * \param QVideoFrame &videoFrame - frame of video data. 53 | * \param const QRect &captureRect - capture area rectangle. 54 | */ 55 | QImage videoFrameToImage(const QVideoFrame &videoFrame, const QRect &captureRect) const; 56 | 57 | /*! 58 | * \fn void setResolution(const int &w, const int &h) 59 | * \brief Update camera resolution values 60 | * \param w - width of the resolution 61 | * \param h - height of the resolution 62 | */ 63 | void setResolution(const QSize&); 64 | [[deprecated("Use QSize overload instead")]] void setResolution(int w, int h); 65 | 66 | public slots: 67 | /*! 68 | * \fn void process(const QImage capturedImage, ZXing::BarcodeFormats formats) 69 | * \brief Processes the image to scan the given barcode format types. 70 | * \param const QImage capturedImage - captured image. 71 | * \param ZXing::BarcodeFormats formats - barcode formats. 72 | */ 73 | void process(const QImage& capturedImage, ZXing::BarcodeFormats formats); 74 | 75 | signals: 76 | /*! 77 | * \brief This signal is emitted to send decoding state to QML. 78 | * \param bool isDecoding - decoding state. 79 | */ 80 | void isDecodingChanged(bool isDecoding); 81 | 82 | /*! 83 | * \brief This signal is emitted to send captured barcode string to QML. 84 | * \param const QString &captured - captured barcode string. 85 | */ 86 | void capturedChanged(const QString &captured); 87 | 88 | void errorOccured(const QString& errorString); 89 | 90 | private: 91 | /*! 92 | * \brief Indicates the decoding state 93 | */ 94 | bool m_isDecoding = false; 95 | 96 | /*! 97 | * \brief Captured string from barcode 98 | */ 99 | QString m_captured = ""; 100 | QSize m_resolution; 101 | 102 | /*! 103 | * \fn void setCaptured(const QString &captured) 104 | * \brief Sets captured barcode string. 105 | * \param const QString &captured - captured barcode string. 106 | */ 107 | void setCaptured(const QString &captured); 108 | 109 | /*! 110 | * \fn void setIsDecoding(bool isDecoding) 111 | * \brief Sets decoding state. 112 | * \param bool isDecoding - decoding state. 113 | */ 114 | void setIsDecoding(bool isDecoding); 115 | }; 116 | 117 | #endif // QR_DECODER_H 118 | -------------------------------------------------------------------------------- /src/SBarcodeFilter.cpp: -------------------------------------------------------------------------------- 1 | #include "SBarcodeFilter.h" 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | #include "SBarcodeDecoder.h" 8 | #include "private/debug.h" 9 | 10 | void processImage(SBarcodeDecoder *decoder, const QImage &image, ZXing::BarcodeFormats formats) 11 | { 12 | decoder->process(image, formats); 13 | } 14 | 15 | /*! 16 | * \brief Inherited from QVideoFilterRunnable class and provide `SBarcodeFilterRunnable::run` method in order to asynchronously process the input video frame 17 | */ 18 | class SBarcodeFilterRunnable : public QVideoFilterRunnable 19 | { 20 | public: 21 | 22 | /*! 23 | * \fn SBarcodeFilterRunnable(SBarcodeFilter *filter) 24 | * \brief Constructor. 25 | * \param SBarcodeFilter *filter - a pointer to filter. 26 | */ 27 | SBarcodeFilterRunnable(SBarcodeFilter *filter) 28 | : _filter{filter} 29 | { } 30 | 31 | /*! 32 | * \fn QVideoFrame run(QVideoFrame *input, const QVideoSurfaceFormat &surfaceFormat, QVideoFilterRunnable::RunFlags flags) override 33 | * \brief Run method in order to asynchronously process the input video frame. 34 | * \param QVideoFrame *input - a pointer to frame of video data. 35 | * \param const QVideoSurfaceFormat &surfaceFormat - the stream format of a video presentation surface. 36 | * \param QVideoFilterRunnable::RunFlags flags - typedef for QFlags. 37 | */ 38 | QVideoFrame run(QVideoFrame * input, 39 | const QVideoSurfaceFormat &surfaceFormat, 40 | QVideoFilterRunnable::RunFlags flags) override 41 | { 42 | Q_UNUSED(surfaceFormat); 43 | Q_UNUSED(flags); 44 | 45 | if (_filter->getDecoder()->isDecoding()) { 46 | return *input; 47 | } 48 | 49 | if (_filter->getImageFuture().isRunning()) { 50 | return *input; 51 | } 52 | 53 | const QImage croppedCapturedImage = 54 | _filter->getDecoder()->videoFrameToImage(*input, _filter->captureRect().toRect()); 55 | _filter->getImageFuture() = 56 | QtConcurrent::run(processImage, _filter->getDecoder(), croppedCapturedImage, 57 | SCodes::toZXingFormat(_filter->format())); 58 | 59 | 60 | return *input; 61 | } 62 | 63 | private: 64 | SBarcodeFilter *_filter; 65 | }; 66 | 67 | 68 | SBarcodeFilter::SBarcodeFilter(QObject *parent) 69 | : QAbstractVideoFilter{parent}, 70 | _decoder{new SBarcodeDecoder} 71 | { 72 | connect(_decoder, &SBarcodeDecoder::capturedChanged, this, &SBarcodeFilter::setCaptured); 73 | 74 | connect(this, &QAbstractVideoFilter::activeChanged, this, [this](){ 75 | if (this->isActive()) { 76 | this->clean(); 77 | } 78 | }); 79 | } 80 | 81 | QVideoFilterRunnable *SBarcodeFilter::createFilterRunnable() 82 | { 83 | sDebug() << "FILTER CREATED!"; 84 | return new SBarcodeFilterRunnable(this); 85 | } 86 | 87 | QString SBarcodeFilter::captured() const 88 | { 89 | return m_captured; 90 | } 91 | 92 | void SBarcodeFilter::setCaptured(const QString &captured) 93 | { 94 | if (captured == m_captured) { 95 | return; 96 | } 97 | 98 | m_captured = captured; 99 | 100 | emit capturedChanged(m_captured); 101 | } 102 | 103 | void SBarcodeFilter::clean() 104 | { 105 | m_captured = ""; 106 | 107 | _decoder->clean(); 108 | } 109 | 110 | QRectF SBarcodeFilter::captureRect() const 111 | { 112 | return m_captureRect; 113 | } 114 | 115 | void SBarcodeFilter::setCaptureRect(const QRectF &captureRect) 116 | { 117 | if (captureRect == m_captureRect) { 118 | return; 119 | } 120 | 121 | m_captureRect = captureRect; 122 | 123 | emit captureRectChanged(m_captureRect); 124 | } 125 | 126 | SBarcodeDecoder *SBarcodeFilter::getDecoder() const 127 | { 128 | return _decoder; 129 | } 130 | 131 | QFuture SBarcodeFilter::getImageFuture() const 132 | { 133 | return _imageFuture; 134 | } 135 | 136 | const SCodes::SBarcodeFormats &SBarcodeFilter::format() const 137 | { 138 | return m_format; 139 | } 140 | 141 | void SBarcodeFilter::setFormat(const SCodes::SBarcodeFormats &format) 142 | { 143 | sDebug() << "set format " << format << ", old format " << m_format; 144 | 145 | if (m_format != format) { 146 | m_format = format; 147 | emit formatChanged(m_format); 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /src/SBarcodeFilter.h: -------------------------------------------------------------------------------- 1 | #ifndef QRSCANNERFILTER_H 2 | #define QRSCANNERFILTER_H 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "SBarcodeDecoder.h" 9 | #include "SBarcodeFormat.h" 10 | 11 | /*! 12 | * \brief The SBarcodeFilter class is a custom class that allows image processing with the cooperation of QML VideoOutput type. 13 | */ 14 | class SBarcodeFilter : public QAbstractVideoFilter 15 | { 16 | Q_OBJECT 17 | Q_PROPERTY(QString captured READ captured NOTIFY capturedChanged) 18 | Q_PROPERTY(QRectF captureRect READ captureRect WRITE setCaptureRect NOTIFY captureRectChanged) 19 | Q_PROPERTY(SCodes::SBarcodeFormats format READ format WRITE setFormat NOTIFY formatChanged) 20 | 21 | public: 22 | 23 | /*! 24 | * \fn explicit SBarcodeFilter(QObject *parent) 25 | * \brief Constructor. 26 | * \param QObject *parent - a pointer to the parent object. 27 | */ 28 | explicit SBarcodeFilter(QObject *parent = nullptr); 29 | 30 | /*! 31 | * \fn QString captured() const 32 | * \brief Returns the captured barcode string. 33 | */ 34 | QString captured() const; 35 | 36 | /*! 37 | * \fn QRectF captureRect() const 38 | * \brief Returns the capture area rectangle. 39 | */ 40 | QRectF captureRect() const; 41 | 42 | /*! 43 | * \fn void setCaptureRect(const QRectF &captureRect) 44 | * \brief Sets the capture area rectangle. 45 | * \param const QRectF &captureRect - capture area rectagle. 46 | */ 47 | void setCaptureRect(const QRectF &captureRect); 48 | 49 | /*! 50 | * \fn SBarcodeDecoder *getDecoder() const 51 | * \brief Returns the decoder. 52 | */ 53 | SBarcodeDecoder *getDecoder() const; 54 | 55 | /*! 56 | * \fn QFuture getImageFuture() const 57 | * \brief Returns the future thread. 58 | */ 59 | QFuture getImageFuture() const; 60 | 61 | /*! 62 | * \fn QVideoFilterRunnable *createFilterRunnable() override 63 | * \brief Returns instance of the SBarcodeFilterRunnable subclass. 64 | */ 65 | QVideoFilterRunnable *createFilterRunnable() override; 66 | 67 | /*! 68 | * \fn const SCodes::SBarcodeFormats &format() const 69 | * \brief Returns the barcode format. 70 | */ 71 | const SCodes::SBarcodeFormats &format() const; 72 | 73 | /*! 74 | * \fn void setFormat(SCodes::SBarcodeFormat format) 75 | * \brief Sets the barcode format. 76 | * \param SCodes::SBarcodeFormat format - barcode format. 77 | */ 78 | void setFormat(const SCodes::SBarcodeFormats &format); 79 | 80 | signals: 81 | 82 | /*! 83 | * \brief This signal is emitted to send captured barcode string to QML. 84 | * \param const QString &captured - captured barcode string. 85 | */ 86 | void capturedChanged(const QString &captured); 87 | 88 | /*! 89 | * \brief This signal is emitted to send capture area rectangle to QML. 90 | * \param const QRectF &captureRect - capture area rectangle. 91 | */ 92 | void captureRectChanged(const QRectF &captureRect); 93 | 94 | /*! 95 | * \brief This signal is emitted to send barcode format to QML. 96 | * \param const SCodes::SBarcodeFormat &format - barcode format. 97 | */ 98 | void formatChanged(const SCodes::SBarcodeFormats &format); 99 | 100 | private slots: 101 | 102 | /*! 103 | * \fn void setCaptured(const QString &captured) 104 | * \brief Sets the captured barcode string. 105 | * \param const QString &captured - captured barcode string. 106 | */ 107 | void setCaptured(const QString &captured); 108 | 109 | /*! 110 | * \fn void clean() 111 | * \brief Sets the captured barcode string to empty. 112 | */ 113 | void clean(); 114 | 115 | private: 116 | QString m_captured = ""; 117 | 118 | QRectF m_captureRect; 119 | 120 | SBarcodeDecoder *_decoder; 121 | 122 | QFuture _imageFuture; 123 | 124 | SCodes::SBarcodeFormats m_format = SCodes::SBarcodeFormat::Basic; 125 | }; 126 | 127 | #endif // QRSCANNERFILTER_H 128 | -------------------------------------------------------------------------------- /src/SBarcodeFormat.cpp: -------------------------------------------------------------------------------- 1 | #include "SBarcodeFormat.h" 2 | 3 | /*! 4 | * Provide access to ZXing::BarcodeFormat's with SCodes::SBarcodeFormat keys 5 | */ 6 | namespace { 7 | const QMap k_formatsTranslations 8 | { 9 | { SCodes::SBarcodeFormat::None, ZXing::BarcodeFormat::None }, 10 | { SCodes::SBarcodeFormat::Aztec, ZXing::BarcodeFormat::Aztec }, 11 | { SCodes::SBarcodeFormat::Codabar, ZXing::BarcodeFormat::Codabar }, 12 | { SCodes::SBarcodeFormat::Code39, ZXing::BarcodeFormat::Code39 }, 13 | { SCodes::SBarcodeFormat::Code93, ZXing::BarcodeFormat::Code93 }, 14 | { SCodes::SBarcodeFormat::Code128, ZXing::BarcodeFormat::Code128 }, 15 | { SCodes::SBarcodeFormat::DataBar, ZXing::BarcodeFormat::DataBar }, 16 | { SCodes::SBarcodeFormat::DataBarExpanded, ZXing::BarcodeFormat::DataBarExpanded }, 17 | { SCodes::SBarcodeFormat::DataMatrix, ZXing::BarcodeFormat::DataMatrix }, 18 | { SCodes::SBarcodeFormat::EAN8, ZXing::BarcodeFormat::EAN8 }, 19 | { SCodes::SBarcodeFormat::EAN13, ZXing::BarcodeFormat::EAN13 }, 20 | { SCodes::SBarcodeFormat::ITF, ZXing::BarcodeFormat::ITF }, 21 | { SCodes::SBarcodeFormat::MaxiCode, ZXing::BarcodeFormat::MaxiCode }, 22 | { SCodes::SBarcodeFormat::PDF417, ZXing::BarcodeFormat::PDF417 }, 23 | { SCodes::SBarcodeFormat::QRCode, ZXing::BarcodeFormat::QRCode }, 24 | { SCodes::SBarcodeFormat::UPCA, ZXing::BarcodeFormat::UPCA }, 25 | { SCodes::SBarcodeFormat::UPCE, ZXing::BarcodeFormat::UPCE }, 26 | { SCodes::SBarcodeFormat::MicroQRCode, ZXing::BarcodeFormat::MicroQRCode }, 27 | { SCodes::SBarcodeFormat::RMQRCode, ZXing::BarcodeFormat::RMQRCode }, 28 | { SCodes::SBarcodeFormat::DXFilmEdge, ZXing::BarcodeFormat::DXFilmEdge }, 29 | { SCodes::SBarcodeFormat::Any, ZXing::BarcodeFormat::Any }, 30 | }; 31 | } 32 | 33 | ZXing::BarcodeFormat SCodes::toZXingFormat(SBarcodeFormat format) 34 | { 35 | return k_formatsTranslations[format]; 36 | } 37 | 38 | QString SCodes::toString(SBarcodeFormat format) 39 | { 40 | return QString::fromStdString(ZXing::ToString(toZXingFormat(format))); 41 | } 42 | 43 | SCodes::SBarcodeFormat SCodes::fromString(const QString &formatName) 44 | { 45 | const auto zxingFormat = ZXing::BarcodeFormatFromString(formatName.toStdString()); 46 | 47 | QMapIterator it(k_formatsTranslations); 48 | 49 | while (it.hasNext()) { 50 | it.next(); 51 | 52 | if (it.value() == zxingFormat) { 53 | return it.key(); 54 | } 55 | } 56 | 57 | return SCodes::SBarcodeFormat::None; 58 | } 59 | 60 | ZXing::BarcodeFormats SCodes::toZXingFormat(SBarcodeFormats formats) 61 | { 62 | ZXing::BarcodeFormats zXingformats; 63 | 64 | int formatEnumIndex = SCodes::staticMetaObject.indexOfEnumerator("SBarcodeFormat"); 65 | 66 | QMetaEnum sBarcodeFormatEnumMeta = SCodes::staticMetaObject.enumerator(formatEnumIndex); 67 | 68 | for (int i = 0; i < sBarcodeFormatEnumMeta.keyCount(); ++i) { 69 | const auto key = sBarcodeFormatEnumMeta.key(i); 70 | 71 | const auto value = sBarcodeFormatEnumMeta.keyToValue(key); 72 | 73 | const auto enumValue = static_cast(value); 74 | 75 | if (formats.testFlag(enumValue)) { 76 | zXingformats |= toZXingFormat(enumValue); 77 | } 78 | } 79 | 80 | return zXingformats; 81 | } 82 | -------------------------------------------------------------------------------- /src/SBarcodeFormat.h: -------------------------------------------------------------------------------- 1 | #ifndef SBARCODEFORMAT_H 2 | #define SBARCODEFORMAT_H 3 | 4 | #include 5 | 6 | #include "BarcodeFormat.h" 7 | 8 | namespace SCodes { 9 | Q_NAMESPACE 10 | 11 | /*! 12 | * \brief The SBarcodeFormat is binary enumeration class for barcode types 13 | */ 14 | enum class SBarcodeFormat : int { 15 | None = 0, 16 | Aztec = (1 << 0), 17 | Codabar = (1 << 1), 18 | Code39 = (1 << 2), 19 | Code93 = (1 << 3), 20 | Code128 = (1 << 4), 21 | DataBar = (1 << 5), 22 | DataBarExpanded = (1 << 6), 23 | DataMatrix = (1 << 7), 24 | EAN8 = (1 << 8), 25 | EAN13 = (1 << 9), 26 | ITF = (1 << 10), 27 | MaxiCode = (1 << 11), 28 | PDF417 = (1 << 12), 29 | QRCode = (1 << 13), 30 | UPCA = (1 << 14), 31 | UPCE = (1 << 15), 32 | MicroQRCode = (1 << 16), 33 | RMQRCode = (1 << 17), 34 | DXFilmEdge = (1 << 18), 35 | 36 | OneDCodes = Codabar | Code39 | Code93 | Code128 | EAN8 | EAN13 | ITF | DataBar | DataBarExpanded | UPCA 37 | | UPCE | DXFilmEdge, 38 | TwoDCodes = Aztec | DataMatrix | MaxiCode | PDF417 | QRCode | MicroQRCode | RMQRCode, 39 | Any = OneDCodes | TwoDCodes, 40 | Basic = Code39 | Code93 | Code128 | QRCode | DataMatrix, 41 | }; 42 | 43 | Q_DECLARE_FLAGS(SBarcodeFormats, SBarcodeFormat) 44 | Q_DECLARE_OPERATORS_FOR_FLAGS(SBarcodeFormats) 45 | Q_FLAG_NS(SBarcodeFormats) 46 | 47 | /*! 48 | * \fn ZXing::BarcodeFormat toZXingFormat(SBarcodeFormat format) 49 | * \brief Returns ZXing barcode format for given SCode barcode format. 50 | * \param SBarcodeFormat format - SCodes barcode format. 51 | */ 52 | ZXing::BarcodeFormat toZXingFormat(SBarcodeFormat format); 53 | 54 | /*! 55 | * \fn ZXing::BarcodeFormats toZXingFormat(SBarcodeFormats formats) 56 | * \brief Returns ZXing barcode formats for given SCodes barcode formats. 57 | * \param SBarcodeFormats formats - SCodes barcode formats. 58 | */ 59 | ZXing::BarcodeFormats toZXingFormat(SBarcodeFormats formats); 60 | 61 | /*! 62 | * \fn QString toString(SBarcodeFormat format) 63 | * \brief Returns format string for given SCode barcode format. 64 | * \param SBarcodeFormat format - SCodes barcode format. 65 | */ 66 | QString toString(SBarcodeFormat format); 67 | 68 | /*! 69 | * \fn SBarcodeFormat fromString(const QString &formatName) 70 | * \brief Returns SCode barcode format for given barcode format string. 71 | * \param const QString &formatName - barcode format string. 72 | */ 73 | SBarcodeFormat fromString(const QString &formatName); 74 | } 75 | 76 | #endif // SBARCODEFORMAT_H 77 | -------------------------------------------------------------------------------- /src/SBarcodeGenerator.cpp: -------------------------------------------------------------------------------- 1 | #include "SBarcodeGenerator.h" 2 | #include 3 | #include 4 | 5 | #ifdef Q_OS_ANDROID 6 | #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 7 | #include 8 | #else 9 | #include 10 | #endif 11 | #endif 12 | 13 | #include "MultiFormatWriter.h" 14 | 15 | SBarcodeGenerator::SBarcodeGenerator(QQuickItem *parent) 16 | : QQuickItem(parent) 17 | { } 18 | 19 | bool SBarcodeGenerator::generate(const QString &inputString) 20 | { 21 | try { 22 | if (inputString.isEmpty()) { 23 | return false; 24 | } else { 25 | // Change ecc level to max to generate image on QR code. 26 | if (m_format == SCodes::SBarcodeFormat::QRCode && !m_imagePath.isEmpty()) { 27 | if (m_eccLevel < 8) { 28 | qDebug() << "To draw image on QR Code use maximum level of ecc. Setting it to 8."; 29 | 30 | setEccLvel(8); 31 | } 32 | } 33 | 34 | ZXing::MultiFormatWriter writer = ZXing::MultiFormatWriter(SCodes::toZXingFormat(m_format)) 35 | .setMargin(m_margin) 36 | .setEccLevel(m_eccLevel); 37 | 38 | auto qrCodeMatrix = writer.encode(inputString.toStdString(), m_width, m_height); 39 | 40 | QImage image(m_width, m_height, QImage::Format_ARGB32); 41 | 42 | for (int y = 0; y < m_height; ++y) { 43 | for (int x = 0; x < m_width; ++x) { 44 | if (qrCodeMatrix.get(x, y)) { 45 | image.setPixelColor(x, y, m_foregroundColor); 46 | } else { 47 | image.setPixelColor(x, y, m_backgroundColor); 48 | } 49 | } 50 | } 51 | 52 | // Center images works only on QR codes. 53 | if (m_format == SCodes::SBarcodeFormat::QRCode) { 54 | if (!m_imagePath.isEmpty()) { 55 | QSize centerImageSize(m_width / m_centerImageRatio, m_height / m_centerImageRatio); 56 | drawCenterImage(&image, m_imagePath, centerImageSize, 57 | (image.width() - centerImageSize.width()) / 2, 58 | (image.height() - centerImageSize.height()) / 2); 59 | } else { 60 | qDebug() << "Center Image path is empty. Skip drawing center image."; 61 | } 62 | } else { 63 | qDebug() << "Center images works only on QR codes."; 64 | } 65 | 66 | m_filePath = QDir::tempPath() + "/" + m_fileName + "." + m_extension; 67 | 68 | QFile file{m_filePath}; 69 | if (file.open(QIODevice::WriteOnly | QIODevice::Truncate)) { 70 | image.save(&file); 71 | } else { 72 | qWarning() << "Could not open file for writing!"; 73 | return false; 74 | } 75 | 76 | emit generationFinished(); 77 | 78 | return true; 79 | } 80 | } catch (const std::exception &e) { 81 | emit generationFinished(e.what()); 82 | } catch (...) { 83 | emit generationFinished("Unsupported exception thrown"); 84 | } 85 | 86 | return false; 87 | } // SBarcodeGenerator::generate 88 | 89 | bool SBarcodeGenerator::saveImage() 90 | { 91 | if (m_filePath.isEmpty()) { 92 | return false; 93 | } 94 | 95 | #ifdef Q_OS_ANDROID 96 | 97 | #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) 98 | if (QtAndroid::checkPermission(QString("android.permission.WRITE_EXTERNAL_STORAGE")) == 99 | QtAndroid::PermissionResult::Denied) 100 | { 101 | QtAndroid::PermissionResultMap resultHash = 102 | QtAndroid::requestPermissionsSync(QStringList({ "android.permission.WRITE_EXTERNAL_STORAGE" })); 103 | if (resultHash["android.permission.WRITE_EXTERNAL_STORAGE"] == QtAndroid::PermissionResult::Denied) { 104 | return false; 105 | } 106 | } 107 | #else 108 | 109 | QtAndroidPrivate::requestPermission(QString("android.permission.WRITE_EXTERNAL_STORAGE")); 110 | 111 | #endif 112 | #endif 113 | 114 | QString docFolder = QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation) + "/" + m_fileName + "." 115 | + m_extension; 116 | 117 | QFile::copy(m_filePath, docFolder); 118 | 119 | return true; 120 | } 121 | 122 | void SBarcodeGenerator::drawCenterImage(QImage *parentImage, const QString &imagePath, QSize imageSize, int x, int y) 123 | { 124 | QImage centerImage(imageSize, QImage::Format_RGB32); 125 | centerImage.load(imagePath); 126 | 127 | if (centerImage.isNull()) { 128 | qWarning() << "Center image could not be loaded!"; 129 | return; 130 | } 131 | 132 | // Create a painter to overlay the center image on the parentImage. 133 | QPainter painter(parentImage); 134 | 135 | // Draw background rectangle. 136 | painter.setBrush(Qt::white); 137 | painter.setPen(Qt::NoPen); 138 | painter.drawRect(x, y, imageSize.width(), imageSize.height()); 139 | 140 | // Scale the center image to be smaller than background rectangle. 141 | float imageRatio = 0.8; 142 | centerImage = centerImage.scaled(imageSize.width() * imageRatio, 143 | imageSize.height() * imageRatio, 144 | Qt::KeepAspectRatio, Qt::SmoothTransformation); 145 | 146 | // Draw image. 147 | painter.drawImage(x + (imageSize.width() - centerImage.width()) / 2, 148 | y + (imageSize.height() - centerImage.height()) / 2, 149 | centerImage); 150 | painter.end(); 151 | } 152 | 153 | void SBarcodeGenerator::setEccLvel(int eccLevel) 154 | { 155 | if (m_eccLevel == eccLevel) { 156 | return; 157 | } 158 | 159 | m_eccLevel = eccLevel; 160 | emit eccLevelChanged(m_eccLevel); 161 | } 162 | 163 | SCodes::SBarcodeFormat SBarcodeGenerator::format() const 164 | { 165 | return m_format; 166 | } 167 | 168 | void SBarcodeGenerator::setFormat(SCodes::SBarcodeFormat format) 169 | { 170 | if (m_format != format) { 171 | switch (format) { 172 | case SCodes::SBarcodeFormat::None: 173 | qWarning() << "You need to set a specific format"; 174 | return; 175 | 176 | case SCodes::SBarcodeFormat::Any: 177 | case SCodes::SBarcodeFormat::OneDCodes: 178 | case SCodes::SBarcodeFormat::TwoDCodes: 179 | qWarning() << "Multiple formats can't be used to generate a barcode"; 180 | return; 181 | 182 | default: 183 | m_format = format; 184 | emit formatChanged(m_format); 185 | } 186 | } 187 | } 188 | 189 | void SBarcodeGenerator::setFormat(const QString &formatName) 190 | { 191 | setFormat(SCodes::fromString(formatName)); 192 | } 193 | 194 | QString SBarcodeGenerator::imagePath() const 195 | { 196 | return m_imagePath; 197 | } 198 | 199 | void SBarcodeGenerator::setImagePath(const QString &imagePath) 200 | { 201 | if (m_imagePath == imagePath) { 202 | return; 203 | } 204 | 205 | m_imagePath = imagePath; 206 | emit imagePathChanged(); 207 | } 208 | 209 | int SBarcodeGenerator::centerImageRatio() const 210 | { 211 | return m_centerImageRatio; 212 | } 213 | 214 | void SBarcodeGenerator::setCenterImageRatio(int centerImageRatio) 215 | { 216 | if (m_centerImageRatio == centerImageRatio) { 217 | return; 218 | } 219 | 220 | m_centerImageRatio = centerImageRatio; 221 | emit centerImageRatioChanged(); 222 | } 223 | 224 | QColor SBarcodeGenerator::foregroundColor() const 225 | { 226 | return m_foregroundColor; 227 | } 228 | 229 | void SBarcodeGenerator::setForegroundColor(const QColor &foregroundColor) 230 | { 231 | if (m_foregroundColor == foregroundColor) { 232 | return; 233 | } 234 | 235 | m_foregroundColor = foregroundColor; 236 | emit foregroundColorChanged(); 237 | } 238 | 239 | QColor SBarcodeGenerator::backgroundColor() const 240 | { 241 | return m_backgroundColor; 242 | } 243 | 244 | void SBarcodeGenerator::setBackgroundColor(const QColor &backgroundColor) 245 | { 246 | if (m_backgroundColor == backgroundColor) { 247 | return; 248 | } 249 | 250 | m_backgroundColor = backgroundColor; 251 | emit backgroundColorChanged(); 252 | } 253 | -------------------------------------------------------------------------------- /src/SBarcodeGenerator.h: -------------------------------------------------------------------------------- 1 | #ifndef SBARCODEGENERATOR_H 2 | #define SBARCODEGENERATOR_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include "BitMatrix.h" 11 | #include "ByteMatrix.h" 12 | 13 | #include "SBarcodeFormat.h" 14 | 15 | /*! 16 | * \brief The SBarcodeGenerator class allows you to configure, generate & save barcodes. 17 | */ 18 | class SBarcodeGenerator : public QQuickItem 19 | { 20 | Q_OBJECT 21 | Q_PROPERTY(int width MEMBER m_width NOTIFY widthChanged) 22 | Q_PROPERTY(int height MEMBER m_height NOTIFY heightChanged) 23 | Q_PROPERTY(int margin MEMBER m_margin NOTIFY marginChanged) 24 | Q_PROPERTY(int eccLevel MEMBER m_eccLevel NOTIFY eccLevelChanged) 25 | Q_PROPERTY(QString fileName MEMBER m_fileName NOTIFY fileNameChanged) 26 | Q_PROPERTY(QString extension MEMBER m_extension) 27 | Q_PROPERTY(QString filePath MEMBER m_filePath) 28 | Q_PROPERTY(QString inputText MEMBER m_inputText) 29 | Q_PROPERTY(SCodes::SBarcodeFormat format READ format WRITE setFormat NOTIFY formatChanged) 30 | Q_PROPERTY(QString imagePath READ imagePath WRITE setImagePath NOTIFY imagePathChanged) 31 | Q_PROPERTY(int centerImageRatio READ centerImageRatio WRITE setCenterImageRatio NOTIFY centerImageRatioChanged) 32 | Q_PROPERTY(QColor foregroundColor READ foregroundColor WRITE setForegroundColor NOTIFY foregroundColorChanged) 33 | Q_PROPERTY(QColor backgroundColor READ backgroundColor WRITE setBackgroundColor NOTIFY backgroundColorChanged) 34 | 35 | public: 36 | 37 | /*! 38 | * \fn explicit SBarcodeGenerator(QObject *parent) 39 | * \brief Constructor. 40 | * \param QObject *parent - a pointer to the parent object. 41 | */ 42 | explicit SBarcodeGenerator(QQuickItem *parent = nullptr); 43 | 44 | /*! 45 | * \fn ~SBarcodeGenerator() override 46 | * \brief Destructor. 47 | */ 48 | ~SBarcodeGenerator() override { } 49 | 50 | /*! 51 | * \fn SCodes::SBarcodeFormat format() const 52 | * \brief Returns current barcode format. 53 | */ 54 | SCodes::SBarcodeFormat format() const; 55 | 56 | /*! 57 | * \fn void setFormat(SCodes::SBarcodeFormat format) 58 | * \brief Sets the barcode format. 59 | * \param SCodes::SBarcodeFormat format - barcode format. 60 | */ 61 | void setFormat(SCodes::SBarcodeFormat format); 62 | 63 | /*! 64 | * \fn QString imagePath() const 65 | * \brief Returns the center image path. 66 | */ 67 | QString imagePath() const; 68 | 69 | /*! 70 | * \fn void setImagePath(const QString &imagePath) 71 | * \brief Sets the center image path. 72 | * \param const QString &imagePath - new image path. 73 | */ 74 | void setImagePath(const QString &imagePath); 75 | 76 | /*! 77 | * \fn int centerImageRatio() const 78 | * \brief Returns the center image ratio. 79 | */ 80 | int centerImageRatio() const; 81 | 82 | /*! 83 | * \fn void setCenterImageRatio(int centerImageRatio) 84 | * \brief Sets the center image ratio. 85 | * \param const int ¢erImageRatio - new image ratio. 86 | */ 87 | void setCenterImageRatio(int centerImageRatio); 88 | 89 | /*! 90 | * \fn QColor foregroundColor() const 91 | * \brief Returns foregroundColor. 92 | */ 93 | QColor foregroundColor() const; 94 | 95 | 96 | /*! 97 | * \fn QColor backgroundColor() const 98 | * \brief Returns backgroundColor. 99 | */ 100 | QColor backgroundColor() const; 101 | 102 | public slots: 103 | 104 | /*! 105 | * \fn bool generate(const QString &inputString) 106 | * \brief Function for generating barcodes from given string 107 | * \param const QString &inputString - string of the barcode 108 | */ 109 | bool generate(const QString &inputString); 110 | 111 | /*! 112 | * \fn void setFormat(const QString &formatName) 113 | * \brief Sets the barcode format. 114 | * \param const QString &formatName - barcode format string. 115 | */ 116 | void setFormat(const QString &formatName); 117 | 118 | /*! 119 | * \fn bool saveImage() 120 | * \brief Saves the generated barcode image. 121 | */ 122 | bool saveImage(); 123 | 124 | /*! 125 | * \fn void setForegroundColor(const QColor &newForegroundColor) 126 | * \brief Sets the foreground. 127 | * \param const QColor &foreground - foreground color. 128 | */ 129 | void setForegroundColor(const QColor &foregroundColor); 130 | 131 | /*! 132 | * \fn void setBackgroundColor(const QColor &backgroundColor) 133 | * \brief Sets the backgroundColor. 134 | * \param const QColor &backgroundColor - background color. 135 | */ 136 | void setBackgroundColor(const QColor &backgroundColor); 137 | 138 | signals: 139 | 140 | /*! 141 | * \brief This signal is emitted when barcode generation is finished. If any error happens, sends the error string to QML. 142 | * \param const QString &error - error string. 143 | */ 144 | void generationFinished(const QString &error = ""); 145 | 146 | /*! 147 | * \brief This signal is emitted to send width to QML. 148 | * \param int width - width. 149 | */ 150 | void widthChanged(int width); 151 | 152 | /*! 153 | * \brief This signal is emitted to send height to QML. 154 | * \param int height - height. 155 | */ 156 | void heightChanged(int height); 157 | 158 | /*! 159 | * \brief This signal is emitted to send margin to QML. 160 | * \param int margin - margin. 161 | */ 162 | void marginChanged(int margin); 163 | 164 | /*! 165 | * \brief This signal is emitted to send eccLevel to QML. 166 | * \param int eccLevel - error correction code level. 167 | */ 168 | void eccLevelChanged(int eccLevel); 169 | 170 | /*! 171 | * \brief This signal is emitted to send fileName to QML. 172 | * \param const QString &fileName - fileName. 173 | */ 174 | void fileNameChanged(const QString &fileName); 175 | 176 | /*! 177 | * \brief This signal is emitted to send barcode format to QML. 178 | * \param SCodes::SBarcodeFormat format - barcode format. 179 | */ 180 | void formatChanged(SCodes::SBarcodeFormat format); 181 | 182 | /*! 183 | * \brief This signal is emitted to send image path to QML. 184 | */ 185 | void imagePathChanged(); 186 | 187 | /*! 188 | * \brief This signal is emitted to send center image ratio to QML. 189 | */ 190 | void centerImageRatioChanged(); 191 | 192 | /*! 193 | * \brief This signal is emitted to send foregroundColor to QML. 194 | * \param const QColor &foregroundColor - foregroundColor. 195 | */ 196 | void foregroundColorChanged(); 197 | 198 | /*! 199 | * \brief This signal is emitted to send backgroundColor to QML. 200 | * \param const QColor &backgroundColor - backgroundColor. 201 | */ 202 | void backgroundColorChanged(); 203 | 204 | private: 205 | int m_width = 500; 206 | int m_height = 500; 207 | int m_margin = 10; 208 | int m_eccLevel = -1; 209 | 210 | // centerImageRatio defines the ratio by which the center image is smaller than the QR code. 211 | int m_centerImageRatio = 5; 212 | 213 | QString m_extension = "png"; 214 | QString m_fileName = "code"; 215 | QString m_filePath = ""; 216 | QString m_inputText = ""; 217 | QString m_imagePath = ""; 218 | 219 | SCodes::SBarcodeFormat m_format = SCodes::SBarcodeFormat::Code128; 220 | 221 | /*! 222 | * \brief This method draws Rectangle and `imageRatio` smaller Image in the center of that Rectangle. 223 | * \param QImage *parentImage - Image parent. It is used for Painter constructor. 224 | * \param QString imagePath - Image path. 225 | * \param QSize imageSize - Image size. 226 | * \param int x - X coordinate where Image should be painted. 227 | * \param Qint y - Y coordinate where Image should be painted. 228 | */ 229 | void drawCenterImage(QImage *parentImage, const QString &imagePath, QSize imageSize, int x, int y); 230 | 231 | /*! 232 | * \fn void setEccLvel(int eccLevel) 233 | * \brief Sets the QR code ecc level. 234 | * \param int eccLevel - QR code ecc level. 235 | */ 236 | void setEccLvel(int eccLevel); 237 | 238 | QColor m_foregroundColor = "black"; 239 | QColor m_backgroundColor = "white"; 240 | }; 241 | 242 | #endif // SBARCODEGENERATOR_H 243 | -------------------------------------------------------------------------------- /src/SBarcodeScanner.cpp: -------------------------------------------------------------------------------- 1 | #include "SBarcodeScanner.h" 2 | #include 3 | #include "private/debug.h" 4 | SBarcodeScanner::SBarcodeScanner(QObject* parent) 5 | : QVideoSink(parent) 6 | , m_camera(nullptr) 7 | , m_scanning{true} 8 | { 9 | // Print error message if error occurs 10 | connect(this, &SBarcodeScanner::errorOccured, this, [](const QString& msg){ 11 | qWarning() << "SCodes Error:" << msg; 12 | }); 13 | // Connect self to the media capture session 14 | m_capture.setVideoSink(this); 15 | connect(this, &QVideoSink::videoFrameChanged, this, &SBarcodeScanner::tryProcessFrame); 16 | 17 | // Connect cameraAvaliable property. Utilise implicit conversion from pointer to bool. 18 | connect(this, &SBarcodeScanner::cameraChanged, this, &SBarcodeScanner::setCameraAvailable); 19 | 20 | 21 | m_decoder.moveToThread(&workerThread); 22 | connect(&m_decoder, &SBarcodeDecoder::capturedChanged, this, &SBarcodeScanner::setCaptured, Qt::QueuedConnection); 23 | connect(&m_decoder, &SBarcodeDecoder::errorOccured, this, &SBarcodeScanner::errorOccured, Qt::QueuedConnection); 24 | workerThread.start(); 25 | } 26 | 27 | SBarcodeScanner::~SBarcodeScanner() 28 | { 29 | workerThread.quit(); 30 | workerThread.wait(); 31 | } 32 | 33 | SBarcodeDecoder* SBarcodeScanner::getDecoder() 34 | { 35 | return &m_decoder; 36 | } 37 | 38 | void SBarcodeScanner::componentComplete() 39 | { 40 | sDebug() << "Component complete, Camera status: " << m_camera; 41 | if(m_camera.isNull()) 42 | { 43 | sDebug() << "No camera provided. Setting default camera"; 44 | setCamera(makeDefaultCamera()); 45 | } 46 | } 47 | 48 | void SBarcodeScanner::classBegin() 49 | { 50 | return; 51 | } 52 | 53 | void SBarcodeScanner::tryProcessFrame(const QVideoFrame& frame) 54 | { 55 | if(!m_scanning || m_frameProcessingInProgress) { 56 | return; 57 | } 58 | // Set the guard variable to not process more than 1 frame at the time 59 | m_frameProcessingInProgress = true; 60 | 61 | // Scale the normalized rectangle for camera resolution 62 | auto r = m_camera->cameraFormat().resolution(); 63 | auto cRect = QRectF{m_captureRect.x()*r.width(), 64 | m_captureRect.y()*r.height(), 65 | m_captureRect.width()*r.width(), 66 | m_captureRect.height()*r.height()}.toRect(); 67 | 68 | // Invoke processing asynchronously, potential result will be reported by capturedChanged signal 69 | // We can copy QVideoFrame as it's explicitly shared (just like std::shared_ptr) 70 | // Note the releasing the guard variable 71 | QMetaObject::invokeMethod(&m_decoder, [=](){ 72 | m_decoder.process(m_decoder.videoFrameToImage(frame, cRect),SCodes::toZXingFormat(SCodes::SBarcodeFormat::Basic)); 73 | m_frameProcessingInProgress = false; 74 | }); 75 | } 76 | 77 | void SBarcodeScanner::setCameraAvailable(bool available) 78 | { 79 | if (m_cameraAvailable == available) { 80 | return; 81 | } 82 | 83 | m_cameraAvailable = available; 84 | emit cameraAvailableChanged(); 85 | } 86 | 87 | QCamera *SBarcodeScanner::makeDefaultCamera() 88 | { 89 | auto defaultCamera = QMediaDevices::defaultVideoInput(); 90 | if (defaultCamera.isNull()) 91 | { 92 | errorOccured("No default camera could be found on the system"); 93 | return nullptr; 94 | } 95 | 96 | auto camera = new QCamera(defaultCamera, this); 97 | if (camera->error()) { 98 | errorOccured("Error during camera initialization: " + camera->errorString()); 99 | return nullptr; 100 | } 101 | 102 | auto supportedFormats = camera->cameraDevice().videoFormats(); 103 | for (auto f : supportedFormats) 104 | { 105 | sDebug() << "Supported format: " 106 | << f.pixelFormat() 107 | << f.resolution() 108 | << " FPS:" << f.minFrameRate() << "-" << f.maxFrameRate(); 109 | } 110 | if(supportedFormats.empty()) 111 | { 112 | errorOccured("A default camera was found but it has no supported formats. The Camera may be wrongly configured."); 113 | return nullptr; 114 | } 115 | 116 | /// Pick best format - most pixels 117 | std::sort(supportedFormats.begin(),supportedFormats.end(),[](const auto& f1, const auto& f2){ 118 | QSize r1 = f1.resolution(); 119 | QSize r2 = f2.resolution(); 120 | return r1.height()*r1.width() < r2.height()*r2.width(); 121 | }); 122 | auto format = supportedFormats.last(); 123 | 124 | camera->setFocusMode(QCamera::FocusModeAuto); 125 | camera->setCameraFormat(format); 126 | return camera; 127 | } 128 | 129 | void SBarcodeScanner::setCaptured(const QString& captured) 130 | { 131 | m_captured = captured; 132 | emit capturedChanged(m_captured); 133 | } 134 | 135 | QString SBarcodeScanner::captured() const 136 | { 137 | return m_captured; 138 | } 139 | 140 | QRectF SBarcodeScanner::captureRect() const 141 | { 142 | return m_captureRect; 143 | } 144 | 145 | void SBarcodeScanner::setCaptureRect(const QRectF& captureRect) 146 | { 147 | if (captureRect == m_captureRect) { 148 | return; 149 | } 150 | 151 | m_captureRect = captureRect; 152 | sDebug() << "Capture Rectangle changed:" << m_captureRect; 153 | emit captureRectChanged(m_captureRect); 154 | } 155 | 156 | 157 | bool SBarcodeScanner::cameraAvailable() const 158 | { 159 | return m_cameraAvailable; 160 | } 161 | 162 | void SBarcodeScanner::setCamera(QCamera *newCamera) 163 | { 164 | if(m_camera == newCamera){ 165 | return; 166 | } 167 | // disconnect old camera if not already null 168 | if(m_camera) 169 | { 170 | m_camera->stop(); 171 | disconnect(m_camera,nullptr,this,nullptr); 172 | m_capture.setCamera(nullptr); 173 | if(m_camera->parent() == this) 174 | { 175 | delete m_camera; 176 | } 177 | m_camera = nullptr; 178 | } 179 | 180 | // connect new camera if not null 181 | if(newCamera) 182 | { 183 | auto format = newCamera->cameraFormat(); 184 | connect(newCamera,&QCamera::errorOccurred,this,[this](auto err,const auto& string){ 185 | errorOccured("Camera error:" + string); 186 | }); 187 | m_decoder.setResolution(format.resolution()); 188 | m_capture.setCamera(newCamera); 189 | m_camera = newCamera; 190 | m_camera->start(); 191 | } 192 | sDebug() << "New Camera set: " << m_camera 193 | << "\nFormat:\n" 194 | << " Pixel format:" << m_camera->cameraFormat().pixelFormat() << '\n' 195 | << " Resolution:" << m_camera->cameraFormat().resolution() << '\n' 196 | << " FPS:" << m_camera->cameraFormat().minFrameRate() << "-" << m_camera->cameraFormat().maxFrameRate(); 197 | 198 | emit cameraChanged(m_camera); 199 | } 200 | 201 | void SBarcodeScanner::setForwardVideoSink(QVideoSink *newSink) 202 | { 203 | if(m_forwardVideoSink == newSink){ 204 | return; 205 | } 206 | if(m_forwardVideoSink) 207 | { 208 | disconnect(this,nullptr,m_forwardVideoSink,nullptr); 209 | } 210 | if(newSink) 211 | { 212 | connect(this,&SBarcodeScanner::videoFrameChanged,newSink,&QVideoSink::setVideoFrame); 213 | } 214 | m_forwardVideoSink = newSink; 215 | forwardVideoSinkChanged(m_forwardVideoSink); 216 | } 217 | -------------------------------------------------------------------------------- /src/SBarcodeScanner.h: -------------------------------------------------------------------------------- 1 | #ifndef SBARCODESCANNER_H 2 | #define SBARCODESCANNER_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include "SBarcodeDecoder.h" 17 | /*! 18 | * \brief The SBarcodeScanner class processes the video input from Camera, 19 | */ 20 | class SBarcodeScanner : public QVideoSink, public QQmlParserStatus 21 | { 22 | Q_OBJECT 23 | Q_INTERFACES(QQmlParserStatus) 24 | QML_ELEMENT 25 | 26 | /// Set this property to the videosink that's supposed to do further processing on video frame. A VideoOutput.videosink for example, to show the video. 27 | Q_PROPERTY(QVideoSink* forwardVideoSink MEMBER m_forwardVideoSink WRITE setForwardVideoSink NOTIFY forwardVideoSinkChanged) 28 | /// This property controls wether the frames are passed along to the decoder or not (default true) 29 | Q_PROPERTY(bool scanning MEMBER m_scanning) 30 | /// Set this to the subsection of the frame that's acutally supposed to be scanned for qr code. In Normalized coordinates (0.0-1.0) 31 | Q_PROPERTY(QRectF captureRect READ captureRect WRITE setCaptureRect NOTIFY captureRectChanged) 32 | /// Set to true if camera property is set 33 | Q_PROPERTY(bool cameraAvailable READ cameraAvailable NOTIFY cameraAvailableChanged) 34 | /// Optional property if you want to set your own camera as an video input for scanning. Default video input is chosen by default. 35 | Q_PROPERTY(QCamera* camera MEMBER m_camera WRITE setCamera NOTIFY cameraChanged) 36 | 37 | public: 38 | explicit SBarcodeScanner(QObject *parent = nullptr); 39 | ~SBarcodeScanner() override; 40 | 41 | SBarcodeDecoder *getDecoder(); 42 | /*! 43 | * This function is called after all properties set in Qml instantiation have been assigned. 44 | * This allows us to, for example create default camera if none has been set by the user 45 | */ 46 | void componentComplete() override; 47 | /// This function does nothing and is here only to satisfy QQmlParserStatus interface 48 | void classBegin() override; 49 | 50 | 51 | 52 | QRectF captureRect() const; 53 | void setCaptureRect(const QRectF &captureRect); 54 | QString captured() const; 55 | bool cameraAvailable() const; 56 | void setCamera(QCamera *newCamera); 57 | void setForwardVideoSink(QVideoSink* sink); 58 | public slots: 59 | 60 | signals: 61 | void cameraChanged(QCamera *); 62 | 63 | /// This signal emitted for running process in a thread 64 | void process(const QImage &image); 65 | void forwardVideoSinkChanged(QVideoSink*); 66 | void captureRectChanged(const QRectF &captureRect); 67 | void capturedChanged(const QString &captured); 68 | void cameraAvailableChanged(); 69 | void errorOccured(const QString& errorString); 70 | protected: 71 | QCamera* makeDefaultCamera(); 72 | private: 73 | /// Decoder object, doing the actual Qr detection and conversion 74 | SBarcodeDecoder m_decoder; 75 | /// Camera object used to capture video, set automatically to device described by QMediaDevices::defaultVideoInput() 76 | QPointer m_camera; 77 | /// VideoSink to forward the captured frame to. Normally this should be VideoOutput.videoSink 78 | QPointer m_forwardVideoSink; 79 | /// Subsection of videoframe to capture, in normalized coordinates 80 | QRectF m_captureRect; 81 | /// Last captured string from QrCode 82 | QString m_captured = ""; 83 | /// QMediaCaptureSession instance to actually perform the camera recording 84 | QMediaCaptureSession m_capture; 85 | /// Separate thread for Qr code processing and detection 86 | QThread workerThread; 87 | /// Guard variable that prevents us from queueuing up the frames for processing 88 | QAtomicInteger m_frameProcessingInProgress=false; 89 | 90 | bool m_scanning = true; 91 | bool m_cameraAvailable = false; 92 | 93 | /*! 94 | * \fn void setCaptured(const QString &captured) 95 | * \brief Function for setting capture string 96 | * \param const QString &captured - captured string 97 | */ 98 | void setCaptured(const QString &captured); 99 | /// Try process captured frame, if previous frame is already processed - skip it 100 | void tryProcessFrame(const QVideoFrame &frame); 101 | 102 | /*! 103 | * \fn void setCameraAvailable(bool available) 104 | * \brief Function setting camera availability 105 | * \param bool available - camera availability status 106 | */ 107 | void setCameraAvailable(bool available); 108 | }; 109 | 110 | #endif // SBARCODESCANNER_H 111 | -------------------------------------------------------------------------------- /src/SCodes.pri: -------------------------------------------------------------------------------- 1 | QT += multimedia concurrent 2 | 3 | 4 | CONFIG += qmltypes 5 | QML_IMPORT_NAME = com.scythestudio.scodes 6 | QML_IMPORT_MAJOR_VERSION = 1 7 | 8 | INCLUDEPATH += \ 9 | $$PWD/ \ 10 | $$PWD/zxing-cpp/core/src/ \ 11 | 12 | 13 | equals(QT_MAJOR_VERSION, 6) { 14 | HEADERS += \ 15 | $$PWD/SBarcodeScanner.h 16 | 17 | SOURCES += \ 18 | $$PWD/SBarcodeScanner.cpp 19 | android { 20 | QT += gui-private 21 | } 22 | } 23 | 24 | equals(QT_MAJOR_VERSION, 5) { 25 | HEADERS += \ 26 | $$PWD/SBarcodeFilter.h 27 | 28 | SOURCES += \ 29 | $$PWD/SBarcodeFilter.cpp 30 | 31 | android { 32 | QT += androidextras 33 | } 34 | } 35 | 36 | HEADERS += \ 37 | $$PWD/SBarcodeDecoder.h \ 38 | $$PWD/SBarcodeFormat.h \ 39 | $$PWD/SBarcodeGenerator.h \ 40 | $$PWD/qvideoframeconversionhelper_p.h \ 41 | $$PWD/zxing-cpp/core/src/BarcodeFormat.h \ 42 | $$PWD/zxing-cpp/core/src/BinaryBitmap.h \ 43 | $$PWD/zxing-cpp/core/src/BitArray.h \ 44 | $$PWD/zxing-cpp/core/src/BitHacks.h \ 45 | $$PWD/zxing-cpp/core/src/BitMatrix.h \ 46 | $$PWD/zxing-cpp/core/src/BitMatrixCursor.h \ 47 | $$PWD/zxing-cpp/core/src/BitMatrixIO.h \ 48 | $$PWD/zxing-cpp/core/src/BitSource.h \ 49 | $$PWD/zxing-cpp/core/src/ByteArray.h \ 50 | $$PWD/zxing-cpp/core/src/ByteMatrix.h \ 51 | $$PWD/zxing-cpp/core/src/CharacterSet.h \ 52 | $$PWD/zxing-cpp/core/src/ConcentricFinder.h \ 53 | $$PWD/zxing-cpp/core/src/Content.h \ 54 | $$PWD/zxing-cpp/core/src/CustomData.h \ 55 | $$PWD/zxing-cpp/core/src/DecodeHints.h \ 56 | $$PWD/zxing-cpp/core/src/DecoderResult.h \ 57 | $$PWD/zxing-cpp/core/src/DetectorResult.h \ 58 | $$PWD/zxing-cpp/core/src/ECI.h \ 59 | $$PWD/zxing-cpp/core/src/Error.h \ 60 | $$PWD/zxing-cpp/core/src/Flags.h \ 61 | $$PWD/zxing-cpp/core/src/GTIN.h \ 62 | $$PWD/zxing-cpp/core/src/Generator.h \ 63 | $$PWD/zxing-cpp/core/src/GenericGF.h \ 64 | $$PWD/zxing-cpp/core/src/GenericGFPoly.h \ 65 | $$PWD/zxing-cpp/core/src/GlobalHistogramBinarizer.h \ 66 | $$PWD/zxing-cpp/core/src/GridSampler.h \ 67 | $$PWD/zxing-cpp/core/src/HRI.h \ 68 | $$PWD/zxing-cpp/core/src/HybridBinarizer.h \ 69 | $$PWD/zxing-cpp/core/src/ImageView.h \ 70 | $$PWD/zxing-cpp/core/src/LogMatrix.h \ 71 | $$PWD/zxing-cpp/core/src/Matrix.h \ 72 | $$PWD/zxing-cpp/core/src/MultiFormatReader.h \ 73 | $$PWD/zxing-cpp/core/src/MultiFormatWriter.h \ 74 | $$PWD/zxing-cpp/core/src/Pattern.h \ 75 | $$PWD/zxing-cpp/core/src/PerspectiveTransform.h \ 76 | $$PWD/zxing-cpp/core/src/Point.h \ 77 | $$PWD/zxing-cpp/core/src/Quadrilateral.h \ 78 | $$PWD/zxing-cpp/core/src/Range.h \ 79 | $$PWD/zxing-cpp/core/src/ReadBarcode.h \ 80 | $$PWD/zxing-cpp/core/src/Reader.h \ 81 | $$PWD/zxing-cpp/core/src/ReaderOptions.h \ 82 | $$PWD/zxing-cpp/core/src/ReedSolomonDecoder.h \ 83 | $$PWD/zxing-cpp/core/src/ReedSolomonEncoder.h \ 84 | $$PWD/zxing-cpp/core/src/RegressionLine.h \ 85 | $$PWD/zxing-cpp/core/src/Result.h \ 86 | $$PWD/zxing-cpp/core/src/ResultPoint.h \ 87 | $$PWD/zxing-cpp/core/src/Scope.h \ 88 | $$PWD/zxing-cpp/core/src/StructuredAppend.h \ 89 | $$PWD/zxing-cpp/core/src/TextDecoder.h \ 90 | $$PWD/zxing-cpp/core/src/TextEncoder.h \ 91 | $$PWD/zxing-cpp/core/src/TextUtfEncoding.h \ 92 | $$PWD/zxing-cpp/core/src/ThresholdBinarizer.h \ 93 | $$PWD/zxing-cpp/core/src/TritMatrix.h \ 94 | $$PWD/zxing-cpp/core/src/Utf.h \ 95 | $$PWD/zxing-cpp/core/src/WhiteRectDetector.h \ 96 | $$PWD/zxing-cpp/core/src/ZXAlgorithms.h \ 97 | $$PWD/zxing-cpp/core/src/ZXBigInteger.h \ 98 | $$PWD/zxing-cpp/core/src/ZXConfig.h \ 99 | $$PWD/zxing-cpp/core/src/ZXNullable.h \ 100 | $$PWD/zxing-cpp/core/src/ZXTestSupport.h \ 101 | $$PWD/zxing-cpp/core/src/aztec/AZDecoder.h \ 102 | $$PWD/zxing-cpp/core/src/aztec/AZDetector.h \ 103 | $$PWD/zxing-cpp/core/src/aztec/AZDetectorResult.h \ 104 | $$PWD/zxing-cpp/core/src/aztec/AZEncoder.h \ 105 | $$PWD/zxing-cpp/core/src/aztec/AZEncodingState.h \ 106 | $$PWD/zxing-cpp/core/src/aztec/AZHighLevelEncoder.h \ 107 | $$PWD/zxing-cpp/core/src/aztec/AZReader.h \ 108 | $$PWD/zxing-cpp/core/src/aztec/AZToken.h \ 109 | $$PWD/zxing-cpp/core/src/aztec/AZWriter.h \ 110 | $$PWD/zxing-cpp/core/src/datamatrix/DMBitLayout.h \ 111 | $$PWD/zxing-cpp/core/src/datamatrix/DMDataBlock.h \ 112 | $$PWD/zxing-cpp/core/src/datamatrix/DMDecoder.h \ 113 | $$PWD/zxing-cpp/core/src/datamatrix/DMDetector.h \ 114 | $$PWD/zxing-cpp/core/src/datamatrix/DMECEncoder.h \ 115 | $$PWD/zxing-cpp/core/src/datamatrix/DMEncoderContext.h \ 116 | $$PWD/zxing-cpp/core/src/datamatrix/DMHighLevelEncoder.h \ 117 | $$PWD/zxing-cpp/core/src/datamatrix/DMReader.h \ 118 | $$PWD/zxing-cpp/core/src/datamatrix/DMSymbolInfo.h \ 119 | $$PWD/zxing-cpp/core/src/datamatrix/DMSymbolShape.h \ 120 | $$PWD/zxing-cpp/core/src/datamatrix/DMVersion.h \ 121 | $$PWD/zxing-cpp/core/src/datamatrix/DMWriter.h \ 122 | $$PWD/zxing-cpp/core/src/libzueci/zueci.h \ 123 | $$PWD/zxing-cpp/core/src/libzueci/zueci_big5.h \ 124 | $$PWD/zxing-cpp/core/src/libzueci/zueci_common.h \ 125 | $$PWD/zxing-cpp/core/src/libzueci/zueci_gb18030.h \ 126 | $$PWD/zxing-cpp/core/src/libzueci/zueci_gb2312.h \ 127 | $$PWD/zxing-cpp/core/src/libzueci/zueci_gbk.h \ 128 | $$PWD/zxing-cpp/core/src/libzueci/zueci_ksx1001.h \ 129 | $$PWD/zxing-cpp/core/src/libzueci/zueci_sb.h \ 130 | $$PWD/zxing-cpp/core/src/libzueci/zueci_sjis.h \ 131 | $$PWD/zxing-cpp/core/src/maxicode/MCBitMatrixParser.h \ 132 | $$PWD/zxing-cpp/core/src/maxicode/MCDecoder.h \ 133 | $$PWD/zxing-cpp/core/src/maxicode/MCReader.h \ 134 | $$PWD/zxing-cpp/core/src/oned/ODCodabarReader.h \ 135 | $$PWD/zxing-cpp/core/src/oned/ODCodabarWriter.h \ 136 | $$PWD/zxing-cpp/core/src/oned/ODCode128Patterns.h \ 137 | $$PWD/zxing-cpp/core/src/oned/ODCode128Reader.h \ 138 | $$PWD/zxing-cpp/core/src/oned/ODCode128Writer.h \ 139 | $$PWD/zxing-cpp/core/src/oned/ODCode39Reader.h \ 140 | $$PWD/zxing-cpp/core/src/oned/ODCode39Writer.h \ 141 | $$PWD/zxing-cpp/core/src/oned/ODCode93Reader.h \ 142 | $$PWD/zxing-cpp/core/src/oned/ODCode93Writer.h \ 143 | $$PWD/zxing-cpp/core/src/oned/ODDXFilmEdgeReader.h \ 144 | $$PWD/zxing-cpp/core/src/oned/ODDataBarCommon.h \ 145 | $$PWD/zxing-cpp/core/src/oned/ODDataBarExpandedBitDecoder.h \ 146 | $$PWD/zxing-cpp/core/src/oned/ODDataBarExpandedReader.h \ 147 | $$PWD/zxing-cpp/core/src/oned/ODDataBarReader.h \ 148 | $$PWD/zxing-cpp/core/src/oned/ODEAN13Writer.h \ 149 | $$PWD/zxing-cpp/core/src/oned/ODEAN8Writer.h \ 150 | $$PWD/zxing-cpp/core/src/oned/ODITFReader.h \ 151 | $$PWD/zxing-cpp/core/src/oned/ODITFWriter.h \ 152 | $$PWD/zxing-cpp/core/src/oned/ODMultiUPCEANReader.h \ 153 | $$PWD/zxing-cpp/core/src/oned/ODReader.h \ 154 | $$PWD/zxing-cpp/core/src/oned/ODRowReader.h \ 155 | $$PWD/zxing-cpp/core/src/oned/ODUPCAWriter.h \ 156 | $$PWD/zxing-cpp/core/src/oned/ODUPCEANCommon.h \ 157 | $$PWD/zxing-cpp/core/src/oned/ODUPCEWriter.h \ 158 | $$PWD/zxing-cpp/core/src/oned/ODWriterHelper.h \ 159 | $$PWD/zxing-cpp/core/src/pdf417/PDFBarcodeMetadata.h \ 160 | $$PWD/zxing-cpp/core/src/pdf417/PDFBarcodeValue.h \ 161 | $$PWD/zxing-cpp/core/src/pdf417/PDFBoundingBox.h \ 162 | $$PWD/zxing-cpp/core/src/pdf417/PDFCodeword.h \ 163 | $$PWD/zxing-cpp/core/src/pdf417/PDFCodewordDecoder.h \ 164 | $$PWD/zxing-cpp/core/src/pdf417/PDFCompaction.h \ 165 | $$PWD/zxing-cpp/core/src/pdf417/PDFDecoder.h \ 166 | $$PWD/zxing-cpp/core/src/pdf417/PDFDecoderResultExtra.h \ 167 | $$PWD/zxing-cpp/core/src/pdf417/PDFDetectionResult.h \ 168 | $$PWD/zxing-cpp/core/src/pdf417/PDFDetectionResultColumn.h \ 169 | $$PWD/zxing-cpp/core/src/pdf417/PDFDetector.h \ 170 | $$PWD/zxing-cpp/core/src/pdf417/PDFEncoder.h \ 171 | $$PWD/zxing-cpp/core/src/pdf417/PDFHighLevelEncoder.h \ 172 | $$PWD/zxing-cpp/core/src/pdf417/PDFModulusGF.h \ 173 | $$PWD/zxing-cpp/core/src/pdf417/PDFModulusPoly.h \ 174 | $$PWD/zxing-cpp/core/src/pdf417/PDFReader.h \ 175 | $$PWD/zxing-cpp/core/src/pdf417/PDFScanningDecoder.h \ 176 | $$PWD/zxing-cpp/core/src/pdf417/PDFWriter.h \ 177 | $$PWD/zxing-cpp/core/src/qrcode/QRBitMatrixParser.h \ 178 | $$PWD/zxing-cpp/core/src/qrcode/QRCodecMode.h \ 179 | $$PWD/zxing-cpp/core/src/qrcode/QRDataBlock.h \ 180 | $$PWD/zxing-cpp/core/src/qrcode/QRDataMask.h \ 181 | $$PWD/zxing-cpp/core/src/qrcode/QRDecoder.h \ 182 | $$PWD/zxing-cpp/core/src/qrcode/QRDetector.h \ 183 | $$PWD/zxing-cpp/core/src/qrcode/QRECB.h \ 184 | $$PWD/zxing-cpp/core/src/qrcode/QREncodeResult.h \ 185 | $$PWD/zxing-cpp/core/src/qrcode/QREncoder.h \ 186 | $$PWD/zxing-cpp/core/src/qrcode/QRErrorCorrectionLevel.h \ 187 | $$PWD/zxing-cpp/core/src/qrcode/QRFormatInformation.h \ 188 | $$PWD/zxing-cpp/core/src/qrcode/QRMaskUtil.h \ 189 | $$PWD/zxing-cpp/core/src/qrcode/QRMatrixUtil.h \ 190 | $$PWD/zxing-cpp/core/src/qrcode/QRReader.h \ 191 | $$PWD/zxing-cpp/core/src/qrcode/QRVersion.h \ 192 | $$PWD/zxing-cpp/core/src/qrcode/QRWriter.h 193 | 194 | SOURCES += \ 195 | $$PWD/SBarcodeDecoder.cpp \ 196 | $$PWD/SBarcodeFormat.cpp \ 197 | $$PWD/SBarcodeGenerator.cpp \ 198 | $$PWD/zxing-cpp/core/src/BarcodeFormat.cpp \ 199 | $$PWD/zxing-cpp/core/src/BinaryBitmap.cpp \ 200 | $$PWD/zxing-cpp/core/src/BitArray.cpp \ 201 | $$PWD/zxing-cpp/core/src/BitMatrix.cpp \ 202 | $$PWD/zxing-cpp/core/src/BitMatrixIO.cpp \ 203 | $$PWD/zxing-cpp/core/src/BitSource.cpp \ 204 | $$PWD/zxing-cpp/core/src/CharacterSet.cpp \ 205 | $$PWD/zxing-cpp/core/src/ConcentricFinder.cpp \ 206 | $$PWD/zxing-cpp/core/src/Content.cpp \ 207 | $$PWD/zxing-cpp/core/src/DecodeHints.cpp \ 208 | $$PWD/zxing-cpp/core/src/ECI.cpp \ 209 | $$PWD/zxing-cpp/core/src/GTIN.cpp \ 210 | $$PWD/zxing-cpp/core/src/GenericGF.cpp \ 211 | $$PWD/zxing-cpp/core/src/GenericGFPoly.cpp \ 212 | $$PWD/zxing-cpp/core/src/GlobalHistogramBinarizer.cpp \ 213 | $$PWD/zxing-cpp/core/src/GridSampler.cpp \ 214 | $$PWD/zxing-cpp/core/src/HRI.cpp \ 215 | $$PWD/zxing-cpp/core/src/HybridBinarizer.cpp \ 216 | $$PWD/zxing-cpp/core/src/MultiFormatReader.cpp \ 217 | $$PWD/zxing-cpp/core/src/MultiFormatWriter.cpp \ 218 | $$PWD/zxing-cpp/core/src/PerspectiveTransform.cpp \ 219 | $$PWD/zxing-cpp/core/src/ReadBarcode.cpp \ 220 | $$PWD/zxing-cpp/core/src/ReedSolomonDecoder.cpp \ 221 | $$PWD/zxing-cpp/core/src/ReedSolomonEncoder.cpp \ 222 | $$PWD/zxing-cpp/core/src/Result.cpp \ 223 | $$PWD/zxing-cpp/core/src/ResultPoint.cpp \ 224 | $$PWD/zxing-cpp/core/src/TextDecoder.cpp \ 225 | $$PWD/zxing-cpp/core/src/TextEncoder.cpp \ 226 | $$PWD/zxing-cpp/core/src/TextUtfEncoding.cpp \ 227 | $$PWD/zxing-cpp/core/src/Utf.cpp \ 228 | $$PWD/zxing-cpp/core/src/WhiteRectDetector.cpp \ 229 | $$PWD/zxing-cpp/core/src/ZXBigInteger.cpp \ 230 | $$PWD/zxing-cpp/core/src/aztec/AZDecoder.cpp \ 231 | $$PWD/zxing-cpp/core/src/aztec/AZDetector.cpp \ 232 | $$PWD/zxing-cpp/core/src/aztec/AZEncoder.cpp \ 233 | $$PWD/zxing-cpp/core/src/aztec/AZHighLevelEncoder.cpp \ 234 | $$PWD/zxing-cpp/core/src/aztec/AZReader.cpp \ 235 | $$PWD/zxing-cpp/core/src/aztec/AZToken.cpp \ 236 | $$PWD/zxing-cpp/core/src/aztec/AZWriter.cpp \ 237 | $$PWD/zxing-cpp/core/src/datamatrix/DMBitLayout.cpp \ 238 | $$PWD/zxing-cpp/core/src/datamatrix/DMDataBlock.cpp \ 239 | $$PWD/zxing-cpp/core/src/datamatrix/DMDecoder.cpp \ 240 | $$PWD/zxing-cpp/core/src/datamatrix/DMDetector.cpp \ 241 | $$PWD/zxing-cpp/core/src/datamatrix/DMECEncoder.cpp \ 242 | $$PWD/zxing-cpp/core/src/datamatrix/DMHighLevelEncoder.cpp \ 243 | $$PWD/zxing-cpp/core/src/datamatrix/DMReader.cpp \ 244 | $$PWD/zxing-cpp/core/src/datamatrix/DMSymbolInfo.cpp \ 245 | $$PWD/zxing-cpp/core/src/datamatrix/DMVersion.cpp \ 246 | $$PWD/zxing-cpp/core/src/datamatrix/DMWriter.cpp \ 247 | $$PWD/zxing-cpp/core/src/libzueci/zueci.c \ 248 | $$PWD/zxing-cpp/core/src/maxicode/MCBitMatrixParser.cpp \ 249 | $$PWD/zxing-cpp/core/src/maxicode/MCDecoder.cpp \ 250 | $$PWD/zxing-cpp/core/src/maxicode/MCReader.cpp \ 251 | $$PWD/zxing-cpp/core/src/oned/ODCodabarReader.cpp \ 252 | $$PWD/zxing-cpp/core/src/oned/ODCodabarWriter.cpp \ 253 | $$PWD/zxing-cpp/core/src/oned/ODCode128Patterns.cpp \ 254 | $$PWD/zxing-cpp/core/src/oned/ODCode128Reader.cpp \ 255 | $$PWD/zxing-cpp/core/src/oned/ODCode128Writer.cpp \ 256 | $$PWD/zxing-cpp/core/src/oned/ODCode39Reader.cpp \ 257 | $$PWD/zxing-cpp/core/src/oned/ODCode39Writer.cpp \ 258 | $$PWD/zxing-cpp/core/src/oned/ODCode93Reader.cpp \ 259 | $$PWD/zxing-cpp/core/src/oned/ODCode93Writer.cpp \ 260 | $$PWD/zxing-cpp/core/src/oned/ODDXFilmEdgeReader.cpp \ 261 | $$PWD/zxing-cpp/core/src/oned/ODDataBarCommon.cpp \ 262 | $$PWD/zxing-cpp/core/src/oned/ODDataBarExpandedBitDecoder.cpp \ 263 | $$PWD/zxing-cpp/core/src/oned/ODDataBarExpandedReader.cpp \ 264 | $$PWD/zxing-cpp/core/src/oned/ODDataBarReader.cpp \ 265 | $$PWD/zxing-cpp/core/src/oned/ODEAN13Writer.cpp \ 266 | $$PWD/zxing-cpp/core/src/oned/ODEAN8Writer.cpp \ 267 | $$PWD/zxing-cpp/core/src/oned/ODITFReader.cpp \ 268 | $$PWD/zxing-cpp/core/src/oned/ODITFWriter.cpp \ 269 | $$PWD/zxing-cpp/core/src/oned/ODMultiUPCEANReader.cpp \ 270 | $$PWD/zxing-cpp/core/src/oned/ODReader.cpp \ 271 | $$PWD/zxing-cpp/core/src/oned/ODRowReader.cpp \ 272 | $$PWD/zxing-cpp/core/src/oned/ODUPCAWriter.cpp \ 273 | $$PWD/zxing-cpp/core/src/oned/ODUPCEANCommon.cpp \ 274 | $$PWD/zxing-cpp/core/src/oned/ODUPCEWriter.cpp \ 275 | $$PWD/zxing-cpp/core/src/oned/ODWriterHelper.cpp \ 276 | $$PWD/zxing-cpp/core/src/pdf417/PDFBarcodeValue.cpp \ 277 | $$PWD/zxing-cpp/core/src/pdf417/PDFBoundingBox.cpp \ 278 | $$PWD/zxing-cpp/core/src/pdf417/PDFCodewordDecoder.cpp \ 279 | $$PWD/zxing-cpp/core/src/pdf417/PDFDecoder.cpp \ 280 | $$PWD/zxing-cpp/core/src/pdf417/PDFDetectionResult.cpp \ 281 | $$PWD/zxing-cpp/core/src/pdf417/PDFDetectionResultColumn.cpp \ 282 | $$PWD/zxing-cpp/core/src/pdf417/PDFDetector.cpp \ 283 | $$PWD/zxing-cpp/core/src/pdf417/PDFEncoder.cpp \ 284 | $$PWD/zxing-cpp/core/src/pdf417/PDFHighLevelEncoder.cpp \ 285 | $$PWD/zxing-cpp/core/src/pdf417/PDFModulusGF.cpp \ 286 | $$PWD/zxing-cpp/core/src/pdf417/PDFModulusPoly.cpp \ 287 | $$PWD/zxing-cpp/core/src/pdf417/PDFReader.cpp \ 288 | $$PWD/zxing-cpp/core/src/pdf417/PDFScanningDecoder.cpp \ 289 | $$PWD/zxing-cpp/core/src/pdf417/PDFWriter.cpp \ 290 | $$PWD/zxing-cpp/core/src/qrcode/QRBitMatrixParser.cpp \ 291 | $$PWD/zxing-cpp/core/src/qrcode/QRCodecMode.cpp \ 292 | $$PWD/zxing-cpp/core/src/qrcode/QRDataBlock.cpp \ 293 | $$PWD/zxing-cpp/core/src/qrcode/QRDecoder.cpp \ 294 | $$PWD/zxing-cpp/core/src/qrcode/QRDetector.cpp \ 295 | $$PWD/zxing-cpp/core/src/qrcode/QREncoder.cpp \ 296 | $$PWD/zxing-cpp/core/src/qrcode/QRErrorCorrectionLevel.cpp \ 297 | $$PWD/zxing-cpp/core/src/qrcode/QRFormatInformation.cpp \ 298 | $$PWD/zxing-cpp/core/src/qrcode/QRMaskUtil.cpp \ 299 | $$PWD/zxing-cpp/core/src/qrcode/QRMatrixUtil.cpp \ 300 | $$PWD/zxing-cpp/core/src/qrcode/QRReader.cpp \ 301 | $$PWD/zxing-cpp/core/src/qrcode/QRVersion.cpp \ 302 | $$PWD/zxing-cpp/core/src/qrcode/QRWriter.cpp 303 | -------------------------------------------------------------------------------- /src/private/debug.h: -------------------------------------------------------------------------------- 1 | /*! 2 | * This file contains simple debug print definitions that allow for turning on/off debug print in the SCodes library by 3 | * adding SCODE_DEBUG in compile definitions 4 | */ 5 | #ifndef DEBUG_H 6 | #define DEBUG_H 7 | #include 8 | #ifdef SCODES_DEBUG 9 | #include 10 | #define sDebug QMessageLogger(QT_MESSAGELOG_FILE, QT_MESSAGELOG_LINE, QT_MESSAGELOG_FUNC).debug 11 | namespace SCodes { 12 | struct TimeMeasure { 13 | const char *fname, *id; 14 | std::chrono::high_resolution_clock::time_point start; 15 | TimeMeasure(const char* fname, const char* id) : fname{fname}, id{id}, start{std::chrono::high_resolution_clock::now()} {}; 16 | ~TimeMeasure(){ 17 | auto end = std::chrono::high_resolution_clock::now(); 18 | auto time = std::chrono::duration(end-start); 19 | sDebug() << fname << " / " << id << "took: " << time.count() << " ms"; 20 | } 21 | }; 22 | } 23 | 24 | #define SCODES_MEASURE(x) SCodes::TimeMeasure x (__FUNCTION__, #x) 25 | #else 26 | #define sDebug while (false) QMessageLogger().noDebug 27 | #define SCODES_MEASURE(x) ((void)0) 28 | #endif 29 | 30 | #endif // DEBUG_H 31 | -------------------------------------------------------------------------------- /src/qvideoframeconversionhelper_p.h: -------------------------------------------------------------------------------- 1 | /**************************************************************************** 2 | ** 3 | ** Copyright (C) 2016 The Qt Company Ltd. 4 | ** Contact: https://www.qt.io/licensing/ 5 | ** 6 | ** This file is part of the Qt Toolkit. 7 | ** 8 | ** $QT_BEGIN_LICENSE:LGPL$ 9 | ** Commercial License Usage 10 | ** Licensees holding valid commercial Qt licenses may use this file in 11 | ** accordance with the commercial license agreement provided with the 12 | ** Software or, alternatively, in accordance with the terms contained in 13 | ** a written agreement between you and The Qt Company. For licensing terms 14 | ** and conditions see https://www.qt.io/terms-conditions. For further 15 | ** information use the contact form at https://www.qt.io/contact-us. 16 | ** 17 | ** GNU Lesser General Public License Usage 18 | ** Alternatively, this file may be used under the terms of the GNU Lesser 19 | ** General Public License version 3 as published by the Free Software 20 | ** Foundation and appearing in the file LICENSE.LGPL3 included in the 21 | ** packaging of this file. Please review the following information to 22 | ** ensure the GNU Lesser General Public License version 3 requirements 23 | ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. 24 | ** 25 | ** GNU General Public License Usage 26 | ** Alternatively, this file may be used under the terms of the GNU 27 | ** General Public License version 2.0 or (at your option) the GNU General 28 | ** Public license version 3 or any later version approved by the KDE Free 29 | ** Qt Foundation. The licenses are as published by the Free Software 30 | ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 31 | ** included in the packaging of this file. Please review the following 32 | ** information to ensure the GNU General Public License requirements will 33 | ** be met: https://www.gnu.org/licenses/gpl-2.0.html and 34 | ** https://www.gnu.org/licenses/gpl-3.0.html. 35 | ** 36 | ** $QT_END_LICENSE$ 37 | ** 38 | ****************************************************************************/ 39 | 40 | #ifndef QVIDEOFRAMECONVERSIONHELPER_P_H 41 | #define QVIDEOFRAMECONVERSIONHELPER_P_H 42 | 43 | // 44 | // W A R N I N G 45 | // ------------- 46 | // 47 | // This file is not part of the Qt API. It exists purely as an 48 | // implementation detail. This header file may change from version to 49 | // version without notice, or even be removed. 50 | // 51 | // We mean it. 52 | // 53 | 54 | #include 55 | // #include 56 | 57 | 58 | #define FETCH_INFO_PACKED(frame) \ 59 | const uchar *src = frame.bits(); \ 60 | int stride = frame.bytesPerLine(); \ 61 | int width = frame.width(); \ 62 | int height = frame.height(); 63 | 64 | #define FETCH_INFO_BIPLANAR(frame) \ 65 | const uchar *plane1 = frame.bits(0); \ 66 | const uchar *plane2 = frame.bits(1); \ 67 | int plane1Stride = frame.bytesPerLine(0); \ 68 | int plane2Stride = frame.bytesPerLine(1); \ 69 | int width = frame.width(); \ 70 | int height = frame.height(); 71 | 72 | #define FETCH_INFO_TRIPLANAR(frame) \ 73 | const uchar *plane1 = frame.bits(0); \ 74 | const uchar *plane2 = frame.bits(1); \ 75 | const uchar *plane3 = frame.bits(2); \ 76 | int plane1Stride = frame.bytesPerLine(0); \ 77 | int plane2Stride = frame.bytesPerLine(1); \ 78 | int plane3Stride = frame.bytesPerLine(2); \ 79 | int width = frame.width(); \ 80 | int height = frame.height(); \ 81 | 82 | #define MERGE_LOOPS(width, height, stride, bpp) \ 83 | if (stride == width * bpp) { \ 84 | width *= height; \ 85 | height = 1; \ 86 | stride = 0; \ 87 | } 88 | 89 | #define ALIGN(boundary, ptr, x, length) \ 90 | for (; ((reinterpret_cast(ptr) & (boundary - 1)) != 0) && x < length; ++x) 91 | 92 | #define CLAMP(n) (n > 255 ? 255 : (n < 0 ? 0 : n)) 93 | 94 | #define EXPAND_UV(u, v) \ 95 | int uu = u - 128; \ 96 | int vv = v - 128; \ 97 | int rv = 409 * vv + 128; \ 98 | int guv = 100 * uu + 208 * vv + 128; \ 99 | int bu = 516 * uu + 128; \ 100 | 101 | 102 | typedef void (QT_FASTCALL *VideoFrameConvertFunc)(const QVideoFrame &frame, uchar *output); 103 | 104 | inline quint32 qConvertBGRA32ToARGB32(quint32 bgra) 105 | { 106 | return (((bgra & 0xFF000000) >> 24) 107 | | ((bgra & 0x00FF0000) >> 8) 108 | | ((bgra & 0x0000FF00) << 8) 109 | | ((bgra & 0x000000FF) << 24)); 110 | } 111 | 112 | inline quint32 qConvertBGR24ToARGB32(const uchar *bgr) 113 | { 114 | return 0xFF000000 | bgr[0] | bgr[1] << 8 | bgr[2] << 16; 115 | } 116 | 117 | inline quint32 qConvertBGR565ToARGB32(quint16 bgr) 118 | { 119 | return 0xff000000 120 | | ((((bgr) >> 8) & 0xf8) | (((bgr) >> 13) & 0x7)) 121 | | ((((bgr) << 5) & 0xfc00) | (((bgr) >> 1) & 0x300)) 122 | | ((((bgr) << 19) & 0xf80000) | (((bgr) << 14) & 0x70000)); 123 | } 124 | 125 | inline quint32 qConvertBGR555ToARGB32(quint16 bgr) 126 | { 127 | return 0xff000000 128 | | ((((bgr) >> 7) & 0xf8) | (((bgr) >> 12) & 0x7)) 129 | | ((((bgr) << 6) & 0xf800) | (((bgr) << 1) & 0x700)) 130 | | ((((bgr) << 19) & 0xf80000) | (((bgr) << 11) & 0x70000)); 131 | } 132 | 133 | static inline quint32 qYUVToARGB32(int y, int rv, int guv, int bu, int a = 0xff) 134 | { 135 | int yy = (y - 16) * 298; 136 | 137 | return (a << 24) 138 | | CLAMP((yy + rv) >> 8) << 16 139 | | CLAMP((yy - guv) >> 8) << 8 140 | | CLAMP((yy + bu) >> 8); 141 | } 142 | 143 | static inline void planarYUV420_to_ARGB32(const uchar *y, int yStride, 144 | const uchar *u, int uStride, 145 | const uchar *v, int vStride, 146 | int uvPixelStride, 147 | quint32 *rgb, 148 | int width, int height) 149 | { 150 | quint32 *rgb0 = rgb; 151 | quint32 *rgb1 = rgb + width; 152 | 153 | for (int j = 0; j < height; j += 2) { 154 | const uchar *lineY0 = y; 155 | const uchar *lineY1 = y + yStride; 156 | const uchar *lineU = u; 157 | const uchar *lineV = v; 158 | 159 | for (int i = 0; i < width; i += 2) { 160 | EXPAND_UV(*lineU, *lineV); 161 | lineU += uvPixelStride; 162 | lineV += uvPixelStride; 163 | 164 | *rgb0++ = qYUVToARGB32(*lineY0++, rv, guv, bu); 165 | *rgb0++ = qYUVToARGB32(*lineY0++, rv, guv, bu); 166 | *rgb1++ = qYUVToARGB32(*lineY1++, rv, guv, bu); 167 | *rgb1++ = qYUVToARGB32(*lineY1++, rv, guv, bu); 168 | } 169 | 170 | y += yStride << 1; // stride * 2 171 | u += uStride; 172 | v += vStride; 173 | rgb0 += width; 174 | rgb1 += width; 175 | } 176 | } 177 | 178 | void QT_FASTCALL qt_convert_YUV420P_to_ARGB32(const QVideoFrame &frame, uchar *output) 179 | { 180 | FETCH_INFO_TRIPLANAR(frame) 181 | planarYUV420_to_ARGB32(plane1, plane1Stride, 182 | plane2, plane2Stride, 183 | plane3, plane3Stride, 184 | 1, 185 | reinterpret_cast(output), 186 | width, height); 187 | } 188 | 189 | void QT_FASTCALL qt_convert_YV12_to_ARGB32(const QVideoFrame &frame, uchar *output) 190 | { 191 | FETCH_INFO_TRIPLANAR(frame) 192 | planarYUV420_to_ARGB32(plane1, plane1Stride, 193 | plane3, plane3Stride, 194 | plane2, plane2Stride, 195 | 1, 196 | reinterpret_cast(output), 197 | width, height); 198 | } 199 | 200 | void QT_FASTCALL qt_convert_AYUV444_to_ARGB32(const QVideoFrame &frame, uchar *output) 201 | { 202 | FETCH_INFO_PACKED(frame) 203 | MERGE_LOOPS(width, height, stride, 4) 204 | 205 | quint32 *rgb = reinterpret_cast(output); 206 | 207 | for (int i = 0; i < height; ++i) { 208 | const uchar *lineSrc = src; 209 | 210 | for (int j = 0; j < width; ++j) { 211 | int a = *lineSrc++; 212 | int y = *lineSrc++; 213 | int u = *lineSrc++; 214 | int v = *lineSrc++; 215 | 216 | EXPAND_UV(u, v); 217 | 218 | *rgb++ = qYUVToARGB32(y, rv, guv, bu, a); 219 | } 220 | 221 | src += stride; 222 | } 223 | } 224 | 225 | void QT_FASTCALL qt_convert_YUV444_to_ARGB32(const QVideoFrame &frame, uchar *output) 226 | { 227 | FETCH_INFO_PACKED(frame) 228 | MERGE_LOOPS(width, height, stride, 3) 229 | 230 | quint32 *rgb = reinterpret_cast(output); 231 | 232 | for (int i = 0; i < height; ++i) { 233 | const uchar *lineSrc = src; 234 | 235 | for (int j = 0; j < width; ++j) { 236 | int y = *lineSrc++; 237 | int u = *lineSrc++; 238 | int v = *lineSrc++; 239 | 240 | EXPAND_UV(u, v); 241 | 242 | *rgb++ = qYUVToARGB32(y, rv, guv, bu); 243 | } 244 | 245 | src += stride; 246 | } 247 | } 248 | 249 | void QT_FASTCALL qt_convert_UYVY_to_ARGB32(const QVideoFrame &frame, uchar *output) 250 | { 251 | FETCH_INFO_PACKED(frame) 252 | MERGE_LOOPS(width, height, stride, 2) 253 | 254 | quint32 *rgb = reinterpret_cast(output); 255 | 256 | for (int i = 0; i < height; ++i) { 257 | const uchar *lineSrc = src; 258 | 259 | for (int j = 0; j < width; j += 2) { 260 | int u = *lineSrc++; 261 | int y0 = *lineSrc++; 262 | int v = *lineSrc++; 263 | int y1 = *lineSrc++; 264 | 265 | EXPAND_UV(u, v); 266 | 267 | *rgb++ = qYUVToARGB32(y0, rv, guv, bu); 268 | *rgb++ = qYUVToARGB32(y1, rv, guv, bu); 269 | } 270 | 271 | src += stride; 272 | } 273 | } 274 | 275 | void QT_FASTCALL qt_convert_YUYV_to_ARGB32(const QVideoFrame &frame, uchar *output) 276 | { 277 | FETCH_INFO_PACKED(frame) 278 | MERGE_LOOPS(width, height, stride, 2) 279 | 280 | quint32 *rgb = reinterpret_cast(output); 281 | 282 | for (int i = 0; i < height; ++i) { 283 | const uchar *lineSrc = src; 284 | 285 | for (int j = 0; j < width; j += 2) { 286 | int y0 = *lineSrc++; 287 | int u = *lineSrc++; 288 | int y1 = *lineSrc++; 289 | int v = *lineSrc++; 290 | 291 | EXPAND_UV(u, v); 292 | 293 | *rgb++ = qYUVToARGB32(y0, rv, guv, bu); 294 | *rgb++ = qYUVToARGB32(y1, rv, guv, bu); 295 | } 296 | 297 | src += stride; 298 | } 299 | } 300 | 301 | void QT_FASTCALL qt_convert_NV12_to_ARGB32(const QVideoFrame &frame, uchar *output) 302 | { 303 | FETCH_INFO_BIPLANAR(frame) 304 | planarYUV420_to_ARGB32(plane1, plane1Stride, 305 | plane2, plane2Stride, 306 | plane2 + 1, plane2Stride, 307 | 2, 308 | reinterpret_cast(output), 309 | width, height); 310 | } 311 | 312 | void QT_FASTCALL qt_convert_NV21_to_ARGB32(const QVideoFrame &frame, uchar *output) 313 | { 314 | FETCH_INFO_BIPLANAR(frame) 315 | planarYUV420_to_ARGB32(plane1, plane1Stride, 316 | plane2 + 1, plane2Stride, 317 | plane2, plane2Stride, 318 | 2, 319 | reinterpret_cast(output), 320 | width, height); 321 | } 322 | 323 | void QT_FASTCALL qt_convert_BGRA32_to_ARGB32(const QVideoFrame &frame, uchar *output) 324 | { 325 | FETCH_INFO_PACKED(frame) 326 | MERGE_LOOPS(width, height, stride, 4) 327 | 328 | quint32 *argb = reinterpret_cast(output); 329 | 330 | for (int y = 0; y < height; ++y) { 331 | const quint32 *bgra = reinterpret_cast(src); 332 | 333 | int x = 0; 334 | for (; x < width - 3; x += 4) { 335 | *argb++ = qConvertBGRA32ToARGB32(*bgra++); 336 | *argb++ = qConvertBGRA32ToARGB32(*bgra++); 337 | *argb++ = qConvertBGRA32ToARGB32(*bgra++); 338 | *argb++ = qConvertBGRA32ToARGB32(*bgra++); 339 | } 340 | 341 | // leftovers 342 | for (; x < width; ++x) 343 | *argb++ = qConvertBGRA32ToARGB32(*bgra++); 344 | 345 | src += stride; 346 | } 347 | } 348 | 349 | void QT_FASTCALL qt_convert_BGR24_to_ARGB32(const QVideoFrame &frame, uchar *output) 350 | { 351 | FETCH_INFO_PACKED(frame) 352 | MERGE_LOOPS(width, height, stride, 3) 353 | 354 | quint32 *argb = reinterpret_cast(output); 355 | 356 | for (int y = 0; y < height; ++y) { 357 | const uchar *bgr = src; 358 | 359 | int x = 0; 360 | for (; x < width - 3; x += 4) { 361 | *argb++ = qConvertBGR24ToARGB32(bgr); 362 | bgr += 3; 363 | *argb++ = qConvertBGR24ToARGB32(bgr); 364 | bgr += 3; 365 | *argb++ = qConvertBGR24ToARGB32(bgr); 366 | bgr += 3; 367 | *argb++ = qConvertBGR24ToARGB32(bgr); 368 | bgr += 3; 369 | } 370 | 371 | // leftovers 372 | for (; x < width; ++x) { 373 | *argb++ = qConvertBGR24ToARGB32(bgr); 374 | bgr += 3; 375 | } 376 | 377 | src += stride; 378 | } 379 | } 380 | 381 | void QT_FASTCALL qt_convert_BGR565_to_ARGB32(const QVideoFrame &frame, uchar *output) 382 | { 383 | FETCH_INFO_PACKED(frame) 384 | MERGE_LOOPS(width, height, stride, 2) 385 | 386 | quint32 *argb = reinterpret_cast(output); 387 | 388 | for (int y = 0; y < height; ++y) { 389 | const quint16 *bgr = reinterpret_cast(src); 390 | 391 | int x = 0; 392 | for (; x < width - 3; x += 4) { 393 | *argb++ = qConvertBGR565ToARGB32(*bgr++); 394 | *argb++ = qConvertBGR565ToARGB32(*bgr++); 395 | *argb++ = qConvertBGR565ToARGB32(*bgr++); 396 | *argb++ = qConvertBGR565ToARGB32(*bgr++); 397 | } 398 | 399 | // leftovers 400 | for (; x < width; ++x) 401 | *argb++ = qConvertBGR565ToARGB32(*bgr++); 402 | 403 | src += stride; 404 | } 405 | } 406 | 407 | void QT_FASTCALL qt_convert_BGR555_to_ARGB32(const QVideoFrame &frame, uchar *output) 408 | { 409 | FETCH_INFO_PACKED(frame) 410 | MERGE_LOOPS(width, height, stride, 2) 411 | 412 | quint32 *argb = reinterpret_cast(output); 413 | 414 | for (int y = 0; y < height; ++y) { 415 | const quint16 *bgr = reinterpret_cast(src); 416 | 417 | int x = 0; 418 | for (; x < width - 3; x += 4) { 419 | *argb++ = qConvertBGR555ToARGB32(*bgr++); 420 | *argb++ = qConvertBGR555ToARGB32(*bgr++); 421 | *argb++ = qConvertBGR555ToARGB32(*bgr++); 422 | *argb++ = qConvertBGR555ToARGB32(*bgr++); 423 | } 424 | 425 | // leftovers 426 | for (; x < width; ++x) 427 | *argb++ = qConvertBGR555ToARGB32(*bgr++); 428 | 429 | src += stride; 430 | } 431 | } 432 | 433 | #endif // QVIDEOFRAMECONVERSIONHELPER_P_H 434 | --------------------------------------------------------------------------------