├── .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 | 
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 | [](https://somcosoftware.com)
13 |
14 | [](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 | 
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 |
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 |
--------------------------------------------------------------------------------