diff --git a/.clang-format b/.clang-format index 5520e59df9..51ba5e80f4 100644 --- a/.clang-format +++ b/.clang-format @@ -8,22 +8,26 @@ TabWidth: 4 UseTab: ForContinuationAndIndentation # ForIndentation AccessModifierOffset: -4 -BreakBeforeBraces: Mozilla -ColumnLimit: 120 +ColumnLimit: 135 #AlignConsecutiveAssignments: true +AlignConsecutiveBitFields: true AlignEscapedNewlines: DontAlign AlignTrailingComments: true -AllowShortCaseLabelsOnASingleLine: true +AllowShortCaseLabelsOnASingleLine: true AllowShortFunctionsOnASingleLine: Inline #AllowShortLambdasOnASingleLine: Inline +AllowShortEnumsOnASingleLine: true +AllowAllArgumentsOnNextLine: true +AllowAllParametersOfDeclarationOnNextLine: true AlwaysBreakAfterDefinitionReturnType: None AlwaysBreakTemplateDeclarations: Yes BreakBeforeBraces: Mozilla +BreakBeforeBinaryOperators: NonAssignment BreakBeforeTernaryOperators: true -ConstructorInitializerAllOnOneLineOrOnePerLine: false +ConstructorInitializerAllOnOneLineOrOnePerLine: true FixNamespaceComments: true IncludeBlocks: Regroup KeepEmptyLinesAtTheStartOfBlocks: false diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000000..482add0e9b --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +test/samples export-ignore diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 79becdffc6..6858fb4f2e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -39,7 +39,7 @@ jobs: # Use a bash shell so we can use the same syntax for environment variable # access regardless of the host operating system shell: bash - run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DBUILD_UNIT_TESTS=ON -DBUILD_PYTHON_MODULE=ON + run: cmake $GITHUB_WORKSPACE -DCMAKE_BUILD_TYPE=$BUILD_TYPE -DBUILD_BLACKBOX_TESTS=ON -DBUILD_UNIT_TESTS=ON -DBUILD_PYTHON_MODULE=ON - name: Build working-directory: ${{runner.workspace}}/build diff --git a/CMakeLists.txt b/CMakeLists.txt index 7d01ee88b4..e947ce8dbe 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,11 +1,11 @@ cmake_minimum_required (VERSION 3.14) -project (ZXing VERSION "1.3.0" LANGUAGES CXX) +project (ZXing VERSION "1.4.0" LANGUAGES CXX) option (BUILD_WRITERS "Build with writer support (encoders)" ON) option (BUILD_READERS "Build with reader support (decoders)" ON) option (BUILD_EXAMPLES "Build the example barcode reader/writer applications" ON) -option (BUILD_BLACKBOX_TESTS "Build the black box reader/writer tests" ON) +option (BUILD_BLACKBOX_TESTS "Build the black box reader/writer tests" OFF) option (BUILD_UNIT_TESTS "Build the unit tests (don't enable for production builds)" OFF) option (BUILD_PYTHON_MODULE "Build the python module" OFF) set(BUILD_DEPENDENCIES "AUTO" CACHE STRING "Fetch from github or use locally installed (AUTO/GITHUB/LOCAL)") @@ -87,29 +87,13 @@ install ( DESTINATION ${CMAKECONFIG_INSTALL_DIR} NAMESPACE ZXing:: ) -install ( - DIRECTORY core/src/ - DESTINATION include/ZXing - FILES_MATCHING PATTERN "*.h" -) - -configure_file ( - core/ZXVersion.h.in - ZXVersion.h -) - -install ( - FILES "${CMAKE_CURRENT_BINARY_DIR}/ZXVersion.h" - DESTINATION include/ZXing -) - # PC file generation. if (NOT DEFINED INSTALLDIR) set (INSTALLDIR ${CMAKE_INSTALL_PREFIX}) get_filename_component(INSTALLDIR ${INSTALLDIR} ABSOLUTE) endif() -IF (NOT WIN32) +IF (NOT WIN32 OR MINGW) configure_file(zxing.pc.in zxing.pc @ONLY) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/zxing.pc DESTINATION ${CMAKE_INSTALL_LIBDIR}/pkgconfig) ENDIF() diff --git a/README.md b/README.md index 58a274cf5f..0508b63cac 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ # ZXing-C++ -ZXing-C++ ("zebra crossing") is an open-source, multi-format 1D/2D barcode image processing library implemented in C++. +ZXing-C++ ("zebra crossing") is an open-source, multi-format linear/matrix barcode image processing library implemented in C++. It was originally ported from the Java [ZXing Library](https://github.com/zxing/zxing) but has been developed further and now includes many improvements in terms of quality and performance. It can both read and write barcodes in a number of formats. @@ -18,14 +18,14 @@ It was originally ported from the Java [ZXing Library](https://github.com/zxing/ ## Supported Formats -| 1D product | 1D industrial | 2D -| ---------- | ----------------- | -------------- -| UPC-A | Code 39 | QR Code -| UPC-E | Code 93 | DataMatrix -| EAN-8 | Code 128 | Aztec -| EAN-13 | Codabar | PDF417 -| DataBar | ITF | MaxiCode (beta) -| | DataBar Expanded | +| Linear product | Linear industrial | Matrix | +|----------------|-------------------|--------------------| +| UPC-A | Code 39 | QR Code | +| UPC-E | Code 93 | Micro QR Code | +| EAN-8 | Code 128 | Aztec | +| EAN-13 | Codabar | DataMatrix | +| DataBar | DataBar Exanded | PDF417 | +| | ITF | MaxiCode (partial) | Note: DataBar used to be called RSS. DataBar is not supported for writing. @@ -34,7 +34,7 @@ Note: DataBar used to be called RSS. DataBar is not supported for writing. ### To read barcodes: As an example, have a look at [`ZXingReader.cpp`](example/ZXingReader.cpp). 1. Load your image into memory (3rd-party library required). -2. Call `ReadBarcode()` from [`ReadBarcode.h`](core/src/ReadBarcode.h), the simplest API to get a `Result`. +2. Call `ReadBarcodes()` from [`ReadBarcode.h`](core/src/ReadBarcode.h), the simplest API to get a list of `Result` objects. ### To write barcodes: As an example, have a look at [`ZXingWriter.cpp`](example/ZXingWriter.cpp). diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index 0d4bff9f0c..7382bcae71 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -19,6 +19,7 @@ set (ZXING_CORE_LOCAL_DEFINES $<$:-DZXING_BUILD_READERS> $<$:-DZXING_BUILD_WRITERS> $<$:-DZXING_BUILD_FOR_TEST> + -DZX_USE_UTF8 # silence deprecation warning in Result.h ) if (MSVC) set (ZXING_CORE_LOCAL_DEFINES ${ZXING_CORE_LOCAL_DEFINES} @@ -49,12 +50,15 @@ set (COMMON_FILES src/ByteArray.h src/ByteMatrix.h src/CharacterSet.h + src/CharacterSet.cpp src/CharacterSetECI.h - src/CharacterSetECI.cpp src/ConcentricFinder.h src/ConcentricFinder.cpp src/CustomData.h + src/ECI.h + src/ECI.cpp src/Flags.h + src/Generator.h src/GenericGF.h src/GenericGF.cpp src/GenericGFPoly.h @@ -71,11 +75,11 @@ set (COMMON_FILES src/TextUtfEncoding.h src/TextUtfEncoding.cpp src/TritMatrix.h + src/ZXAlgorithms.h src/ZXBigInteger.h src/ZXBigInteger.cpp src/ZXConfig.h src/ZXNullable.h - src/ZXContainerAlgorithms.h src/ZXTestSupport.h ) if (BUILD_READERS) @@ -84,16 +88,21 @@ if (BUILD_READERS) src/BinaryBitmap.cpp src/BitSource.h src/BitSource.cpp + src/Content.h + src/Content.cpp src/DecodeHints.h src/DecodeHints.cpp src/DecodeStatus.h src/DecodeStatus.cpp src/DecoderResult.h src/DetectorResult.h + src/Error.h src/GlobalHistogramBinarizer.h src/GlobalHistogramBinarizer.cpp src/GridSampler.h src/GridSampler.cpp + src/GS1.h + src/GS1.cpp src/HybridBinarizer.h src/HybridBinarizer.cpp src/ImageView.h @@ -129,6 +138,42 @@ if (BUILD_WRITERS) ) endif() +# define subset of public headers that get distributed with the binaries +set (PUBLIC_HEADERS + src/BarcodeFormat.h + src/BitHacks.h + src/ByteArray.h + src/CharacterSet.h + src/CharacterSetECI.h # deprecated + src/Flags.h + src/GTIN.h + src/TextUtfEncoding.h + src/ZXAlgorithms.h + src/ZXConfig.h +) +if (BUILD_READERS) + set (PUBLIC_HEADERS ${PUBLIC_HEADERS} + src/Content.h + src/DecodeHints.h + src/DecodeStatus.h + src/Error.h + src/ImageView.h + src/Point.h + src/Quadrilateral.h + src/ReadBarcode.h + src/Result.h + src/StructuredAppend.h + ) +endif() +if (BUILD_WRITERS) + set (PUBLIC_HEADERS ${PUBLIC_HEADERS} + src/BitMatrix.h + src/BitMatrixIO.h + src/Matrix.h + src/MultiFormatWriter.h + ) +endif() +# end of public header set set (AZTEC_FILES ) @@ -226,6 +271,8 @@ if (BUILD_READERS) src/oned/ODDataBarCommon.cpp src/oned/ODDataBarReader.h src/oned/ODDataBarReader.cpp + src/oned/ODDataBarExpandedBitDecoder.h + src/oned/ODDataBarExpandedBitDecoder.cpp src/oned/ODDataBarExpandedReader.h src/oned/ODDataBarExpandedReader.cpp src/oned/ODITFReader.h @@ -264,20 +311,6 @@ if (BUILD_WRITERS) endif() -set (ONED_RSS_FILES -) -if (BUILD_READERS) - set (ONED_RSS_FILES ${ONED_RSS_FILES} - src/oned/rss/ODRSSExpandedBinaryDecoder.h - src/oned/rss/ODRSSExpandedBinaryDecoder.cpp - src/oned/rss/ODRSSFieldParser.h - src/oned/rss/ODRSSFieldParser.cpp - src/oned/rss/ODRSSGenericAppIdDecoder.h - src/oned/rss/ODRSSGenericAppIdDecoder.cpp - ) -endif() - - set (PDF417_FILES ) if (BUILD_READERS) @@ -399,7 +432,6 @@ source_group (Sources\\aztec FILES ${AZTEC_FILES}) source_group (Sources\\datamatrix FILES ${DATAMATRIX_FILES}) source_group (Sources\\maxicode FILES ${MAXICODE_FILES}) source_group (Sources\\oned FILES ${ONED_FILES}) -source_group (Sources\\oned\\rss FILES ${ONED_RSS_FILES}) source_group (Sources\\pdf417 FILES ${PDF417_FILES}) source_group (Sources\\qrcode FILES ${QRCODE_FILES}) source_group (Sources\\textcodec FILES ${TEXT_CODEC_FILES}) @@ -414,7 +446,6 @@ add_library (ZXing ${DATAMATRIX_FILES} ${MAXICODE_FILES} ${ONED_FILES} - ${ONED_RSS_FILES} ${PDF417_FILES} ${QRCODE_FILES} ${TEXT_CODEC_FILES} @@ -458,6 +489,8 @@ if (PROJECT_VERSION) set_target_properties(ZXing PROPERTIES SOVERSION ${PROJECT_VERSION_MAJOR}) endif() +set_target_properties(ZXing PROPERTIES PUBLIC_HEADER "${PUBLIC_HEADERS}") + include (GNUInstallDirs) install ( @@ -465,7 +498,15 @@ install ( LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR} - INCLUDES DESTINATION include +# INCLUDES DESTINATION include + PUBLIC_HEADER DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/ZXing" +) + +configure_file (ZXVersion.h.in ZXVersion.h) + +install ( + FILES "${CMAKE_CURRENT_BINARY_DIR}/ZXVersion.h" + DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/ZXing" ) if(MSVC) diff --git a/core/ZXVersion.h.in b/core/ZXVersion.h.in index 8e2151f629..78fde4106a 100644 --- a/core/ZXVersion.h.in +++ b/core/ZXVersion.h.in @@ -1,19 +1,9 @@ -#pragma once /* * Copyright 2019 Nu-book Inc. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once // Version numbering #define ZXING_VERSION_MAJOR @PROJECT_VERSION_MAJOR@ diff --git a/core/src/BarcodeFormat.cpp b/core/src/BarcodeFormat.cpp index fddb6eface..e188f2908a 100644 --- a/core/src/BarcodeFormat.cpp +++ b/core/src/BarcodeFormat.cpp @@ -1,23 +1,12 @@ /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "BarcodeFormat.h" -#include "ZXContainerAlgorithms.h" +#include "ZXAlgorithms.h" #include #include @@ -48,12 +37,13 @@ static BarcodeFormatName NAMES[] = { {BarcodeFormat::EAN13, "EAN-13"}, {BarcodeFormat::ITF, "ITF"}, {BarcodeFormat::MaxiCode, "MaxiCode"}, + {BarcodeFormat::MicroQRCode, "MicroQRCode"}, {BarcodeFormat::PDF417, "PDF417"}, {BarcodeFormat::QRCode, "QRCode"}, {BarcodeFormat::UPCA, "UPC-A"}, {BarcodeFormat::UPCE, "UPC-E"}, - {BarcodeFormat::OneDCodes, "1D-Codes"}, - {BarcodeFormat::TwoDCodes, "2D-Codes"}, + {BarcodeFormat::LinearCodes, "Linear-Codes"}, + {BarcodeFormat::MatrixCodes, "Matrix-Codes"}, }; const char* ToString(BarcodeFormat format) diff --git a/core/src/BarcodeFormat.h b/core/src/BarcodeFormat.h index 2858ed57e6..01263c375a 100644 --- a/core/src/BarcodeFormat.h +++ b/core/src/BarcodeFormat.h @@ -1,20 +1,10 @@ -#pragma once /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include "Flags.h" @@ -31,26 +21,27 @@ enum class BarcodeFormat // would not have been necessary to explicitly set the values to single bit constants. This has been done to ease // the interoperability with C-like interfaces, the python and the Qt wrapper. None = 0, ///< Used as a return value if no valid barcode has been detected - Aztec = (1 << 0), ///< Aztec (2D) - Codabar = (1 << 1), ///< Codabar (1D) - Code39 = (1 << 2), ///< Code39 (1D) - Code93 = (1 << 3), ///< Code93 (1D) - Code128 = (1 << 4), ///< Code128 (1D) + Aztec = (1 << 0), ///< Aztec + Codabar = (1 << 1), ///< Codabar + Code39 = (1 << 2), ///< Code39 + Code93 = (1 << 3), ///< Code93 + Code128 = (1 << 4), ///< Code128 DataBar = (1 << 5), ///< GS1 DataBar, formerly known as RSS 14 DataBarExpanded = (1 << 6), ///< GS1 DataBar Expanded, formerly known as RSS EXPANDED - DataMatrix = (1 << 7), ///< DataMatrix (2D) - EAN8 = (1 << 8), ///< EAN-8 (1D) - EAN13 = (1 << 9), ///< EAN-13 (1D) - ITF = (1 << 10), ///< ITF (Interleaved Two of Five) (1D) - MaxiCode = (1 << 11), ///< MaxiCode (2D) - PDF417 = (1 << 12), ///< PDF417 (1D) or (2D) - QRCode = (1 << 13), ///< QR Code (2D) - UPCA = (1 << 14), ///< UPC-A (1D) - UPCE = (1 << 15), ///< UPC-E (1D) + DataMatrix = (1 << 7), ///< DataMatrix + EAN8 = (1 << 8), ///< EAN-8 + EAN13 = (1 << 9), ///< EAN-13 + ITF = (1 << 10), ///< ITF (Interleaved Two of Five) + MaxiCode = (1 << 11), ///< MaxiCode + PDF417 = (1 << 12), ///< PDF417 + QRCode = (1 << 13), ///< QR Code + UPCA = (1 << 14), ///< UPC-A + UPCE = (1 << 15), ///< UPC-E + MicroQRCode = (1 << 16), ///< Micro QR Code - OneDCodes = Codabar | Code39 | Code93 | Code128 | EAN8 | EAN13 | ITF | DataBar | DataBarExpanded | UPCA | UPCE, - TwoDCodes = Aztec | DataMatrix | MaxiCode | PDF417 | QRCode, - Any = OneDCodes | TwoDCodes, + LinearCodes = Codabar | Code39 | Code93 | Code128 | EAN8 | EAN13 | ITF | DataBar | DataBarExpanded | UPCA | UPCE, + MatrixCodes = Aztec | DataMatrix | MaxiCode | PDF417 | QRCode | MicroQRCode, + Any = LinearCodes | MatrixCodes, // Deprecated names, kept for compatibility at the moment NONE [[deprecated]] = None, @@ -69,8 +60,10 @@ enum class BarcodeFormat RSS_EXPANDED [[deprecated]] = DataBarExpanded, UPC_A [[deprecated]] = UPCA, UPC_E [[deprecated]] = UPCE, + OneDCodes [[deprecated]] = LinearCodes, + TwoDCodes [[deprecated]] = MatrixCodes, - _max = UPCE, ///> implementation detail, don't use + _max = MicroQRCode, ///> implementation detail, don't use }; ZX_DECLARE_FLAGS(BarcodeFormats, BarcodeFormat) @@ -89,7 +82,7 @@ BarcodeFormat BarcodeFormatFromString(const std::string& str); * Separators can be (any combination of) '|', ',' or ' '. * Underscores are optional and input can be lower case. * e.g. "EAN-8 qrcode, Itf" would be parsed into [EAN8, QRCode, ITF]. - * @throws std::invalid_parameter Throws if the string can not be fully parsed. + * @throws std::invalid_parameter if the string can not be fully parsed. */ BarcodeFormats BarcodeFormatsFromString(const std::string& str); diff --git a/core/src/BinaryBitmap.cpp b/core/src/BinaryBitmap.cpp index e68cccd2bc..e3676eef6a 100644 --- a/core/src/BinaryBitmap.cpp +++ b/core/src/BinaryBitmap.cpp @@ -1,18 +1,7 @@ /* * Copyright 2020 Axel Waggershauser -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "BinaryBitmap.h" diff --git a/core/src/BinaryBitmap.h b/core/src/BinaryBitmap.h index 896294db73..433e510aed 100644 --- a/core/src/BinaryBitmap.h +++ b/core/src/BinaryBitmap.h @@ -1,23 +1,13 @@ -#pragma once /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors * Copyright 2021 Axel Waggershauser -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once -#include "ReadBarcode.h" +#include "ImageView.h" #include #include diff --git a/core/src/BitArray.cpp b/core/src/BitArray.cpp index 5566c65e47..718d025bac 100644 --- a/core/src/BitArray.cpp +++ b/core/src/BitArray.cpp @@ -1,19 +1,8 @@ /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "BitArray.h" diff --git a/core/src/BitArray.h b/core/src/BitArray.h index 2fdb4a567e..4c840262e6 100644 --- a/core/src/BitArray.h +++ b/core/src/BitArray.h @@ -1,24 +1,14 @@ -#pragma once /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors * Copyright 2017 Axel Waggershauser -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include "ZXConfig.h" -#include "ZXContainerAlgorithms.h" +#include "ZXAlgorithms.h" #ifndef ZX_FAST_BIT_STORAGE #include "BitHacks.h" #endif @@ -27,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -36,10 +27,11 @@ namespace ZXing { class ByteArray; template -struct Range { +struct Range +{ Iterator begin, end; explicit operator bool() const { return begin < end; } - int size() const { return static_cast(end - begin); } + int size() const { return narrow_cast(end - begin); } }; /** @@ -97,7 +89,7 @@ class BitArray int operator-(const Iterator& rhs) const { - return static_cast(_value - rhs._value) * 32 + (_mask >= rhs._mask + return narrow_cast(_value - rhs._value) * 32 + (_mask >= rhs._mask ? +BitHacks::CountBitsSet(_mask - rhs._mask) : -BitHacks::CountBitsSet(rhs._mask - _mask)); } @@ -129,20 +121,24 @@ class BitArray BitArray() = default; - explicit BitArray(int size) : + explicit BitArray(int size) + : #ifdef ZX_FAST_BIT_STORAGE - _bits(size, 0) {} + _bits(size, 0) {} #else - _size(size), _bits((size + 31) / 32, 0) {} + _size(size), + _bits((size + 31) / 32, 0) {} #endif - BitArray(BitArray&& other) noexcept : + BitArray(BitArray&& other) noexcept + : #ifndef ZX_FAST_BIT_STORAGE - _size(other._size), + _size(other._size), #endif - _bits(std::move(other._bits)) {} + _bits(std::move(other._bits)) {} - BitArray& operator=(BitArray&& other) noexcept { + BitArray& operator=(BitArray&& other) noexcept + { #ifndef ZX_FAST_BIT_STORAGE _size = other._size; #endif @@ -150,27 +146,25 @@ class BitArray return *this; } - BitArray copy() const { - return *this; - } + BitArray copy() const { return *this; } - int size() const noexcept { + int size() const noexcept + { #ifdef ZX_FAST_BIT_STORAGE return Size(_bits); #else return _size; #endif } - - int sizeInBytes() const noexcept { - return (size() + 7) / 8; - } + + int sizeInBytes() const noexcept { return (size() + 7) / 8; } /** * @param i bit to get * @return true iff bit i is set */ - bool get(int i) const { + bool get(int i) const + { #ifdef ZX_FAST_BIT_STORAGE return _bits.at(i) != 0; #else @@ -188,7 +182,8 @@ class BitArray Iterator end() const noexcept { return _bits.cend(); } template - static ITER getNextSetTo(ITER begin, ITER end, bool v) noexcept { + static ITER getNextSetTo(ITER begin, ITER end, bool v) noexcept + { while( begin != end && *begin != static_cast(v) ) ++begin; return begin; @@ -198,7 +193,8 @@ class BitArray Iterator begin() const noexcept { return iterAt(0); } Iterator end() const noexcept { return iterAt(_size); } - static Iterator getNextSetTo(Iterator begin, Iterator end, bool v) { + static Iterator getNextSetTo(Iterator begin, Iterator end, bool v) + { auto i = begin; // reconstruct _bits.end() auto bitsEnd = end._mask == 0x1 ? end._value : std::next(end._value); @@ -216,16 +212,15 @@ class BitArray return i; } - static ReverseIterator getNextSetTo(ReverseIterator begin, ReverseIterator end, bool v) { + static ReverseIterator getNextSetTo(ReverseIterator begin, ReverseIterator end, bool v) + { while( begin != end && *begin != v ) ++begin; return begin; } #endif - Iterator getNextSetTo(Iterator i, bool v) const { - return getNextSetTo(i, end(), v); - } + Iterator getNextSetTo(Iterator i, bool v) const { return getNextSetTo(i, end(), v); } Iterator getNextSet(Iterator i) const { return getNextSetTo(i, true); } Iterator getNextUnset(Iterator i) const { return getNextSetTo(i, false); } @@ -238,7 +233,8 @@ class BitArray * * @param i bit to set */ - void set(int i, bool val) { + void set(int i, bool val) + { #ifdef ZX_FAST_BIT_STORAGE _bits.at(i) = val; #else @@ -252,9 +248,7 @@ class BitArray /** * Clears all bits (sets to false). */ - void clearBits() { - std::fill(_bits.begin(), _bits.end(), 0); - } + void clearBits() { std::fill(_bits.begin(), _bits.end(), 0); } /** * Efficient method to check if a range of bits is set, or not set. @@ -263,10 +257,10 @@ class BitArray * @param end end of range, exclusive * @param value if true, checks that bits in range are set, otherwise checks that they are not set * @return true iff all bits are set or not set in range, according to value argument - * @throws IllegalArgumentException if end is less than or equal to start */ #ifdef ZX_FAST_BIT_STORAGE - bool isRange(int start, int end, bool value) const { + bool isRange(int start, int end, bool value) const + { return std::all_of(std::begin(_bits) + start, std::begin(_bits) + end, [value](uint8_t v) { return v == static_cast(value); }); } #else @@ -276,8 +270,9 @@ class BitArray // Little helper method to make common isRange use case more readable. // Pass positive zone size to look for quiet zone after i and negative for zone in front of i. // Set allowClippedZone to false if clipping the zone at the image border is not acceptable. - bool hasQuietZone(Iterator i, int signedZoneSize, bool allowClippedZone = true) const { - int index = static_cast(i - begin()); + bool hasQuietZone(Iterator i, int signedZoneSize, bool allowClippedZone = true) const + { + int index = narrow_cast(i - begin()); if (signedZoneSize > 0) { if (!allowClippedZone && index + signedZoneSize >= size()) return false; @@ -289,7 +284,8 @@ class BitArray } } - bool hasQuietZone(ReverseIterator i, int signedZoneSize, bool allowClippedZone = true) const { + bool hasQuietZone(ReverseIterator i, int signedZoneSize, bool allowClippedZone = true) const + { return hasQuietZone(i.base(), -signedZoneSize, allowClippedZone); } @@ -302,25 +298,20 @@ class BitArray * @param numBits bits from value to append */ #ifdef ZX_FAST_BIT_STORAGE - void appendBits(int value, int numBits) { + void appendBits(int value, int numBits) + { for (; numBits; --numBits) _bits.push_back((value >> (numBits-1)) & 1); } - void appendBit(bool bit) { - _bits.push_back(bit); - } + void appendBit(bool bit) { _bits.push_back(bit); } - void appendBitArray(const BitArray& other) { - _bits.insert(_bits.end(), other.begin(), other.end()); - } + void appendBitArray(const BitArray& other) { _bits.insert(_bits.end(), other.begin(), other.end()); } /** * Reverses all bits in the array. */ - void reverse() { - std::reverse(_bits.begin(), _bits.end()); - } + void reverse() { std::reverse(_bits.begin(), _bits.end()); } #else void appendBits(int value, int numBits); @@ -331,9 +322,7 @@ class BitArray /** * Reverses all bits in the array. */ - void reverse() { - BitHacks::Reverse(_bits, _bits.size() * 32 - _size); - } + void reverse() { BitHacks::Reverse(_bits, _bits.size() * 32 - _size); } #endif void bitwiseXOR(const BitArray& other); @@ -374,14 +363,6 @@ int ToInt(const ARRAY& a) return pattern; } -inline int ReadBits(BitArray::Range& bits, int n) -{ - int res = 0; - for (; n > 0 && bits.size(); --n, bits.begin++) - AppendBit(res, *bits.begin); - return res; -} - template >> T ToInt(const BitArray& bits, int pos = 0, int count = 8 * sizeof(T)) { @@ -410,4 +391,46 @@ std::vector ToInts(const BitArray& bits, int wordSize, int totalWords, int of return res; } +class BitArrayView +{ + const BitArray& bits; + BitArray::Iterator cur; + +public: + BitArrayView(const BitArray& bits) : bits(bits), cur(bits.begin()) {} + + BitArrayView& skipBits(int n) + { + if (n > bits.size()) + throw std::out_of_range("BitArrayView::skipBits() out of range."); + cur += n; + return *this; + } + + int peakBits(int n) const + { + assert(n <= 32); + if (n > bits.size()) + throw std::out_of_range("BitArrayView::peakBits() out of range."); + int res = 0; + for (auto i = cur; n > 0; --n, i++) + AppendBit(res, *i); + return res; + } + + int readBits(int n) + { + int res = peakBits(n); + cur += n; + return res; + } + + int size() const + { + return narrow_cast(bits.end() - cur); + } + + explicit operator bool() const { return size(); } +}; + } // ZXing diff --git a/core/src/BitHacks.h b/core/src/BitHacks.h index 7ee06fc38b..482b181a8b 100644 --- a/core/src/BitHacks.h +++ b/core/src/BitHacks.h @@ -1,20 +1,10 @@ -#pragma once /* * Copyright 2016 Huy Cuong Nguyen * Copyright 2017 Axel Waggershauser -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include #include diff --git a/core/src/BitMatrix.cpp b/core/src/BitMatrix.cpp index 2f484f7d1c..d0497ff394 100644 --- a/core/src/BitMatrix.cpp +++ b/core/src/BitMatrix.cpp @@ -1,19 +1,8 @@ /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "BitMatrix.h" @@ -207,9 +196,9 @@ BitMatrix::getBottomRightOnBit(int& right, int& bottom) const constexpr BitMatrix::data_t BitMatrix::SET_V; constexpr BitMatrix::data_t BitMatrix::UNSET_V; -void BitMatrix::getPatternRow(int r, PatternRow& p_row) const +template +void GetPatternRow(BitMatrix::Row b_row, int row_size, PatternRow& p_row) { - auto b_row = row(r); #if 0 p_row.reserve(64); p_row.clear(); @@ -227,11 +216,11 @@ void BitMatrix::getPatternRow(int r, PatternRow& p_row) const if (BitMatrix::isSet(*lastPos)) p_row.push_back(0); // last value is number of white pixels, here 0 #else - p_row.resize(width() + 2); + p_row.resize(row_size + 2); std::fill(p_row.begin(), p_row.end(), 0); - auto* bitPos = b_row.begin(); - auto* intPos = p_row.data(); + auto bitPos = b_row.begin(); + auto intPos = p_row.data(); intPos += BitMatrix::isSet(*bitPos); // first value is number of white pixels, here 0 @@ -247,6 +236,14 @@ void BitMatrix::getPatternRow(int r, PatternRow& p_row) const p_row.resize(intPos - p_row.data() + 1); #endif } + +void BitMatrix::getPatternRow(int r, PatternRow& p_row, bool transpose) const +{ + if (transpose) + GetPatternRow(col(r), height(), p_row); + else + GetPatternRow(row(r), width(), p_row); +} #endif BitMatrix Inflate(BitMatrix&& input, int width, int height, int quietZone) diff --git a/core/src/BitMatrix.h b/core/src/BitMatrix.h index 1569e885a5..13c34fd875 100644 --- a/core/src/BitMatrix.h +++ b/core/src/BitMatrix.h @@ -1,20 +1,10 @@ -#pragma once /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include "Matrix.h" #include "Point.h" @@ -81,14 +71,19 @@ class BitMatrix BitMatrix(int width, int height) : _width(width), _height(height), _rowSize(width), _bits(width * height, UNSET_V) {} #else - BitMatrix(int width, int height) : _width(width), _height(height), _rowSize((width + 31) / 32), _bits(((width + 31) / 32) * _height, 0) {} + BitMatrix(int width, int height) + : _width(width), _height(height), _rowSize((width + 31) / 32), _bits(((width + 31) / 32) * _height, 0) + {} #endif explicit BitMatrix(int dimension) : BitMatrix(dimension, dimension) {} // Construct a square matrix. - BitMatrix(BitMatrix&& other) noexcept : _width(other._width), _height(other._height), _rowSize(other._rowSize), _bits(std::move(other._bits)) {} + BitMatrix(BitMatrix&& other) noexcept + : _width(other._width), _height(other._height), _rowSize(other._rowSize), _bits(std::move(other._bits)) + {} - BitMatrix& operator=(BitMatrix&& other) noexcept { + BitMatrix& operator=(BitMatrix&& other) noexcept + { _width = other._width; _height = other._height; _rowSize = other._rowSize; @@ -96,13 +91,11 @@ class BitMatrix return *this; } - BitMatrix copy() const { - return *this; - } + BitMatrix copy() const { return *this; } #ifdef ZX_FAST_BIT_STORAGE // experimental iterator based access - template + template struct Row { iterator _begin, _end; @@ -111,6 +104,19 @@ class BitMatrix }; Row row(int y) { return {_bits.data() + y * _width, _bits.data() + (y + 1) * _width}; } Row row(int y) const { return {_bits.data() + y * _width, _bits.data() + (y + 1) * _width}; } + + struct ColIter + { + const data_t* pos; + int stride; + + data_t operator*() const { return *pos; } + data_t operator[](int i) const { return *(pos + i * stride); } + ColIter& operator++() { return pos += stride, *this; } + bool operator<(const ColIter& rhs) const { return pos < rhs.pos; } + }; + Row col(int x) const { return {{_bits.data() + x, _width}, {_bits.data() + x + _height * _width, _width}}; } + #endif /** @@ -120,7 +126,8 @@ class BitMatrix * @param y The vertical component (i.e. which row) * @return value of given bit in matrix */ - bool get(int x, int y) const { + bool get(int x, int y) const + { #ifdef ZX_FAST_BIT_STORAGE return isSet(get(y * _width + x)); #else @@ -134,7 +141,8 @@ class BitMatrix * @param x The horizontal component (i.e. which column) * @param y The vertical component (i.e. which row) */ - void set(int x, int y) { + void set(int x, int y) + { #ifdef ZX_FAST_BIT_STORAGE get(y * _width + x) = SET_V; #else @@ -142,7 +150,8 @@ class BitMatrix #endif } - void unset(int x, int y) { + void unset(int x, int y) + { #ifdef ZX_FAST_BIT_STORAGE get(y * _width + x) = UNSET_V; #else @@ -150,7 +159,8 @@ class BitMatrix #endif } - void set(int x, int y, bool val) { + void set(int x, int y, bool val) + { #ifdef ZX_FAST_BIT_STORAGE get(y * _width + x) = val ? SET_V : UNSET_V; #else @@ -164,7 +174,8 @@ class BitMatrix * @param x The horizontal component (i.e. which column) * @param y The vertical component (i.e. which row) */ - void flip(int x, int y) { + void flip(int x, int y) + { #ifdef ZX_FAST_BIT_STORAGE auto& v =get(y * _width + x); v = !v; @@ -173,7 +184,8 @@ class BitMatrix #endif } - void flipAll() { + void flipAll() + { for (auto& i : _bits) { i = ~i; } @@ -182,9 +194,7 @@ class BitMatrix /** * Clears all bits (sets to false). */ - void clear() { - std::fill(_bits.begin(), _bits.end(), 0); - } + void clear() { std::fill(_bits.begin(), _bits.end(), 0); } /** *

Sets a square region of the bit matrix to true.

@@ -235,33 +245,25 @@ class BitMatrix bool getBottomRightOnBit(int &right, int& bottom) const; #ifdef ZX_FAST_BIT_STORAGE - void getPatternRow(int r, std::vector& p_row) const; + void getPatternRow(int r, std::vector& p_row, bool transpose = false) const; #endif /** * @return The width of the matrix */ - int width() const { - return _width; - } + int width() const { return _width; } /** * @return The height of the matrix */ - int height() const { - return _height; - } + int height() const { return _height; } /** * @return The row size of the matrix. That is the number of 32-bits blocks that one row takes. */ - int rowSize() const { - return _rowSize; - } + int rowSize() const { return _rowSize; } - bool empty() const { - return _bits.empty(); - } + bool empty() const { return _bits.empty(); } friend bool operator==(const BitMatrix& a, const BitMatrix& b) { diff --git a/core/src/BitMatrixCursor.h b/core/src/BitMatrixCursor.h index a7a98e1b61..7e1f16c440 100644 --- a/core/src/BitMatrixCursor.h +++ b/core/src/BitMatrixCursor.h @@ -1,19 +1,9 @@ -#pragma once /* * Copyright 2020 Axel Waggershauser -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include "BitMatrix.h" @@ -21,7 +11,7 @@ namespace ZXing { -enum class Direction {LEFT = -1, RIGHT = 1}; +enum class Direction { LEFT = -1, RIGHT = 1 }; inline Direction opposite(Direction dir) noexcept { diff --git a/core/src/BitMatrixIO.cpp b/core/src/BitMatrixIO.cpp index be1732326c..0d4e54325d 100644 --- a/core/src/BitMatrixIO.cpp +++ b/core/src/BitMatrixIO.cpp @@ -1,25 +1,15 @@ /* * Copyright 2017 Huy Cuong Nguyen * Copyright 2017 Axel Waggershauser -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "BitMatrixIO.h" #include "BitArray.h" #include +#include namespace ZXing { @@ -44,6 +34,29 @@ std::string ToString(const BitMatrix& matrix, char one, char zero, bool addSpace return result; } +std::string ToSVG(const BitMatrix& matrix) +{ + // see https://stackoverflow.com/questions/10789059/create-qr-code-in-vector-image/60638350#60638350 + + const int width = matrix.width(); + const int height = matrix.height(); + std::ostringstream out; + + out << "\n" + << "\n" + << "\n"; + + return out.str(); +} + BitMatrix ParseBitMatrix(const std::string& str, char one, bool expectSpace) { auto lineLength = str.find('\n'); @@ -51,8 +64,8 @@ BitMatrix ParseBitMatrix(const std::string& str, char one, bool expectSpace) return {}; int strStride = expectSpace ? 2 : 1; - int height = static_cast(str.length() / (lineLength + 1)); - int width = static_cast(lineLength / strStride); + int height = narrow_cast(str.length() / (lineLength + 1)); + int width = narrow_cast(lineLength / strStride); BitMatrix mat(width, height); for (int y = 0; y < height; ++y) { size_t offset = y * (lineLength + 1); diff --git a/core/src/BitMatrixIO.h b/core/src/BitMatrixIO.h index 6946b33905..022b48ec35 100644 --- a/core/src/BitMatrixIO.h +++ b/core/src/BitMatrixIO.h @@ -1,20 +1,10 @@ -#pragma once /* * Copyright 2017 Huy Cuong Nguyen * Copyright 2017 Axel Waggershauser -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include @@ -22,8 +12,8 @@ namespace ZXing { -std::string ToString(const BitMatrix& matrix, char one = 'X', char zero = ' ', bool addSpace = true, - bool printAsCString = false); +std::string ToString(const BitMatrix& matrix, char one = 'X', char zero = ' ', bool addSpace = true, bool printAsCString = false); +std::string ToSVG(const BitMatrix& matrix); BitMatrix ParseBitMatrix(const std::string& str, char one = 'X', bool expectSpace = true); void SaveAsPBM(const BitMatrix& matrix, const std::string filename, int quietZone = 0); diff --git a/core/src/BitSource.cpp b/core/src/BitSource.cpp index 6580bd6649..3693e52607 100644 --- a/core/src/BitSource.cpp +++ b/core/src/BitSource.cpp @@ -1,24 +1,13 @@ /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "BitSource.h" #include "ByteArray.h" -#include "ZXContainerAlgorithms.h" +#include "ZXAlgorithms.h" #include @@ -30,10 +19,9 @@ BitSource::available() const return 8 * (Size(_bytes) - _byteOffset) - _bitOffset; } -int -BitSource::readBits(int numBits) +static int ReadBitsImpl(int numBits, const ByteArray& _bytes, int available, int& _byteOffset, int& _bitOffset) { - if (numBits < 1 || numBits > 32 || numBits > available()) { + if (numBits < 1 || numBits > 32 || numBits > available) { throw std::out_of_range("BitSource::readBits: out of range"); } @@ -74,4 +62,16 @@ BitSource::readBits(int numBits) return result; } +int BitSource::readBits(int numBits) +{ + return ReadBitsImpl(numBits, _bytes, available(), _byteOffset, _bitOffset); +} + +int BitSource::peakBits(int numBits) const +{ + int bitOffset = _bitOffset; + int byteOffset = _byteOffset; + return ReadBitsImpl(numBits, _bytes, available(), byteOffset, bitOffset); +} + } // ZXing diff --git a/core/src/BitSource.h b/core/src/BitSource.h index be55d42158..9e9bbe977f 100644 --- a/core/src/BitSource.h +++ b/core/src/BitSource.h @@ -1,20 +1,10 @@ -#pragma once /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once namespace ZXing { @@ -62,12 +52,17 @@ class BitSource /** * @param numBits number of bits to read - * @return int representing the bits read. The bits will appear as the least-significant - * bits of the int - * @throws IllegalArgumentException if numBits isn't in [1,32] or more than is available + * @return int representing the bits read. The bits will appear as the least-significant bits of the int */ int readBits(int numBits); + /** + * @param numBits number of bits to peak + * @return int representing the bits peaked. The bits will appear as the least-significant + * bits of the int + */ + int peakBits(int numBits) const; + /** * @return number of bits that can be read successfully */ diff --git a/core/src/ByteArray.h b/core/src/ByteArray.h index efbd3072c1..a31f42c1ed 100644 --- a/core/src/ByteArray.h +++ b/core/src/ByteArray.h @@ -1,23 +1,20 @@ -#pragma once /* * Copyright 2016 Nu-book Inc. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. +* Copyright 2022 Axel Waggershauser */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include +#include +#include #include +#ifdef __cpp_lib_string_view +#include +#endif + namespace ZXing { /** @@ -29,6 +26,26 @@ class ByteArray : public std::vector ByteArray() = default; ByteArray(std::initializer_list list) : std::vector(list) {} explicit ByteArray(int len) : std::vector(len, 0) {} + explicit ByteArray(const std::string& str) : std::vector(str.begin(), str.end()) {} + + void append(const ByteArray& other) { insert(end(), other.begin(), other.end()); } + +#ifdef __cpp_lib_string_view + std::string_view asString(size_t pos = 0, size_t len = std::string_view::npos) const + { + return std::string_view(reinterpret_cast(data()), size()).substr(pos, len); + } +#endif }; +inline std::string ToHex(const ByteArray& bytes) +{ + std::string res(bytes.size() * 3, ' '); + + for (size_t i = 0; i < bytes.size(); ++i) + sprintf(&res[i * 3], "%02X ", bytes[i]); + + return res.substr(0, res.size()-1); +} + } // ZXing diff --git a/core/src/ByteMatrix.h b/core/src/ByteMatrix.h index 06ffd1ddc3..09dc1eac32 100644 --- a/core/src/ByteMatrix.h +++ b/core/src/ByteMatrix.h @@ -1,20 +1,10 @@ -#pragma once /* * Copyright 2016 Huy Cuong Nguyen * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include "Matrix.h" diff --git a/core/src/CharacterSet.cpp b/core/src/CharacterSet.cpp new file mode 100644 index 0000000000..4c0c17bb16 --- /dev/null +++ b/core/src/CharacterSet.cpp @@ -0,0 +1,76 @@ +/* +* Copyright 2016 Nu-book Inc. +* Copyright 2016 ZXing authors +*/ +// SPDX-License-Identifier: Apache-2.0 + +#include "CharacterSet.h" + +#include "ZXAlgorithms.h" + +#include + +namespace ZXing { + +struct CharacterSetName +{ + const char* name; + CharacterSet cs; +}; + +static CharacterSetName NAME_TO_CHARSET[] = { + {"Cp437", CharacterSet::Cp437}, + {"ISO-8859-1", CharacterSet::ISO8859_1}, + {"ISO-8859-2", CharacterSet::ISO8859_2}, + {"ISO-8859-3", CharacterSet::ISO8859_3}, + {"ISO-8859-4", CharacterSet::ISO8859_4}, + {"ISO-8859-5", CharacterSet::ISO8859_5}, + {"ISO-8859-6", CharacterSet::ISO8859_6}, + {"ISO-8859-7", CharacterSet::ISO8859_7}, + {"ISO-8859-8", CharacterSet::ISO8859_8}, + {"ISO-8859-9", CharacterSet::ISO8859_9}, + {"ISO-8859-10", CharacterSet::ISO8859_10}, + {"ISO-8859-11", CharacterSet::ISO8859_11}, + {"ISO-8859-13", CharacterSet::ISO8859_13}, + {"ISO-8859-14", CharacterSet::ISO8859_14}, + {"ISO-8859-15", CharacterSet::ISO8859_15}, + {"ISO-8859-16", CharacterSet::ISO8859_16}, + {"SJIS", CharacterSet::Shift_JIS}, + {"Shift_JIS", CharacterSet::Shift_JIS}, + {"Cp1250", CharacterSet::Cp1250}, + {"windows-1250",CharacterSet::Cp1250}, + {"Cp1251", CharacterSet::Cp1251}, + {"windows-1251",CharacterSet::Cp1251}, + {"Cp1252", CharacterSet::Cp1252}, + {"windows-1252",CharacterSet::Cp1252}, + {"Cp1256", CharacterSet::Cp1256}, + {"windows-1256",CharacterSet::Cp1256}, + {"UnicodeBigUnmarked", CharacterSet::UnicodeBig}, + {"UTF-16BE", CharacterSet::UnicodeBig}, + {"UnicodeBig", CharacterSet::UnicodeBig}, + {"UTF-8", CharacterSet::UTF8}, + {"ASCII", CharacterSet::ASCII}, + {"US-ASCII", CharacterSet::ASCII}, + {"Big5", CharacterSet::Big5}, + {"GB2312", CharacterSet::GB2312}, + {"GB18030", CharacterSet::GB18030}, + {"EUC-CN", CharacterSet::GB18030}, + {"GBK", CharacterSet::GB18030}, + {"EUC-KR", CharacterSet::EUC_KR}, + {"BINARY", CharacterSet::BINARY}, +}; + +static std::string NormalizeName(std::string str) +{ + std::transform(str.begin(), str.end(), str.begin(), [](char c) { return (char)std::tolower(c); }); + str.erase(std::remove_if(str.begin(), str.end(), [](char c) { return Contains("_-[] ", c); }), str.end()); + return str; +} + +CharacterSet CharacterSetFromString(const std::string& name) +{ + auto i = FindIf(NAME_TO_CHARSET, [str = NormalizeName(name)](auto& v) { return NormalizeName(v.name) == str; }); + return i == std::end(NAME_TO_CHARSET) ? CharacterSet::Unknown : i->cs; +} + +} // namespace ZXing diff --git a/core/src/CharacterSet.h b/core/src/CharacterSet.h index dd34fd4fd0..b26f4b23f2 100644 --- a/core/src/CharacterSet.h +++ b/core/src/CharacterSet.h @@ -1,19 +1,11 @@ -#pragma once /* * Copyright 2016 Nu-book Inc. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include namespace ZXing { @@ -56,4 +48,6 @@ enum class CharacterSet CharsetCount }; +CharacterSet CharacterSetFromString(const std::string& name); + } // ZXing diff --git a/core/src/CharacterSetECI.cpp b/core/src/CharacterSetECI.cpp deleted file mode 100644 index c9142f3891..0000000000 --- a/core/src/CharacterSetECI.cpp +++ /dev/null @@ -1,199 +0,0 @@ -/* -* Copyright 2016 Nu-book Inc. -* Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#include "CharacterSetECI.h" -#include "TextDecoder.h" - -#include -#include -#include - -namespace ZXing::CharacterSetECI { - -static const std::map ECI_VALUE_TO_CHARSET = { - {0, CharacterSet::Cp437}, // Obsolete - {1, CharacterSet::ISO8859_1}, // Obsolete - {2, CharacterSet::Cp437}, // Obsolete but still used by PDF417 Macro fields (ISO/IEC 15438:2015 Annex H.2.3) - {3, CharacterSet::ISO8859_1}, - {4, CharacterSet::ISO8859_2}, - {5, CharacterSet::ISO8859_3}, - {6, CharacterSet::ISO8859_4}, - {7, CharacterSet::ISO8859_5}, - {8, CharacterSet::ISO8859_6}, - {9, CharacterSet::ISO8859_7}, - {10, CharacterSet::ISO8859_8}, - {11, CharacterSet::ISO8859_9}, - {12, CharacterSet::ISO8859_10}, - {13, CharacterSet::ISO8859_11}, - {15, CharacterSet::ISO8859_13}, - {16, CharacterSet::ISO8859_14}, - {17, CharacterSet::ISO8859_15}, - {18, CharacterSet::ISO8859_16}, - {20, CharacterSet::Shift_JIS}, - {21, CharacterSet::Cp1250}, - {22, CharacterSet::Cp1251}, - {23, CharacterSet::Cp1252}, - {24, CharacterSet::Cp1256}, - {25, CharacterSet::UnicodeBig}, - {26, CharacterSet::UTF8}, - {27, CharacterSet::ASCII}, - {28, CharacterSet::Big5}, - {29, CharacterSet::GB18030}, - {30, CharacterSet::EUC_KR}, - {170, CharacterSet::ASCII}, - {899, CharacterSet::BINARY}, -}; - -struct CompareNoCase { - bool operator ()(const char* a, const char* b) const { - while (*a != '\0' && *b != '\0') { - auto ca = std::tolower(*a++); - auto cb = std::tolower(*b++); - if (ca < cb) { - return true; - } - else if (ca > cb) { - return false; - } - } - return *a == '\0' && *b != '\0'; - } -}; - -static const std::map ECI_NAME_TO_CHARSET = { - {"Cp437", CharacterSet::Cp437}, - {"ISO8859_1", CharacterSet::ISO8859_1}, - {"ISO-8859-1", CharacterSet::ISO8859_1}, - {"ISO8859_2", CharacterSet::ISO8859_2}, - {"ISO-8859-2", CharacterSet::ISO8859_2}, - {"ISO8859_3", CharacterSet::ISO8859_3}, - {"ISO-8859-3", CharacterSet::ISO8859_3}, - {"ISO8859_4", CharacterSet::ISO8859_4}, - {"ISO-8859-4", CharacterSet::ISO8859_4}, - {"ISO8859_5", CharacterSet::ISO8859_5}, - {"ISO-8859-5", CharacterSet::ISO8859_5}, - {"ISO8859_6", CharacterSet::ISO8859_6}, - {"ISO-8859-6", CharacterSet::ISO8859_6}, - {"ISO8859_7", CharacterSet::ISO8859_7}, - {"ISO-8859-7", CharacterSet::ISO8859_7}, - {"ISO8859_8", CharacterSet::ISO8859_8}, - {"ISO-8859-8", CharacterSet::ISO8859_8}, - {"ISO8859_9", CharacterSet::ISO8859_9}, - {"ISO-8859-9", CharacterSet::ISO8859_9}, - {"ISO8859_10", CharacterSet::ISO8859_10}, - {"ISO-8859-10", CharacterSet::ISO8859_10}, - {"ISO8859_11", CharacterSet::ISO8859_11}, - {"ISO-8859-11", CharacterSet::ISO8859_11}, - {"ISO8859_13", CharacterSet::ISO8859_13}, - {"ISO-8859-13", CharacterSet::ISO8859_13}, - {"ISO8859_14", CharacterSet::ISO8859_14}, - {"ISO-8859-14", CharacterSet::ISO8859_14}, - {"ISO8859_15", CharacterSet::ISO8859_15}, - {"ISO-8859-15", CharacterSet::ISO8859_15}, - {"ISO8859_16", CharacterSet::ISO8859_16}, - {"ISO-8859-16", CharacterSet::ISO8859_16}, - {"SJIS", CharacterSet::Shift_JIS}, - {"Shift_JIS", CharacterSet::Shift_JIS}, - {"Cp1250", CharacterSet::Cp1250}, - {"windows-1250",CharacterSet::Cp1250}, - {"Cp1251", CharacterSet::Cp1251}, - {"windows-1251",CharacterSet::Cp1251}, - {"Cp1252", CharacterSet::Cp1252}, - {"windows-1252",CharacterSet::Cp1252}, - {"Cp1256", CharacterSet::Cp1256}, - {"windows-1256",CharacterSet::Cp1256}, - {"UnicodeBigUnmarked", CharacterSet::UnicodeBig}, - {"UTF-16BE", CharacterSet::UnicodeBig}, - {"UnicodeBig", CharacterSet::UnicodeBig}, - {"UTF8", CharacterSet::UTF8}, - {"UTF-8", CharacterSet::UTF8}, - {"ASCII", CharacterSet::ASCII}, - {"US-ASCII", CharacterSet::ASCII}, - {"Big5", CharacterSet::Big5}, - {"GB2312", CharacterSet::GB2312}, - {"GB18030", CharacterSet::GB18030}, - {"EUC_CN", CharacterSet::GB18030}, - {"EUC-CN", CharacterSet::GB18030}, - {"GBK", CharacterSet::GB18030}, - {"EUC_KR", CharacterSet::EUC_KR}, - {"EUC-KR", CharacterSet::EUC_KR}, - {"BINARY", CharacterSet::BINARY}, -}; - -CharacterSet CharsetFromValue(int value) -{ - auto it = ECI_VALUE_TO_CHARSET.find(value); - if (it != ECI_VALUE_TO_CHARSET.end()) { - return it->second; - } - return CharacterSet::Unknown; -} - -int ValueForCharset(CharacterSet charset) -{ - // Special case ISO8859_1 to avoid obsolete ECI 1 - if (charset == CharacterSet::ISO8859_1) { - return 3; - } - for (auto& [key, value] : ECI_VALUE_TO_CHARSET) { - if (value == charset) { - return key; - } - } - return -1; -} - -CharacterSet CharsetFromName(const char* name) -{ - auto it = ECI_NAME_TO_CHARSET.find(name); - if (it != ECI_NAME_TO_CHARSET.end()) { - return it->second; - } - return CharacterSet::Unknown; -} - -CharacterSet InitEncoding(const std::string& name, CharacterSet encodingDefault) -{ - if (!name.empty()) { - auto encodingInit = CharacterSetECI::CharsetFromName(name.c_str()); - if (encodingInit != CharacterSet::Unknown) { - encodingDefault = encodingInit; - } - } - - return encodingDefault; -} - -#ifdef ZXING_BUILD_READERS -CharacterSet OnChangeAppendReset(const int eci, std::wstring& encoded, std::string& data, CharacterSet encoding) -{ - // Character set ECIs only - if (eci >= 0 && eci <= 899) { - auto encodingNew = CharacterSetECI::CharsetFromValue(eci); - if (encodingNew != CharacterSet::Unknown && encodingNew != encoding) { - // Encode data so far in current encoding and reset - TextDecoder::Append(encoded, reinterpret_cast(data.data()), data.size(), encoding); - data.clear(); - encoding = encodingNew; - } - } - - return encoding; -} -#endif - -} // namespace ZXing::CharacterSetECI diff --git a/core/src/CharacterSetECI.h b/core/src/CharacterSetECI.h index ee66d55f21..e70f9dc3bc 100644 --- a/core/src/CharacterSetECI.h +++ b/core/src/CharacterSetECI.h @@ -1,24 +1,12 @@ -#pragma once /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 -#include "CharacterSet.h" +#pragma once -#include +#include "CharacterSet.h" namespace ZXing { @@ -29,41 +17,12 @@ namespace ZXing { */ namespace CharacterSetECI { -/** - * @param value character set ECI value - * @return {@code CharacterSet} representing ECI of given value, or {@code CharacterSet::Unknown} if it is unsupported - */ -CharacterSet CharsetFromValue(int value); - -/** - * @param charset {@code CharacterSet} representing ECI - * @return ECI of given {@code CharacterSet}, or -1 if it is unsupported - */ -int ValueForCharset(CharacterSet charset); - /** * @param name character set ECI encoding name * @return {@code CharacterSet} representing ECI of given value, or {@code CharacterSet::Unknown} if it is * unsupported */ -CharacterSet CharsetFromName(const char* name); - -/** - * @param name character set ECI encoding name - * @param encodingDefault default {@code CharacterSet} encoding to return if name is empty or unsupported - * @return {@code CharacterSet} representing ECI for character encoding - */ -CharacterSet InitEncoding(const std::string& name, CharacterSet encodingDefault = CharacterSet::ISO8859_1); - -/** - * @param eci ECI requested, which if different when resolved to the existing {@code CharacterSet} encoding will - * cause conversion to occur - * @param encoded Unicode buffer to append the data to if conversion occurs - * @param data buffer to be converted and appended to Unicode buffer and then cleared if conversion occurs - * @param encoding existing {@code CharacterSet} encoding to use for conversion if conversion occurs - * @return {@code CharacterSet} representing ECI for new character encoding if changed, or existing encoding if not - */ -CharacterSet OnChangeAppendReset(const int eci, std::wstring& encoded, std::string& data, CharacterSet encoding); +[[deprecated]] inline CharacterSet CharsetFromName(const char* name) { return CharacterSetFromString(name); } } // namespace CharacterSetECI } // namespace ZXing diff --git a/core/src/ConcentricFinder.cpp b/core/src/ConcentricFinder.cpp index 66ece3d655..494971de51 100644 --- a/core/src/ConcentricFinder.cpp +++ b/core/src/ConcentricFinder.cpp @@ -1,22 +1,12 @@ /* * Copyright 2020 Axel Waggershauser -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "ConcentricFinder.h" #include "LogMatrix.h" +#include "RegressionLine.h" namespace ZXing { @@ -96,6 +86,10 @@ std::optional CenterOfRings(const BitMatrix& image, PointI center, int r std::optional FinetuneConcentricPatternCenter(const BitMatrix& image, PointF center, int range, int finderPatternSize) { + // make sure we have at least one path of white around the center + if (!CenterOfRing(image, PointI(center), range, 1)) + return {}; + auto res = CenterOfRings(image, PointI(center), range, finderPatternSize / 2); if (!res || !image.get(*res)) res = CenterOfDoubleCross(image, PointI(center), range, finderPatternSize / 2 + 1); @@ -106,4 +100,96 @@ std::optional FinetuneConcentricPatternCenter(const BitMatrix& image, Po return res; } +static std::vector CollectRingPoints(const BitMatrix& image, PointF center, int range, int edgeIndex, bool backup) +{ + PointI centerI(center); + BitMatrixCursorI cur(image, centerI, {0, 1}); + cur.stepToEdge(edgeIndex, range, backup); + cur.turnRight(); // move clock wise and keep edge on the right/left depending on backup + const auto edgeDir = backup ? Direction::LEFT : Direction::RIGHT; + + uint32_t neighbourMask = 0; + auto start = cur.p; + std::vector points; + points.reserve(4 * range); + + do { + log(cur.p, 4); + points.push_back(centered(cur.p)); + + // find out if we come full circle around the center. 8 bits have to be set in the end. + neighbourMask |= (1 << (4 + dot(bresenhamDirection(cur.p - centerI), PointI(1, 3)))); + + if (!cur.stepAlongEdge(edgeDir)) + return {}; + + // use L-inf norm, simply because it is a lot faster than L2-norm and sufficiently accurate + if (maxAbsComponent(cur.p - center) > range || centerI == cur.p || Size(points) > 4 * 2 * range) + return {}; + + } while (cur.p != start); + + if (neighbourMask != 0b111101111) + return {}; + + return points; +} + +static QuadrilateralF FitQadrilateralToPoints(PointF center, std::vector& points) +{ + auto dist2Center = [c = center](auto a, auto b) { return distance(a, c) < distance(b, c); }; + // rotate points such that the first one is the furthest away from the center (hence, a corner) + std::rotate(points.begin(), std::max_element(points.begin(), points.end(), dist2Center), points.end()); + + std::array corners; + corners[0] = &points[0]; + // find the oposite corner by looking for the farthest point near the oposite point + corners[2] = std::max_element(&points[Size(points) * 3 / 8], &points[Size(points) * 5 / 8], dist2Center); + + // find the two in between corners by looking for the points farthest from the long diagonal + auto dist2Diagonal = [l = RegressionLine(*corners[0], *corners[2])](auto a, auto b) { return l.distance(a) < l.distance(b); }; + corners[1] = std::max_element(&points[Size(points) * 1 / 8], &points[Size(points) * 3 / 8], dist2Diagonal); + corners[3] = std::max_element(&points[Size(points) * 5 / 8], &points[Size(points) * 7 / 8], dist2Diagonal); + + std::array lines{RegressionLine{corners[0] + 1, corners[1]}, RegressionLine{corners[1] + 1, corners[2]}, + RegressionLine{corners[2] + 1, corners[3]}, RegressionLine{corners[3] + 1, &points.back() + 1}}; + + QuadrilateralF res; + for (int i = 0; i < 4; ++i) + res[i] = intersect(lines[i], lines[(i + 1) % 4]); + + return res; +} + +std::optional FindConcentricPatternCorners(const BitMatrix& image, PointF center, int range, int lineIndex) +{ + auto innerPoints = CollectRingPoints(image, center, range, lineIndex, false); + auto outerPoints = CollectRingPoints(image, center, range, lineIndex + 1, true); + + if (innerPoints.empty() || outerPoints.empty()) + return {}; + + auto innerCorners = FitQadrilateralToPoints(center, innerPoints); + auto outerCorners = FitQadrilateralToPoints(center, outerPoints); + + auto dist2First = [c = innerCorners[0]](auto a, auto b) { return distance(a, c) < distance(b, c); }; + // rotate points such that the the two topLeft points are closest to each other + std::rotate(outerCorners.begin(), std::min_element(outerCorners.begin(), outerCorners.end(), dist2First), outerCorners.end()); + + QuadrilateralF res; + for (int i=0; i<4; ++i) + res[i] = (innerCorners[i] + outerCorners[i]) / 2; + + for (auto p : innerCorners) + log(p, 3); + + for (auto p : outerCorners) + log(p, 3); + + for (auto p : res) + log(p, 3); + + return res; +} + } // ZXing diff --git a/core/src/ConcentricFinder.h b/core/src/ConcentricFinder.h index 1cfbb6c825..ab86da8a1f 100644 --- a/core/src/ConcentricFinder.h +++ b/core/src/ConcentricFinder.h @@ -1,23 +1,14 @@ -#pragma once /* * Copyright 2020 Axel Waggershauser -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include "BitMatrixCursor.h" #include "Pattern.h" -#include "ZXContainerAlgorithms.h" +#include "Quadrilateral.h" +#include "ZXAlgorithms.h" #include @@ -76,6 +67,8 @@ std::optional CenterOfRing(const BitMatrix& image, PointI center, int ra std::optional FinetuneConcentricPatternCenter(const BitMatrix& image, PointF center, int range, int finderPatternSize); +std::optional FindConcentricPatternCorners(const BitMatrix& image, PointF center, int range, int ringIndex); + struct ConcentricPattern : public PointF { int size = 0; diff --git a/core/src/Content.cpp b/core/src/Content.cpp new file mode 100644 index 0000000000..00ea9b3217 --- /dev/null +++ b/core/src/Content.cpp @@ -0,0 +1,231 @@ +/* + * Copyright 2022 Axel Waggershauser +*/ +// SPDX-License-Identifier: Apache-2.0 + +#include "Content.h" + +#include "CharacterSet.h" +#include "ECI.h" +#include "GS1.h" +#include "TextDecoder.h" +#include "TextUtfEncoding.h" +#include "ZXAlgorithms.h" + +namespace ZXing { + +std::string ToString(ContentType type) +{ + const char* t2s[] = {"Text", "Binary", "Mixed", "GS1", "ISO15434", "UnknownECI"}; + return t2s[static_cast(type)]; +} + +template +void Content::ForEachECIBlock(FUNC func) const +{ + ECI defaultECI = hasECI ? ECI::ISO8859_1 : ECI::Unknown; + if (encodings.empty()) + func(defaultECI, 0, Size(bytes)); + else if (encodings.front().pos != 0) + func(defaultECI, 0, encodings.front().pos); + + for (int i = 0; i < Size(encodings); ++i) { + auto [eci, start] = encodings[i]; + int end = i + 1 == Size(encodings) ? Size(bytes) : encodings[i + 1].pos; + + if (start != end) + func(eci, start, end); + } +} + +void Content::switchEncoding(ECI eci, bool isECI) +{ + // remove all non-ECI entries on first ECI entry + if (isECI && !hasECI) + encodings.clear(); + if (isECI || !hasECI) + encodings.push_back({eci, Size(bytes)}); + + hasECI |= isECI; +} + +Content::Content() {} + +Content::Content(ByteArray&& bytes, SymbologyIdentifier si, std::string ai) + : bytes(std::move(bytes)), applicationIndicator(std::move(ai)), symbology(si) +{} + +void Content::switchEncoding(CharacterSet cs) +{ + switchEncoding(ToECI(cs), false); +} + +void Content::append(const Content& other) +{ + if (!hasECI && other.hasECI) + encodings.clear(); + if (other.hasECI || !hasECI) + for (auto& e : other.encodings) + encodings.push_back({e.eci, Size(bytes) + e.pos}); + append(other.bytes); + + hasECI |= other.hasECI; +} + +void Content::erase(int pos, int n) +{ + bytes.erase(bytes.begin() + pos, bytes.begin() + pos + n); + for (auto& e : encodings) + if (e.pos > pos) + pos -= n; +} + +void Content::insert(int pos, const std::string& str) +{ + bytes.insert(bytes.begin() + pos, str.begin(), str.end()); + for (auto& e : encodings) + if (e.pos > pos) + pos += Size(str); +} + +bool Content::canProcess() const +{ + return std::all_of(encodings.begin(), encodings.end(), [](Encoding e) { return CanProcess(e.eci); }); +} + +std::wstring Content::render(bool withECI) const +{ + if (empty() || !canProcess()) + return {}; + + std::wstring res; + if (withECI) + res = TextDecoder::FromLatin1(symbology.toString(true)); + ECI lastECI = ECI::Unknown; + auto fallbackCS = CharacterSetFromString(defaultCharset); + if (!hasECI && fallbackCS == CharacterSet::Unknown) + fallbackCS = guessEncoding(); + + ForEachECIBlock([&](ECI eci, int begin, int end) { + // first determine how to decode the content (choose character set) + // * eci == ECI::Unknown implies !hasECI and we guess + // * if !IsText(eci) the ToCharcterSet(eci) will return Unknown and we decode as binary + CharacterSet cs = eci == ECI::Unknown ? fallbackCS : ToCharacterSet(eci); + + if (withECI) { + // then find the eci to report back in the ECI designator + if (IsText(ToECI(cs))) // everything decoded as text is reported as utf8 + eci = ECI::UTF8; + else if (eci == ECI::Unknown) // implies !hasECI and fallbackCS is Unknown or Binary + eci = ECI::Binary; + + if (lastECI != eci) + TextDecoder::AppendLatin1(res, ToString(eci)); + lastECI = eci; + + std::wstring tmp; + TextDecoder::Append(tmp, bytes.data() + begin, end - begin, cs); + for (auto c : tmp) { + res += c; + if (c == L'\\') // in the ECI protocol a '\' has to be doubled + res += c; + } + } else { + TextDecoder::Append(res, bytes.data() + begin, end - begin, cs); + } + }); + + return res; +} + +std::string Content::text(TextMode mode) const +{ + switch(mode) { + case TextMode::Utf8: return TextUtfEncoding::ToUtf8(render(false)); + case TextMode::Utf8ECI: return TextUtfEncoding::ToUtf8(render(true)); + case TextMode::HRI: + if (applicationIndicator == "GS1") + return HRIFromGS1(text(TextMode::Utf8)); + else if (type() == ContentType::Text) + return text(TextMode::Utf8); + else + return text(TextMode::Escaped); + case TextMode::Hex: return ToHex(bytes); + case TextMode::Escaped: return TextUtfEncoding::ToUtf8(render(false), true); + } + + return {}; // silence compiler warning +} + +ByteArray Content::bytesECI() const +{ + if (empty()) + return {}; + + std::string res = symbology.toString(true); + + ForEachECIBlock([&](ECI eci, int begin, int end) { + if (hasECI) + res += ToString(eci); + + for (int i = begin; i != end; ++i) { + char c = static_cast(bytes[i]); + res += c; + if (c == '\\') // in the ECI protocol a '\' has to be doubled + res += c; + } + }); + + return ByteArray(res); +} + +CharacterSet Content::guessEncoding() const +{ + // assemble all blocks with unknown encoding + ByteArray input; + ForEachECIBlock([&](ECI eci, int begin, int end) { + if (eci == ECI::Unknown) + input.insert(input.end(), bytes.begin() + begin, bytes.begin() + end); + }); + + if (input.empty()) + return CharacterSet::Unknown; + + return TextDecoder::GuessEncoding(input.data(), input.size(), CharacterSet::ISO8859_1); +} + +ContentType Content::type() const +{ + if (empty()) + return ContentType::Text; + + if (!canProcess()) + return ContentType::UnknownECI; + + if (applicationIndicator == "GS1") + return ContentType::GS1; + + // check for the absolut minimum of a ISO 15434 conforming message ("[)>" + RS + digit + digit) + if (bytes.size() > 6 && bytes.asString(0, 4) == "[)>\x1E" && std::isdigit(bytes[4]) && std::isdigit(bytes[5])) + return ContentType::ISO15434; + + ECI fallback = ToECI(guessEncoding()); + std::vector binaryECIs; + ForEachECIBlock([&](ECI eci, int begin, int end) { + if (eci == ECI::Unknown) + eci = fallback; + binaryECIs.push_back((!IsText(eci) + || (ToInt(eci) > 0 && ToInt(eci) < 28 && ToInt(eci) != 25 + && std::any_of(bytes.begin() + begin, bytes.begin() + end, + [](auto c) { return c < 0x20 && c != 0xa && c != 0xd; })))); + }); + + if (!Contains(binaryECIs, true)) + return ContentType::Text; + if (!Contains(binaryECIs, false)) + return ContentType::Binary; + + return ContentType::Mixed; +} + +} // namespace ZXing diff --git a/core/src/Content.h b/core/src/Content.h new file mode 100644 index 0000000000..d330ca1312 --- /dev/null +++ b/core/src/Content.h @@ -0,0 +1,87 @@ +/* +* Copyright 2022 Axel Waggershauser +*/ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include "ByteArray.h" + +#include +#include + +namespace ZXing { + +enum class ECI : int; +enum class CharacterSet; + +enum class ContentType { Text, Binary, Mixed, GS1, ISO15434, UnknownECI }; +enum class TextMode { Utf8, Utf8ECI, HRI, Hex, Escaped }; + +std::string ToString(ContentType type); + +struct SymbologyIdentifier +{ + char code = 0, modifier = 0; + int eciModifierOffset = 0; + + std::string toString(bool hasECI = false) const + { + return code ? ']' + std::string(1, code) + static_cast(modifier + eciModifierOffset * hasECI) : std::string(); + } +}; + +class Content +{ + template + void ForEachECIBlock(FUNC f) const; + + void switchEncoding(ECI eci, bool isECI); + std::wstring render(bool withECI) const; + +public: + struct Encoding + { + ECI eci; + int pos; + }; + + ByteArray bytes; + std::vector encodings; + std::string defaultCharset; + std::string applicationIndicator; + SymbologyIdentifier symbology; + bool hasECI = false; + + Content(); + Content(ByteArray&& bytes, SymbologyIdentifier si, std::string ai = {}); + + void switchEncoding(ECI eci) { switchEncoding(eci, true); } + void switchEncoding(CharacterSet cs); + + void reserve(int count) { bytes.reserve(bytes.size() + count); } + + void push_back(uint8_t val) { bytes.push_back(val); } + void append(const std::string& str) { bytes.insert(bytes.end(), str.begin(), str.end()); } + void append(const ByteArray& ba) { bytes.insert(bytes.end(), ba.begin(), ba.end()); } + void append(const Content& other); + + void operator+=(char val) { push_back(val); } + void operator+=(const std::string& str) { append(str); } + + void erase(int pos, int n); + void insert(int pos, const std::string& str); + + bool empty() const { return bytes.empty(); } + bool canProcess() const; + + std::string text(TextMode mode) const; + std::wstring utf16() const { return render(false); } + std::string utf8() const { return text(TextMode::Utf8); } + + ByteArray bytesECI() const; + CharacterSet guessEncoding() const; + ContentType type() const; +}; + +} // ZXing diff --git a/core/src/CustomData.h b/core/src/CustomData.h index e80dbf533b..6578af5260 100644 --- a/core/src/CustomData.h +++ b/core/src/CustomData.h @@ -1,20 +1,10 @@ -#pragma once /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once namespace ZXing { diff --git a/core/src/DecodeHints.cpp b/core/src/DecodeHints.cpp index 25f34b717c..72ded6073c 100644 --- a/core/src/DecodeHints.cpp +++ b/core/src/DecodeHints.cpp @@ -1,19 +1,8 @@ /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "DecodeHints.h" diff --git a/core/src/DecodeHints.h b/core/src/DecodeHints.h index d4ef5e6e32..9668a09848 100644 --- a/core/src/DecodeHints.h +++ b/core/src/DecodeHints.h @@ -1,21 +1,11 @@ -#pragma once /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors * Copyright 2020 Axel Waggershauser -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include "BarcodeFormat.h" @@ -34,8 +24,8 @@ namespace ZXing { */ enum class Binarizer : unsigned char // needs to unsigned for the bitfield below to work, uint8_t fails as well { - LocalAverage, ///< T = average of neighboring pixels for 2D and GlobalHistogram for 1D (HybridBinarizer) - GlobalHistogram, ///< T = valley between the 2 largest peaks in the histogram (per line in 1D case) + LocalAverage, ///< T = average of neighboring pixels for matrix and GlobalHistogram for linear (HybridBinarizer) + GlobalHistogram, ///< T = valley between the 2 largest peaks in the histogram (per line in linear case) FixedThreshold, ///< T = 127 BoolCast, ///< T = 0, fastest possible }; @@ -49,36 +39,45 @@ enum class EanAddOnSymbol : unsigned char // see above class DecodeHints { - bool _tryHarder : 1; - bool _tryRotate : 1; - bool _tryDownscale : 1; - bool _isPure : 1; - bool _tryCode39ExtendedMode : 1; - bool _validateCode39CheckSum : 1; - bool _validateITFCheckSum : 1; - bool _returnCodabarStartEnd : 1; - Binarizer _binarizer : 2; + bool _tryHarder : 1; + bool _tryRotate : 1; + bool _tryDownscale : 1; + bool _isPure : 1; + bool _tryCode39ExtendedMode : 1; + bool _validateCode39CheckSum : 1; + bool _validateITFCheckSum : 1; + bool _returnCodabarStartEnd : 1; + bool _returnErrors : 1; EanAddOnSymbol _eanAddOnSymbol : 2; + Binarizer _binarizer : 2; - std::string _characterSet; - std::vector _allowedLengths; - BarcodeFormats _formats = BarcodeFormat::None; + uint8_t _minLineCount = 2; + uint8_t _maxNumberOfSymbols = 0xff; + uint8_t _downscaleFactor = 3; uint16_t _downscaleThreshold = 500; - uint8_t _downscaleFactor = 3; - uint8_t _minLineCount = 2; - uint8_t _maxNumberOfSymbols = 0xff; + BarcodeFormats _formats = BarcodeFormat::None; + std::string _characterSet; public: - // bitfields don't get default initialized to 0. + // bitfields don't get default initialized to 0 before c++20 DecodeHints() - : _tryHarder(1), _tryRotate(1), _tryDownscale(1), _isPure(0), _tryCode39ExtendedMode(0), - _validateCode39CheckSum(0), _validateITFCheckSum(0), _returnCodabarStartEnd(0), - _binarizer(Binarizer::LocalAverage), _eanAddOnSymbol(EanAddOnSymbol::Ignore) + : _tryHarder(1), + _tryRotate(1), + _tryDownscale(1), + _isPure(0), + _tryCode39ExtendedMode(0), + _validateCode39CheckSum(0), + _validateITFCheckSum(0), + _returnCodabarStartEnd(0), + _returnErrors(0), + _eanAddOnSymbol(EanAddOnSymbol::Ignore), + _binarizer(Binarizer::LocalAverage) {} #define ZX_PROPERTY(TYPE, GETTER, SETTER) \ TYPE GETTER() const noexcept { return _##GETTER; } \ - DecodeHints& SETTER(TYPE v) { return _##GETTER = std::move(v), *this; } + DecodeHints& SETTER(TYPE v)& { return _##GETTER = std::move(v), *this; } \ + DecodeHints&& SETTER(TYPE v)&& { return _##GETTER = std::move(v), std::move(*this); } /// Specify a set of BarcodeFormats that should be searched for, the default is all supported formats. ZX_PROPERTY(BarcodeFormats, formats, setFormats) @@ -106,18 +105,15 @@ class DecodeHints // WARNING: this API is experimental and may change/disappear ZX_PROPERTY(uint8_t, downscaleFactor, setDownscaleFactor) - /// The number of scan lines in a 1D barcode that have to be equal to accept the result, default is 2 + /// The number of scan lines in a linear barcode that have to be equal to accept the result, default is 2 ZX_PROPERTY(uint8_t, minLineCount, setMinLineCount) /// The maximum number of symbols (barcodes) to detect / look for in the image with ReadBarcodes ZX_PROPERTY(uint8_t, maxNumberOfSymbols, setMaxNumberOfSymbols) - /// Specifies what character encoding to use when decoding, where applicable. + /// Specifies fallback character set to use instead of auto-detecting it (when applicable) ZX_PROPERTY(std::string, characterSet, setCharacterSet) - /// Allowed lengths of encoded data -- reject anything else.. - ZX_PROPERTY(std::vector, allowedLengths, setAllowedLengths) - /// If true, the Code-39 reader will try to read extended mode. ZX_PROPERTY(bool, tryCode39ExtendedMode, setTryCode39ExtendedMode) @@ -127,29 +123,31 @@ class DecodeHints /// Assume ITF codes employ a GS1 check digit and validate it. ZX_PROPERTY(bool, validateITFCheckSum, setValidateITFCheckSum) - /** - * If true, return the start and end digits in a Codabar barcode instead of stripping them. They - * are alpha, whereas the rest are numeric. By default, they are stripped, but this causes them - * to not be. - */ + /// If true, return the start and end chars in a Codabar barcode instead of stripping them. ZX_PROPERTY(bool, returnCodabarStartEnd, setReturnCodabarStartEnd) + /// If true, return the barcodes with errors as well (e.g. checksum errors, see @Result::error()) + ZX_PROPERTY(bool, returnErrors, setReturnErrors) + /// Specify whether to ignore, read or require EAN-2/5 add-on symbols while scanning EAN/UPC codes ZX_PROPERTY(EanAddOnSymbol, eanAddOnSymbol, setEanAddOnSymbol) #undef ZX_PROPERTY -#undef ZX_PROPERTY_DEPRECATED /// NOTE: used to affect FNC1 handling for Code 128 (aka GS1-128) but behavior now based on position of FNC1. [[deprecated]] bool assumeGS1() const noexcept { return true; } [[deprecated]] DecodeHints& setAssumeGS1(bool v [[maybe_unused]]) { return *this; } + /// NOTE: has not been in effect since at least 1.2 and no one noticed. + [[deprecated]] std::vector allowedLengths() const noexcept { return {}; } + [[deprecated]] DecodeHints& setAllowedLengths(const std::vector v [[maybe_unused]]) { return *this; } + /// NOTE: use validateCode39CheckSum [[deprecated]] bool assumeCode39CheckDigit() const noexcept { return validateCode39CheckSum(); } - [[deprecated]] DecodeHints& setAssumeCode39CheckDigit(bool v) { return setValidateCode39CheckSum(v); } + [[deprecated]] DecodeHints& setAssumeCode39CheckDigit(bool v) & { return setValidateCode39CheckSum(v); } - bool hasFormat(BarcodeFormats f) const noexcept { return _formats.testFlags(f); } - bool hasNoFormat() const noexcept { return _formats.empty(); } + bool hasFormat(BarcodeFormats f) const noexcept { return _formats.testFlags(f) || _formats.empty(); } + [[deprecated]] bool hasNoFormat() const noexcept { return _formats.empty(); } }; } // ZXing diff --git a/core/src/DecodeStatus.cpp b/core/src/DecodeStatus.cpp index 9f7ae1a8d2..8abff86b2d 100644 --- a/core/src/DecodeStatus.cpp +++ b/core/src/DecodeStatus.cpp @@ -1,18 +1,7 @@ /* * Copyright 2016 Nu-book Inc. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "DecodeStatus.h" diff --git a/core/src/DecodeStatus.h b/core/src/DecodeStatus.h index fe321dc3b2..80a52ba3c3 100644 --- a/core/src/DecodeStatus.h +++ b/core/src/DecodeStatus.h @@ -1,19 +1,9 @@ -#pragma once /* * Copyright 2016 Nu-book Inc. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once namespace ZXing { @@ -25,17 +15,17 @@ enum class DecodeStatus ChecksumError, }; -inline bool StatusIsOK(DecodeStatus status) +[[deprecated]] inline bool StatusIsOK(DecodeStatus status) { return status == DecodeStatus::NoError; } -inline bool StatusIsError(DecodeStatus status) +[[deprecated]] inline bool StatusIsError(DecodeStatus status) { return status != DecodeStatus::NoError; } -inline const char* ToString(DecodeStatus status) +[[deprecated]] inline const char* ToString(DecodeStatus status) { constexpr const char* names[] = {"NoError", "NotFound", "FormatError", "ChecksumError"}; return names[static_cast(status)]; diff --git a/core/src/DecoderResult.h b/core/src/DecoderResult.h index 30abc8c772..2b916d0249 100644 --- a/core/src/DecoderResult.h +++ b/core/src/DecoderResult.h @@ -1,25 +1,16 @@ -#pragma once /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include "ByteArray.h" -#include "DecodeStatus.h" +#include "Content.h" +#include "Error.h" #include "StructuredAppend.h" -#include "ZXContainerAlgorithms.h" +#include "ZXAlgorithms.h" #include #include @@ -29,48 +20,46 @@ namespace ZXing { class CustomData; -/** -*

Encapsulates the result of decoding a matrix of bits. This typically -* applies to 2D barcode formats. For now it contains the raw bytes obtained, -* as well as a string interpretation of those bytes, if applicable.

-* -* @author Sean Owen -*/ class DecoderResult { - DecodeStatus _status = DecodeStatus::NoError; ByteArray _rawBytes; + Content _content; int _numBits = 0; - std::wstring _text; - std::wstring _ecLevel; - int _errorsCorrected = -1; - int _erasures = -1; - std::string _symbologyIdentifier; + std::string _ecLevel; + int _lineCount = 0; StructuredAppendInfo _structuredAppend; bool _isMirrored = false; bool _readerInit = false; + Error _error; std::shared_ptr _extra; DecoderResult(const DecoderResult &) = delete; DecoderResult& operator=(const DecoderResult &) = delete; public: - DecoderResult(DecodeStatus status) : _status(status) {} - DecoderResult(ByteArray&& rawBytes, std::wstring&& text) : _rawBytes(std::move(rawBytes)), _text(std::move(text)) { + DecoderResult() = default; + DecoderResult(Error error) : _error(std::move(error)) {} + DecoderResult(ByteArray&& rawBytes, Content&& bytes) : _rawBytes(std::move(rawBytes)), _content(std::move(bytes)) + { _numBits = 8 * Size(_rawBytes); } - DecoderResult() = default; DecoderResult(DecoderResult&&) noexcept = default; DecoderResult& operator=(DecoderResult&&) = default; - bool isValid() const { return StatusIsOK(_status); } - DecodeStatus errorCode() const { return _status; } + bool isValid(bool includeErrors = false) const + { + return _content.symbology.code != 0 && (!_error || includeErrors); + } const ByteArray& rawBytes() const & { return _rawBytes; } ByteArray&& rawBytes() && { return std::move(_rawBytes); } - const std::wstring& text() const & { return _text; } - std::wstring&& text() && { return std::move(_text); } + const Content& content() const & { return _content; } + Content&& content() && { return std::move(_content); } + + // to keep the unit tests happy for now: + std::wstring text() const { return _content.utf16(); } + std::string symbologyIdentifier() const { return _content.symbology.toString(false); } // Simple macro to set up getter/setter methods that save lots of boilerplate. // It sets up a standard 'const & () const', 2 setters for setting lvalues via @@ -88,11 +77,10 @@ class DecoderResult DecoderResult&& SETTER(TYPE&& v) && { _##GETTER = std::move(v); return std::move(*this); } ZX_PROPERTY(int, numBits, setNumBits) - ZX_PROPERTY(std::wstring, ecLevel, setEcLevel) - ZX_PROPERTY(int, errorsCorrected, setErrorsCorrected) - ZX_PROPERTY(int, erasures, setErasures) - ZX_PROPERTY(std::string, symbologyIdentifier, setSymbologyIdentifier) + ZX_PROPERTY(std::string, ecLevel, setEcLevel) + ZX_PROPERTY(int, lineCount, setLineCount) ZX_PROPERTY(StructuredAppendInfo, structuredAppend, setStructuredAppend) + ZX_PROPERTY(Error, error, setError) ZX_PROPERTY(bool, isMirrored, setIsMirrored) ZX_PROPERTY(bool, readerInit, setReaderInit) ZX_PROPERTY(std::shared_ptr, extra, setExtra) diff --git a/core/src/DetectorResult.h b/core/src/DetectorResult.h index a3549c0505..dbeffe0b02 100644 --- a/core/src/DetectorResult.h +++ b/core/src/DetectorResult.h @@ -1,20 +1,10 @@ -#pragma once /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include "BitMatrix.h" #include "Quadrilateral.h" @@ -41,9 +31,7 @@ class DetectorResult DetectorResult(DetectorResult&&) = default; DetectorResult& operator=(DetectorResult&&) = default; - DetectorResult(BitMatrix&& bits, QuadrilateralI&& position) - : _bits(std::move(bits)), _position(std::move(position)) - {} + DetectorResult(BitMatrix&& bits, QuadrilateralI&& position) : _bits(std::move(bits)), _position(std::move(position)) {} const BitMatrix& bits() const & { return _bits; } BitMatrix&& bits() && { return std::move(_bits); } diff --git a/core/src/ECI.cpp b/core/src/ECI.cpp new file mode 100644 index 0000000000..a8ee347009 --- /dev/null +++ b/core/src/ECI.cpp @@ -0,0 +1,76 @@ +/* +* Copyright 2022 Axel Waggershauser +*/ +// SPDX-License-Identifier: Apache-2.0 + +#include "ECI.h" + +#include +#include +#include + +namespace ZXing { + +static const std::map ECI_TO_CHARSET = { + {ECI(0), CharacterSet::Cp437}, // Obsolete + {ECI(1), CharacterSet::ISO8859_1}, // Obsolete + {ECI(2), CharacterSet::Cp437}, // Obsolete but still used by PDF417 Macro fields (ISO/IEC 15438:2015 Annex H.2.3) + {ECI::ISO8859_1, CharacterSet::ISO8859_1}, + {ECI::ISO8859_2, CharacterSet::ISO8859_2}, + {ECI::ISO8859_3, CharacterSet::ISO8859_3}, + {ECI::ISO8859_4, CharacterSet::ISO8859_4}, + {ECI::ISO8859_5, CharacterSet::ISO8859_5}, + {ECI::ISO8859_6, CharacterSet::ISO8859_6}, + {ECI::ISO8859_7, CharacterSet::ISO8859_7}, + {ECI::ISO8859_8, CharacterSet::ISO8859_8}, + {ECI::ISO8859_9, CharacterSet::ISO8859_9}, + {ECI::ISO8859_10, CharacterSet::ISO8859_10}, + {ECI::ISO8859_11, CharacterSet::ISO8859_11}, + {ECI::ISO8859_13, CharacterSet::ISO8859_13}, + {ECI::ISO8859_14, CharacterSet::ISO8859_14}, + {ECI::ISO8859_15, CharacterSet::ISO8859_15}, + {ECI::ISO8859_16, CharacterSet::ISO8859_16}, + {ECI::Shift_JIS, CharacterSet::Shift_JIS}, + {ECI::Cp1250, CharacterSet::Cp1250}, + {ECI::Cp1251, CharacterSet::Cp1251}, + {ECI::Cp1252, CharacterSet::Cp1252}, + {ECI::Cp1256, CharacterSet::Cp1256}, + {ECI::UTF16, CharacterSet::UnicodeBig}, + {ECI::UTF8, CharacterSet::UTF8}, + {ECI::ASCII, CharacterSet::ASCII}, + {ECI::Big5, CharacterSet::Big5}, + {ECI::GB18030, CharacterSet::GB18030}, + {ECI::EUC_KR, CharacterSet::EUC_KR}, + {ECI(170), CharacterSet::ASCII}, + {ECI::Binary, CharacterSet::BINARY}, +}; + +std::string ToString(ECI eci) +{ + std::ostringstream oss; + oss << '\\' << std::setw(6) << std::setfill('0') << ToInt(eci); + return oss.str(); +} + +CharacterSet ToCharacterSet(ECI eci) +{ + if (auto it = ECI_TO_CHARSET.find(eci); it != ECI_TO_CHARSET.end()) + return it->second; + + return CharacterSet::Unknown; +} + +ECI ToECI(CharacterSet cs) +{ + // Special case ISO8859_1 to avoid obsolete ECI 1 + if (cs == CharacterSet::ISO8859_1) + return ECI::ISO8859_1; + + for (auto& [key, value] : ECI_TO_CHARSET) + if (value == cs) + return key; + + return ECI::Unknown; +} + +} // namespace ZXing diff --git a/core/src/ECI.h b/core/src/ECI.h new file mode 100644 index 0000000000..bb780324b0 --- /dev/null +++ b/core/src/ECI.h @@ -0,0 +1,72 @@ +/* +* Copyright 2022 Axel Waggershauser +*/ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include "CharacterSet.h" + +#include + +namespace ZXing { + +enum class ECI : int +{ + Unknown = -1, + ISO8859_1 = 3, + ISO8859_2 = 4, + ISO8859_3 = 5, + ISO8859_4 = 6, + ISO8859_5 = 7, + ISO8859_6 = 8, + ISO8859_7 = 9, + ISO8859_8 = 10, + ISO8859_9 = 11, + ISO8859_10 = 12, + ISO8859_11 = 13, + ISO8859_13 = 15, + ISO8859_14 = 16, + ISO8859_15 = 17, + ISO8859_16 = 18, + Shift_JIS = 20, + Cp1250 = 21, + Cp1251 = 22, + Cp1252 = 23, + Cp1256 = 24, + UTF16 = 25, + UTF8 = 26, + ASCII = 27, + Big5 = 28, + GB18030 = 29, + EUC_KR = 30, + Binary = 899 +}; + +inline constexpr int ToInt(ECI eci) +{ + return static_cast(eci); +} + +inline constexpr bool IsText(ECI eci) +{ + return ToInt(eci) >= 0 && ToInt(eci) <= 32; +} + +inline constexpr bool CanProcess(ECI eci) +{ + // see https://github.com/nu-book/zxing-cpp/commit/d8587545434d533c4e568181e1c12ef04a8e42d9#r74864359 + return ToInt(eci) <= 899; +} + +/** + * @brief ToString converts the numerical ECI value to a 7 character string as used in the ECI protocol + * @return e.g. "\000020" + */ +std::string ToString(ECI eci); + +CharacterSet ToCharacterSet(ECI eci); + +ECI ToECI(CharacterSet cs); + +} // namespace ZXing diff --git a/core/src/Error.h b/core/src/Error.h new file mode 100644 index 0000000000..207caf3d5d --- /dev/null +++ b/core/src/Error.h @@ -0,0 +1,61 @@ +/* + * Copyright 2022 Axel Waggershauser + */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include + +namespace ZXing { + +class Error +{ +public: + enum class Type { None, Format, Checksum, Unsupported }; + Type type() const noexcept { return _type; } + const std::string& msg() const noexcept { return _msg; } + explicit operator bool() const noexcept { return _type != Type::None; } + std::string location() const noexcept + { + return _file.empty() ? "" : _file.substr(_file.find_last_of("/\\") + 1) + ":" + std::to_string(_line); + } + + Error() = default; + Error(Type type, std::string msg = {}) : _type(type), _msg(std::move(msg)) {} + Error(std::string file, int line, Type type, std::string msg = {}) + : _type(type), _msg(std::move(msg)), _file(std::move(file)), _line(line) + {} + + static constexpr auto Format = Type::Format; + static constexpr auto Checksum = Type::Checksum; + static constexpr auto Unsupported = Type::Unsupported; + +protected: + Type _type = Type::None; + std::string _msg; + std::string _file; + int _line = -1; +}; + +inline bool operator==(const Error& e, Error::Type t) noexcept { return e.type() == t; } +inline bool operator!=(const Error& e, Error::Type t) noexcept { return !(e == t); } +inline bool operator==(Error::Type t, const Error& e) noexcept { return e.type() == t; } +inline bool operator!=(Error::Type t, const Error& e) noexcept { return !(t == e); } + +#define FormatError(...) Error(__FILE__, __LINE__, Error::Format, std::string(__VA_ARGS__)) +#define ChecksumError(...) Error(__FILE__, __LINE__, Error::Checksum, std::string(__VA_ARGS__)) +#define UnsupportedError(...) Error(__FILE__, __LINE__, Error::Unsupported, std::string(__VA_ARGS__)) + +inline std::string ToString(const Error& e) +{ + const char* name[] = {"", "FormatError", "ChecksumError", "Unsupported"}; + std::string ret = name[static_cast(e.type())]; + if (!e.msg().empty()) + ret += " (" + e.msg() + ")"; + if (!e.location().empty()) + ret += " @ " + e.location(); + return ret; +} + +} diff --git a/core/src/Flags.h b/core/src/Flags.h index 616082d85b..c5f2e2a8ab 100644 --- a/core/src/Flags.h +++ b/core/src/Flags.h @@ -1,19 +1,9 @@ -#pragma once /* * Copyright 2020 Axel Waggershauser -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include "BitHacks.h" diff --git a/core/src/oned/rss/ODRSSFieldParser.cpp b/core/src/GS1.cpp similarity index 58% rename from core/src/oned/rss/ODRSSFieldParser.cpp rename to core/src/GS1.cpp index ef8552b847..1b5994abfb 100644 --- a/core/src/oned/rss/ODRSSFieldParser.cpp +++ b/core/src/GS1.cpp @@ -1,38 +1,30 @@ /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. +* Copyright 2022 Axel Waggershauser */ +// SPDX-License-Identifier: Apache-2.0 -#include "ODRSSFieldParser.h" +#include "GS1.h" -#include "DecodeStatus.h" -#include "ZXContainerAlgorithms.h" +#include "ZXAlgorithms.h" -#include -#include -#include -#include - -namespace ZXing::OneD::DataBar { - - //private static final Object VARIABLE_LENGTH = new Object(); +namespace ZXing { struct AiInfo { - const char* aiPrefix; - int fieldSize; // if negative, the length is variable and abs(length) give the max size + std::string_view aiPrefix; + int _fieldSize; // if negative, the length is variable and abs(length) give the max size + + bool isVariableLength() const noexcept { return _fieldSize < 0; } + int fieldSize() const noexcept { return std::abs(_fieldSize); } + int aiSize() const + { + if ((aiPrefix[0] == '3' && Contains("1234569", aiPrefix[1])) || aiPrefix == "703" || aiPrefix == "723") + return 4; + else + return Size(aiPrefix); + } }; // GS1 General Specifications Release 22.0 (Jan 22, 2022) @@ -241,48 +233,52 @@ static const AiInfo aiInfos[] = { { "8200", -70 }, }; -static size_t -AiSize(const char* aiPrefix) +std::string HRIFromGS1(const std::string& gs1) { - if ((aiPrefix[0] == '3' && Contains("1234569", aiPrefix[1])) || std::string(aiPrefix) == "703" - || std::string(aiPrefix) == "723") - return 4; - else - return strlen(aiPrefix); -} + //TODO: c++20 + auto starts_with = [](std::string_view str, std::string_view pre) { return str.substr(0, pre.size()) == pre; }; + constexpr char GS = 29; // GS character (29 / 0x1D) + std::string_view rem = gs1; + std::string res; -DecodeStatus -ParseFieldsInGeneralPurpose(const std::string &rawInfo, std::string& result) -{ - if (rawInfo.empty()) { - return DecodeStatus::NoError; - } + while (rem.size()) { + const AiInfo* i = FindIf(aiInfos, [&](const AiInfo& i) { return starts_with(rem, i.aiPrefix); }); + if (i == std::end(aiInfos)) + return {}; - auto starts_with = - [](const std::string& str, const char* pre) { return strncmp(pre, str.data(), strlen(pre)) == 0; }; + int aiSize = i->aiSize(); + if (Size(rem) < aiSize) + return {}; - const AiInfo* aiInfo = FindIf(aiInfos, [&](const AiInfo& i) { return starts_with(rawInfo, i.aiPrefix); }); - if (aiInfo == std::end(aiInfos)) - return DecodeStatus::NotFound; + res += '('; + res += rem.substr(0, aiSize); + res += ')'; + rem.remove_prefix(aiSize); - size_t aiSize = AiSize(aiInfo->aiPrefix); + int fieldSize = i->fieldSize(); + if (i->isVariableLength()) { + auto gsPos = rem.find(GS); +#if 1 + fieldSize = std::min(gsPos == std::string_view::npos ? Size(rem) : narrow_cast(gsPos), fieldSize); +#else + // TODO: ignore the 'max field size' part for now as it breaks rssexpanded-3/13.png? + fieldSize = gsPos == std::string_view::npos ? Size(rem) : narrow_cast(gsPos); +#endif + } + if (fieldSize == 0 || Size(rem) < fieldSize) + return {}; - // require at least one character in the variable field size case - if (rawInfo.length() < aiSize + std::max(1, aiInfo->fieldSize)) - return DecodeStatus::NotFound; + res += rem.substr(0, fieldSize); + rem.remove_prefix(fieldSize); - size_t fieldSize = aiInfo->fieldSize >= 0 - ? size_t(aiInfo->fieldSize) // fixed - : std::min(rawInfo.length() - aiSize, size_t(-aiInfo->fieldSize)); // variable + // See General Specification v22.0 Section 7.8.6.3: "...the processing routine SHALL tolerate a single separator character + // immediately following any element string, whether necessary or not..." + if (Size(rem) && rem.front() == GS) + rem.remove_prefix(1); + } - auto ai = rawInfo.substr(0, aiSize); - auto field = rawInfo.substr(aiSize, fieldSize); - auto remaining = rawInfo.substr(aiSize + fieldSize); - std::string parsedRemaining; - auto status = ParseFieldsInGeneralPurpose(remaining, parsedRemaining); - result = '(' + ai + ')' + field + parsedRemaining; - return status; + return res; } -} // namespace ZXing::OneD::DataBar +} // namespace ZXing diff --git a/core/src/GS1.h b/core/src/GS1.h new file mode 100644 index 0000000000..50b579a8a9 --- /dev/null +++ b/core/src/GS1.h @@ -0,0 +1,14 @@ +/* + * Copyright 2022 Axel Waggershauser + */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include + +namespace ZXing { + +std::string HRIFromGS1(const std::string& gs1); + +} // namespace ZXing diff --git a/core/src/GTIN.cpp b/core/src/GTIN.cpp index 3dc969a66c..252393dcbb 100644 --- a/core/src/GTIN.cpp +++ b/core/src/GTIN.cpp @@ -1,19 +1,8 @@ /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "GTIN.h" @@ -176,7 +165,7 @@ std::string LookupCountryIdentifier(const std::string& GTIN, const BarcodeFormat const std::string::size_type size = space != std::string::npos ? space : GTIN.size(); if (size != 14 && size != 13 && size != 12 && size != 8) - return std::string(); + return {}; // GTIN-14 leading packaging level indicator const int first = size == 14 ? 1 : 0; @@ -187,7 +176,7 @@ std::string LookupCountryIdentifier(const std::string& GTIN, const BarcodeFormat // 0000000 Restricted Circulation Numbers; 0000001-0000099 unused to avoid collision with GTIN-8 int prefix = std::stoi(GTIN.substr(first, 7 - implicitZero)); if (prefix >= 0 && prefix <= 99) - return std::string(); + return {}; // 00001-00009 US prefix = std::stoi(GTIN.substr(first, 5 - implicitZero)); @@ -204,7 +193,7 @@ std::string LookupCountryIdentifier(const std::string& GTIN, const BarcodeFormat // Special case EAN-8 for prefix < 100 (GS1 General Specifications Figure 1.4.3-1) if (size == 8 && format == BarcodeFormat::EAN8 && prefix <= 99) // Restricted Circulation Numbers - return std::string(); + return {}; const auto it = std::lower_bound(std::begin(COUNTRIES), std::end(COUNTRIES), CountryId{0, prefix, nullptr}); @@ -216,9 +205,9 @@ std::string EanAddOn(const Result& result) if (!(BarcodeFormat::EAN13 | BarcodeFormat::UPCA | BarcodeFormat::UPCE | BarcodeFormat::EAN8) .testFlag(result.format())) return {}; - auto txt = result.text(); - auto pos = txt.find(L' '); - return pos != std::wstring::npos ? TextUtfEncoding::ToUtf8(txt.substr(pos + 1)) : std::string(); + auto txt = result.bytes().asString(); + auto pos = txt.find(' '); + return pos != std::string::npos ? std::string(txt.substr(pos + 1)) : std::string(); } std::string IssueNr(const std::string& ean2AddOn) diff --git a/core/src/GTIN.h b/core/src/GTIN.h index 310da18c84..df9405c720 100644 --- a/core/src/GTIN.h +++ b/core/src/GTIN.h @@ -1,24 +1,14 @@ -#pragma once /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors * Copyright 2020 Axel Waggershauser -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include "BarcodeFormat.h" -#include "ZXContainerAlgorithms.h" +#include "ZXAlgorithms.h" #include diff --git a/core/src/Generator.h b/core/src/Generator.h new file mode 100644 index 0000000000..922af66d85 --- /dev/null +++ b/core/src/Generator.h @@ -0,0 +1,109 @@ +/* + * Copyright 2022 Axel Waggershauser + */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#ifdef __cpp_impl_coroutine +#include +#include + +// this code is based on https://en.cppreference.com/w/cpp/coroutine/coroutine_handle#Example +// but modified trying to prevent accidental copying of generated objects + +template +class Generator +{ +public: + struct promise_type + { + Generator get_return_object() { return Generator{Handle::from_promise(*this)}; } + static std::suspend_always initial_suspend() noexcept { return {}; } + static std::suspend_always final_suspend() noexcept { return {}; } + std::suspend_always yield_value(T&& value) noexcept + { + current_value = std::move(value); + return {}; + } +// void return_value(T&& value) noexcept { current_value = std::move(value); } + // Disallow co_await in generator coroutines. + void await_transform() = delete; + [[noreturn]] static void unhandled_exception() { throw; } + + std::optional current_value; + }; + + using Handle = std::coroutine_handle; + + explicit Generator(const Handle coroutine) : _coroutine{coroutine} {} + + Generator() = default; + ~Generator() + { + if (_coroutine) + _coroutine.destroy(); + } + + Generator(const Generator&) = delete; + Generator& operator=(const Generator&) = delete; + + Generator(Generator&& other) noexcept : _coroutine{other._coroutine} { other._coroutine = {}; } +// Generator& operator=(Generator&& other) noexcept +// { +// if (this != &other) { +// if (_coroutine) +// _coroutine.destroy(); + +// _coroutine = other._coroutine; +// other._coroutine = {}; +// } +// return *this; +// } + + // Range-based for loop support. + class Iter + { + public: + void operator++() { _coroutine.resume(); } + T&& operator*() const { return std::move(*_coroutine.promise().current_value); } + bool operator==(std::default_sentinel_t) const { return !_coroutine || _coroutine.done(); } + + explicit Iter(const Handle coroutine) : _coroutine{coroutine} {} + + private: + Handle _coroutine; + }; + + Iter begin() + { + if (_coroutine) + _coroutine.resume(); + + return Iter{_coroutine}; + } + std::default_sentinel_t end() { return {}; } + +private: + Handle _coroutine; +}; + +#endif + +/* +usage example: + +template +Generator range(T first, const T last) +{ + while (first < last) + co_yield first++; +} + +int main() +{ + for (const char i : range(65, 91)) + std::cout << i << ' '; + std::cout << '\n'; +} +*/ diff --git a/core/src/GenericGF.cpp b/core/src/GenericGF.cpp index 6e28b4fd80..d6c03ab056 100644 --- a/core/src/GenericGF.cpp +++ b/core/src/GenericGF.cpp @@ -1,19 +1,8 @@ /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "GenericGF.h" diff --git a/core/src/GenericGF.h b/core/src/GenericGF.h index 5c11f22aac..4f25b62564 100644 --- a/core/src/GenericGF.h +++ b/core/src/GenericGF.h @@ -1,20 +1,10 @@ -#pragma once /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include "GenericGFPoly.h" #include "ZXConfig.h" diff --git a/core/src/GenericGFPoly.cpp b/core/src/GenericGFPoly.cpp index 4fa4df5464..a2634f82d1 100644 --- a/core/src/GenericGFPoly.cpp +++ b/core/src/GenericGFPoly.cpp @@ -2,25 +2,14 @@ * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors * Copyright 2017 Axel Waggershauser -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "GenericGFPoly.h" #include "GenericGF.h" #include "ZXConfig.h" -#include "ZXContainerAlgorithms.h" +#include "ZXAlgorithms.h" #include #include diff --git a/core/src/GenericGFPoly.h b/core/src/GenericGFPoly.h index f87dfda3f4..70ce6f1a70 100644 --- a/core/src/GenericGFPoly.h +++ b/core/src/GenericGFPoly.h @@ -1,22 +1,12 @@ -#pragma once /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once -#include "ZXContainerAlgorithms.h" +#include "ZXAlgorithms.h" #include #include @@ -69,9 +59,6 @@ class GenericGFPoly * to perform computations * @param coefficients coefficients as ints representing elements of GF(size), arranged * from most significant (highest-power term) coefficient to least significant - * @throws IllegalArgumentException if argument is null or empty, - * or if leading coefficient is 0 and this is not a - * constant polynomial (that is, it is not the monomial "0"). */ GenericGFPoly(const GenericGF& field, std::vector&& coefficients) : _field(&field) { diff --git a/core/src/GlobalHistogramBinarizer.cpp b/core/src/GlobalHistogramBinarizer.cpp index 59ad786b43..f09d040d22 100644 --- a/core/src/GlobalHistogramBinarizer.cpp +++ b/core/src/GlobalHistogramBinarizer.cpp @@ -1,19 +1,8 @@ /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "GlobalHistogramBinarizer.h" @@ -41,7 +30,7 @@ static int EstimateBlackPoint(const std::array& buckets) { // Find the tallest peak in the histogram. auto firstPeakPos = std::max_element(buckets.begin(), buckets.end()); - int firstPeak = static_cast(firstPeakPos - buckets.begin()); + int firstPeak = narrow_cast(firstPeakPos - buckets.begin()); int firstPeakSize = *firstPeakPos; int maxBucketCount = firstPeakSize; @@ -110,7 +99,7 @@ bool GlobalHistogramBinarizer::getPatternRow(int row, int rotation, PatternRow& auto process = [&](bool val, const uint8_t* p) { if (val != lastVal) { - res.push_back(static_cast((p - lastPos) / pixStride)); + res.push_back(narrow_cast((p - lastPos) / pixStride)); lastVal = val; lastPos = p; } @@ -123,7 +112,7 @@ bool GlobalHistogramBinarizer::getPatternRow(int row, int rotation, PatternRow& bool backVal = *backPos < blackPoint; process(backVal, backPos); - res.push_back(static_cast((backPos - lastPos) / pixStride + 1)); + res.push_back(narrow_cast((backPos - lastPos) / pixStride + 1)); if (backVal) res.push_back(0); // last value is number of white pixels, here 0 diff --git a/core/src/GlobalHistogramBinarizer.h b/core/src/GlobalHistogramBinarizer.h index fbeac5d9df..8a0bcfa4e9 100644 --- a/core/src/GlobalHistogramBinarizer.h +++ b/core/src/GlobalHistogramBinarizer.h @@ -1,20 +1,10 @@ -#pragma once /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include "BinaryBitmap.h" diff --git a/core/src/GridSampler.cpp b/core/src/GridSampler.cpp index 260d763c27..9bc3490212 100644 --- a/core/src/GridSampler.cpp +++ b/core/src/GridSampler.cpp @@ -2,19 +2,8 @@ * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors * Copyright 2020 Axel Waggershauser -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "GridSampler.h" @@ -33,7 +22,8 @@ DetectorResult SampleGrid(const BitMatrix& image, int width, int height, const P { #ifdef PRINT_DEBUG LogMatrix log; - LogMatrixWriter lmw(log, image, 5, "grid.pnm"); + static int i = 0; + LogMatrixWriter lmw(log, image, 5, "grid" + std::to_string(i++) + ".pnm"); #endif if (width <= 0 || height <= 0 || !mod2Pix.isValid()) return {}; diff --git a/core/src/GridSampler.h b/core/src/GridSampler.h index 01e1eb92f7..8fb4eea6a9 100644 --- a/core/src/GridSampler.h +++ b/core/src/GridSampler.h @@ -1,20 +1,10 @@ -#pragma once /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include "DetectorResult.h" #include "PerspectiveTransform.h" diff --git a/core/src/HybridBinarizer.cpp b/core/src/HybridBinarizer.cpp index 2a9bb7aea5..598bd2a860 100644 --- a/core/src/HybridBinarizer.cpp +++ b/core/src/HybridBinarizer.cpp @@ -1,19 +1,8 @@ /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "HybridBinarizer.h" @@ -21,7 +10,7 @@ #include "BitMatrixIO.h" #include "ByteArray.h" #include "Matrix.h" -#include "ZXContainerAlgorithms.h" +#include "ZXAlgorithms.h" #include #include diff --git a/core/src/HybridBinarizer.h b/core/src/HybridBinarizer.h index 53fd8851d8..6e0a8b42d0 100644 --- a/core/src/HybridBinarizer.h +++ b/core/src/HybridBinarizer.h @@ -1,20 +1,10 @@ -#pragma once /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include "GlobalHistogramBinarizer.h" diff --git a/core/src/ImageView.h b/core/src/ImageView.h index ec72d18ae2..bee631b67a 100644 --- a/core/src/ImageView.h +++ b/core/src/ImageView.h @@ -1,19 +1,9 @@ -#pragma once /* * Copyright 2019 Axel Waggershauser -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include #include @@ -67,8 +57,12 @@ class ImageView * @param pixStride optional pixel stride in bytes, default is calculated from format */ ImageView(const uint8_t* data, int width, int height, ImageFormat format, int rowStride = 0, int pixStride = 0) - : _data(data), _format(format), _width(width), _height(height), - _pixStride(pixStride ? pixStride : PixStride(format)), _rowStride(rowStride ? rowStride : width * _pixStride) + : _data(data), + _format(format), + _width(width), + _height(height), + _pixStride(pixStride ? pixStride : PixStride(format)), + _rowStride(rowStride ? rowStride : width * _pixStride) {} int width() const { return _width; } @@ -91,7 +85,7 @@ class ImageView ImageView rotated(int degree) const { switch ((degree + 360) % 360) { - case 90: return {data(0, _height - 1), _height, _width, _format, _pixStride, -_rowStride}; + case 90: return {data(0, _height - 1), _height, _width, _format, _pixStride, -_rowStride}; case 180: return {data(_width - 1, _height - 1), _width, _height, _format, -_rowStride, -_pixStride}; case 270: return {data(_width - 1, 0), _height, _width, _format, -_pixStride, _rowStride}; } diff --git a/core/src/LogMatrix.h b/core/src/LogMatrix.h index 478545d962..4633a3ef7d 100644 --- a/core/src/LogMatrix.h +++ b/core/src/LogMatrix.h @@ -1,19 +1,9 @@ -#pragma once /* * Copyright 2020 Axel Waggershauser -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include "BitMatrix.h" #include "Matrix.h" @@ -78,7 +68,6 @@ class LogMatrix _log.set(static_cast(p.x * _scale), static_cast(p.y * _scale), color); } - template <> void operator()(const PointT& p, int color) { operator()(centered(p), color); diff --git a/core/src/Matrix.h b/core/src/Matrix.h index 3709f22738..7b350ec735 100644 --- a/core/src/Matrix.h +++ b/core/src/Matrix.h @@ -1,23 +1,13 @@ -#pragma once /* * Copyright 2016 Huy Cuong Nguyen * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include "Point.h" -#include "ZXContainerAlgorithms.h" +#include "ZXAlgorithms.h" #include #include diff --git a/core/src/MultiFormatReader.cpp b/core/src/MultiFormatReader.cpp index 7f01e33ee7..f445232a47 100644 --- a/core/src/MultiFormatReader.cpp +++ b/core/src/MultiFormatReader.cpp @@ -1,19 +1,8 @@ /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "MultiFormatReader.h" @@ -30,16 +19,15 @@ namespace ZXing { -MultiFormatReader::MultiFormatReader(const DecodeHints& hints) +MultiFormatReader::MultiFormatReader(const DecodeHints& hints) : _hints(hints) { - bool tryHarder = hints.tryHarder(); auto formats = hints.formats().empty() ? BarcodeFormat::Any : hints.formats(); - // Put 1D readers upfront in "normal" mode - if (formats.testFlags(BarcodeFormat::OneDCodes) && !tryHarder) + // Put linear readers upfront in "normal" mode + if (formats.testFlags(BarcodeFormat::LinearCodes) && !hints.tryHarder()) _readers.emplace_back(new OneD::Reader(hints)); - if (formats.testFlag(BarcodeFormat::QRCode)) + if (formats.testFlags(BarcodeFormat::QRCode | BarcodeFormat::MicroQRCode)) _readers.emplace_back(new QRCode::Reader(hints)); if (formats.testFlag(BarcodeFormat::DataMatrix)) _readers.emplace_back(new DataMatrix::Reader(hints)); @@ -51,9 +39,8 @@ MultiFormatReader::MultiFormatReader(const DecodeHints& hints) _readers.emplace_back(new MaxiCode::Reader(hints)); // At end in "try harder" mode - if (formats.testFlags(BarcodeFormat::OneDCodes) && tryHarder) { + if (formats.testFlags(BarcodeFormat::LinearCodes) && hints.tryHarder()) _readers.emplace_back(new OneD::Reader(hints)); - } } MultiFormatReader::~MultiFormatReader() = default; @@ -61,17 +48,13 @@ MultiFormatReader::~MultiFormatReader() = default; Result MultiFormatReader::read(const BinaryBitmap& image) const { - // If we have only one reader in our list, just return whatever that decoded. - // This preserves information (e.g. ChecksumError) instead of just returning 'NotFound'. - if (_readers.size() == 1) - return _readers.front()->decode(image); - + Result r; for (const auto& reader : _readers) { - Result r = reader->decode(image); + r = reader->decode(image); if (r.isValid()) return r; } - return Result(DecodeStatus::NotFound); + return _hints.returnErrors() ? r : Result(); } Results MultiFormatReader::readMultiple(const BinaryBitmap& image, int maxSymbols) const @@ -80,6 +63,11 @@ Results MultiFormatReader::readMultiple(const BinaryBitmap& image, int maxSymbol for (const auto& reader : _readers) { auto r = reader->decode(image, maxSymbols); + if (!_hints.returnErrors()) { + //TODO: C++20 res.erase_if() + auto it = std::remove_if(res.begin(), res.end(), [](auto&& r) { return !r.isValid(); }); + res.erase(it, res.end()); + } maxSymbols -= r.size(); res.insert(res.end(), std::move_iterator(r.begin()), std::move_iterator(r.end())); if (maxSymbols <= 0) @@ -90,7 +78,7 @@ Results MultiFormatReader::readMultiple(const BinaryBitmap& image, int maxSymbol std::sort(res.begin(), res.end(), [](const Result& l, const Result& r) { auto lp = l.position().topLeft(); auto rp = r.position().topLeft(); - return lp.y < rp.y || (lp.y == rp.y && lp.x <= rp.x); + return lp.y < rp.y || (lp.y == rp.y && lp.x < rp.x); }); return res; diff --git a/core/src/MultiFormatReader.h b/core/src/MultiFormatReader.h index defafc4b1f..a9022f246c 100644 --- a/core/src/MultiFormatReader.h +++ b/core/src/MultiFormatReader.h @@ -1,20 +1,10 @@ -#pragma once /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include "Result.h" @@ -49,6 +39,7 @@ class MultiFormatReader private: std::vector> _readers; + const DecodeHints& _hints; }; } // ZXing diff --git a/core/src/MultiFormatWriter.cpp b/core/src/MultiFormatWriter.cpp index 1ed1b8ff21..5a03a6a4b3 100644 --- a/core/src/MultiFormatWriter.cpp +++ b/core/src/MultiFormatWriter.cpp @@ -1,18 +1,7 @@ /* * Copyright 2017 Huy Cuong Nguyen -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "MultiFormatWriter.h" @@ -31,6 +20,7 @@ #include "pdf417/PDFWriter.h" #include "qrcode/QRErrorCorrectionLevel.h" #include "qrcode/QRWriter.h" +#include "TextUtfEncoding.h" #include @@ -77,4 +67,9 @@ MultiFormatWriter::encode(const std::wstring& contents, int width, int height) c } } +BitMatrix MultiFormatWriter::encode(const std::string& contents, int width, int height) const +{ + return encode(TextUtfEncoding::FromUtf8(contents), width, height); +} + } // ZXing diff --git a/core/src/MultiFormatWriter.h b/core/src/MultiFormatWriter.h index 1ec252aa0f..f63ca03edb 100644 --- a/core/src/MultiFormatWriter.h +++ b/core/src/MultiFormatWriter.h @@ -1,19 +1,9 @@ -#pragma once /* * Copyright 2017 Huy Cuong Nguyen -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include "BarcodeFormat.h" #include "CharacterSet.h" @@ -60,6 +50,7 @@ class MultiFormatWriter } BitMatrix encode(const std::wstring& contents, int width, int height) const; + BitMatrix encode(const std::string& contents, int width, int height) const; private: BarcodeFormat _format; diff --git a/core/src/Pattern.h b/core/src/Pattern.h index c317be3e57..f75bc7dbb0 100644 --- a/core/src/Pattern.h +++ b/core/src/Pattern.h @@ -1,21 +1,11 @@ -#pragma once /* * Copyright 2020 Axel Waggershauser -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once -#include "ZXContainerAlgorithms.h" +#include "ZXAlgorithms.h" #include #include @@ -69,7 +59,7 @@ class PatternView int size() const { return _size; } // index is the number of bars and spaces from the first bar to the current position - int index() const { return static_cast(_data - (_base + 1)); } + int index() const { return narrow_cast(_data - (_base + 1)); } int pixelsInFront() const { return std::accumulate(_base, _data, 0); } int pixelsTillEnd() const { return std::accumulate(_base, _data + _size, 0) - 1; } bool isAtFirstBar() const { return _data == _base + 1; } @@ -124,7 +114,7 @@ class PatternView void extend() { - _size = std::max(0, static_cast(_end - _data)); + _size = std::max(0, narrow_cast(_end - _data)); } }; diff --git a/core/src/PerspectiveTransform.cpp b/core/src/PerspectiveTransform.cpp index 4aba2f1fd7..f3d1aaa2e9 100644 --- a/core/src/PerspectiveTransform.cpp +++ b/core/src/PerspectiveTransform.cpp @@ -2,19 +2,8 @@ * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors * Copyright 2020 Axel Waggershauser -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "PerspectiveTransform.h" diff --git a/core/src/PerspectiveTransform.h b/core/src/PerspectiveTransform.h index b02ce66fe1..c2f5043e18 100644 --- a/core/src/PerspectiveTransform.h +++ b/core/src/PerspectiveTransform.h @@ -1,21 +1,11 @@ -#pragma once /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors * Copyright 2020 Axel Waggershauser -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include "Point.h" #include "Quadrilateral.h" @@ -44,6 +34,7 @@ class PerspectiveTransform static PerspectiveTransform UnitSquareTo(const QuadrilateralF& q); public: + PerspectiveTransform() = default; PerspectiveTransform(const QuadrilateralF& src, const QuadrilateralF& dst); /// Project from the destination space (grid of modules) into the image space (bit matrix) diff --git a/core/src/Point.h b/core/src/Point.h index 66b8e41f4e..19e1366099 100644 --- a/core/src/Point.h +++ b/core/src/Point.h @@ -1,19 +1,9 @@ -#pragma once /* * Copyright 2020 Axel Waggershauser -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include #include diff --git a/core/src/Quadrilateral.h b/core/src/Quadrilateral.h index 23d7e76a8f..a2620715a8 100644 --- a/core/src/Quadrilateral.h +++ b/core/src/Quadrilateral.h @@ -1,22 +1,12 @@ -#pragma once /* * Copyright 2020 Axel Waggershauser -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include "Point.h" -#include "ZXContainerAlgorithms.h" +#include "ZXAlgorithms.h" #include #include @@ -114,6 +104,14 @@ PointT Center(const Quadrilateral& q) return Reduce(q) / Size(q); } +template +Quadrilateral RotatedCorners(const Quadrilateral& q, int n = 1) +{ + Quadrilateral res; + std::rotate_copy(q.begin(), q.begin() + ((n + 4) % 4), q.end(), res.begin()); + return res; +} + template bool IsInside(const PointT& p, const Quadrilateral& q) { diff --git a/core/src/ReadBarcode.cpp b/core/src/ReadBarcode.cpp index add15b2db7..6b1e22df97 100644 --- a/core/src/ReadBarcode.cpp +++ b/core/src/ReadBarcode.cpp @@ -1,18 +1,7 @@ /* * Copyright 2019 Axel Waggershauser -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "ReadBarcode.h" @@ -132,13 +121,12 @@ Result ReadBarcode(const ImageView& _iv, const DecodeHints& hints) if (hints.maxNumberOfSymbols() == 1) { // HACK: use the maxNumberOfSymbols value as a switch to ReadBarcodes to enable the downscaling // see python and android wrapper - auto ress = ReadBarcodes(_iv, DecodeHints(hints).setMaxNumberOfSymbols(1)); - return ress.empty() ? Result(DecodeStatus::NotFound) : ress.front(); + return FirstOrDefault(ReadBarcodes(_iv, hints)); } else { LumImage lum; ImageView iv = SetupLumImageView(_iv, lum, hints); - return MultiFormatReader(hints).read(*CreateBitmap(hints.binarizer(), iv)); + return MultiFormatReader(hints).read(*CreateBitmap(hints.binarizer(), iv)).setCharacterSet(hints.characterSet()); } } @@ -162,7 +150,7 @@ Results ReadBarcodes(const ImageView& _iv, const DecodeHints& hints) if (iv.width() != _iv.width()) r.setPosition(Scale(r.position(), _iv.width() / iv.width())); if (!Contains(results, r)) { - results.push_back(std::move(r)); + results.push_back(std::move(r)); // TODO: keep the one with no error instead of the first found --maxSymbols; } } @@ -170,6 +158,9 @@ Results ReadBarcodes(const ImageView& _iv, const DecodeHints& hints) break; } + for (auto& res : results) + res.setCharacterSet(hints.characterSet()); + return results; } diff --git a/core/src/ReadBarcode.h b/core/src/ReadBarcode.h index 3bbc48f7b4..5b73d16913 100644 --- a/core/src/ReadBarcode.h +++ b/core/src/ReadBarcode.h @@ -1,19 +1,9 @@ -#pragma once /* * Copyright 2019 Axel Waggershauser -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include "DecodeHints.h" #include "ImageView.h" @@ -30,7 +20,13 @@ namespace ZXing { */ Result ReadBarcode(const ImageView& buffer, const DecodeHints& hints = {}); -// WARNING: this API is experimental and may change/disappear +/** + * Read barcodes from an ImageView + * + * @param buffer view of the image data including layout and format + * @param hints optional DecodeHints to parameterize / speed up decoding + * @return #Results list of results found, may be empty + */ Results ReadBarcodes(const ImageView& buffer, const DecodeHints& hints = {}); } // ZXing diff --git a/core/src/Reader.h b/core/src/Reader.h index 642ac9c35f..70f34e1d29 100644 --- a/core/src/Reader.h +++ b/core/src/Reader.h @@ -1,66 +1,35 @@ -#pragma once /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once +#include "DecodeHints.h" #include "Result.h" namespace ZXing { class BinaryBitmap; +class DecodeHints; -/** -* Implementations of this interface can decode an image of a barcode in some format into -* the string it encodes. For example, {@link com.google.zxing.qrcode.QRCodeReader} can -* decode a QR code. The decoder may optionally receive hints from the caller which may help -* it decode more quickly or accurately. -* -* See {@link MultiFormatReader}, which attempts to determine what barcode -* format is present within the image as well, and then decodes it accordingly. -* -* All readers are thread-safe with no temporary state left behind after decode(). -* -* @author Sean Owen -* @author dswitkin@google.com (Daniel Switkin) -*/ class Reader { +protected: + const DecodeHints& _hints; + public: + explicit Reader(const DecodeHints& hints) : _hints(hints) {} + explicit Reader(DecodeHints&& hints) = delete; virtual ~Reader() = default; - /** - * Locates and decodes a barcode in some format within an image. This method also accepts - * hints, each possibly associated to some data, which may help the implementation decode. - * - * @param image image of barcode to decode - * @param hints passed as a {@link java.util.Map} from {@link DecodeHintType} - * to arbitrary data. The - * meaning of the data depends upon the hint type. The implementation may or may not do - * anything with these hints. - * @return string which the barcode encodes - * @throws NotFoundException if no potential barcode is found - * @throws ChecksumException if a potential barcode is found but does not pass its checksum - * @throws FormatException if a potential barcode is found but format is invalid - */ virtual Result decode(const BinaryBitmap& image) const = 0; // WARNING: this API is experimental and may change/disappear virtual Results decode(const BinaryBitmap& image, [[maybe_unused]] int maxSymbols) const { auto res = decode(image); - return res.isValid() ? Results{std::move(res)} : Results{}; + return res.isValid() || (_hints.returnErrors() && res.format() != BarcodeFormat::None) ? Results{std::move(res)} : Results{}; } }; diff --git a/core/src/ReedSolomonDecoder.cpp b/core/src/ReedSolomonDecoder.cpp index ac38fc3f65..e521f4cb7e 100644 --- a/core/src/ReedSolomonDecoder.cpp +++ b/core/src/ReedSolomonDecoder.cpp @@ -2,19 +2,8 @@ * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors * Copyright 2017 Axel Waggershauser -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "ReedSolomonDecoder.h" diff --git a/core/src/ReedSolomonDecoder.h b/core/src/ReedSolomonDecoder.h index d6f001ffa0..7772adb9a8 100644 --- a/core/src/ReedSolomonDecoder.h +++ b/core/src/ReedSolomonDecoder.h @@ -1,20 +1,10 @@ -#pragma once /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include diff --git a/core/src/ReedSolomonEncoder.cpp b/core/src/ReedSolomonEncoder.cpp index 784d69cd5b..94741f1258 100644 --- a/core/src/ReedSolomonEncoder.cpp +++ b/core/src/ReedSolomonEncoder.cpp @@ -1,19 +1,8 @@ /* * Copyright 2016 Huy Cuong Nguyen * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "ReedSolomonEncoder.h" diff --git a/core/src/ReedSolomonEncoder.h b/core/src/ReedSolomonEncoder.h index 15c96e5bf1..ad1feee017 100644 --- a/core/src/ReedSolomonEncoder.h +++ b/core/src/ReedSolomonEncoder.h @@ -1,20 +1,10 @@ -#pragma once /* * Copyright 2016 Huy Cuong Nguyen * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include "GenericGFPoly.h" diff --git a/core/src/RegressionLine.h b/core/src/RegressionLine.h index 8be690fc72..be3dd0a813 100644 --- a/core/src/RegressionLine.h +++ b/core/src/RegressionLine.h @@ -1,19 +1,9 @@ -#pragma once /* * Copyright 2020 Axel Waggershauser -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include "Point.h" @@ -22,6 +12,10 @@ #include #include +#ifdef PRINT_DEBUG +#include +#endif + namespace ZXing { class RegressionLine @@ -33,12 +27,12 @@ class RegressionLine friend PointF intersect(const RegressionLine& l1, const RegressionLine& l2); - bool evaluate(const std::vector& ps) + template bool evaluate(const PointT* begin, const PointT* end) { - auto mean = std::accumulate(ps.begin(), ps.end(), PointF()) / ps.size(); + auto mean = std::accumulate(begin, end, PointF()) / std::distance(begin, end); PointF::value_t sumXX = 0, sumYY = 0, sumXY = 0; - for (auto& p : ps) { - auto d = p - mean; + for (auto p = begin; p != end; ++p) { + auto d = *p - mean; sumXX += d.x * d.x; sumYY += d.y * d.y; sumXY += d.x * d.y; @@ -60,14 +54,29 @@ class RegressionLine return dot(_directionInward, normal()) > 0.5f; // angle between original and new direction is at most 60 degree } + template bool evaluate(const std::vector>& points) { return evaluate(&points.front(), &points.back() + 1); } + + template static auto distance(PointT a, PointT b) { return ZXing::distance(a, b); } + public: RegressionLine() { _points.reserve(16); } // arbitrary but plausible start size (tiny performance improvement) + template RegressionLine(PointT a, PointT b) + { + evaluate(std::vector{a, b}); + } + + template RegressionLine(const PointT* b, const PointT* e) + { + evaluate(b, e); + } + const auto& points() const { return _points; } int length() const { return _points.size() >= 2 ? int(distance(_points.front(), _points.back())) : 0; } bool isValid() const { return !std::isnan(a); } PointF normal() const { return isValid() ? PointF(a, b) : _directionInward; } auto signedDistance(PointF p) const { return dot(normal(), p) - c; } + template auto distance(PointT p) const { return std::abs(signedDistance(PointF(p))); } PointF project(PointF p) const { return p - signedDistance(p) * normal(); } void reset() diff --git a/core/src/Result.cpp b/core/src/Result.cpp index 19ef576fac..3ce1d103c7 100644 --- a/core/src/Result.cpp +++ b/core/src/Result.cpp @@ -1,70 +1,144 @@ /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "Result.h" #include "DecoderResult.h" #include "TextDecoder.h" +#include "TextUtfEncoding.h" +#include "ZXAlgorithms.h" #include +#include +#include #include namespace ZXing { -Result::Result(std::wstring&& text, Position&& position, BarcodeFormat format, std::string&& symbologyIdentifier, - ByteArray&& rawBytes, StructuredAppendInfo&& sai, const bool readerInit, int lineCount) - : _format(format), _text(std::move(text)), _position(std::move(position)), _rawBytes(std::move(rawBytes)), - _symbologyIdentifier(std::move(symbologyIdentifier)), _sai(std::move(sai)), _readerInit(readerInit), - _lineCount(lineCount) +Result::Result(const std::string& text, int y, int xStart, int xStop, BarcodeFormat format, SymbologyIdentifier si, Error error, + ByteArray&& rawBytes, bool readerInit, const std::string& ai) + : _format(format), + _content({ByteArray(text)}, si, ai), + _error(error), + _position(Line(y, xStart, xStop)), + _rawBytes(std::move(rawBytes)), + _numBits(Size(_rawBytes) * 8), + _readerInit(readerInit), + _lineCount(0) +{} + +Result::Result(DecoderResult&& decodeResult, Position&& position, BarcodeFormat format) + : _format(decodeResult.content().symbology.code == 0 ? BarcodeFormat::None : format), + _content(std::move(decodeResult).content()), + _error(std::move(decodeResult).error()), + _position(std::move(position)), + _rawBytes(std::move(decodeResult).rawBytes()), + _numBits(decodeResult.numBits()), + _ecLevel(decodeResult.ecLevel()), + _sai(decodeResult.structuredAppend()), + _isMirrored(decodeResult.isMirrored()), + _readerInit(decodeResult.readerInit()), + _lineCount(decodeResult.lineCount()) { - _numBits = Size(_rawBytes) * 8; + // TODO: add type opaque and code specific 'extra data'? (see DecoderResult::extra()) } -Result::Result(const std::string& text, int y, int xStart, int xStop, BarcodeFormat format, - std::string&& symbologyIdentifier, ByteArray&& rawBytes, const bool readerInit) - : Result(TextDecoder::FromLatin1(text), Line(y, xStart, xStop), format, std::move(symbologyIdentifier), - std::move(rawBytes), {}, readerInit) -{} +DecodeStatus Result::status() const +{ + switch(_error.type()) { + case Error::Format : return DecodeStatus::FormatError; + case Error::Checksum : return DecodeStatus::ChecksumError; + default: ; + } -Result::Result(DecoderResult&& decodeResult, Position&& position, BarcodeFormat format) - : _status(decodeResult.errorCode()), _format(format), _text(std::move(decodeResult).text()), - _position(std::move(position)), _rawBytes(std::move(decodeResult).rawBytes()), _numBits(decodeResult.numBits()), - _ecLevel(decodeResult.ecLevel()), _symbologyIdentifier(decodeResult.symbologyIdentifier()), - _sai(decodeResult.structuredAppend()), _isMirrored(decodeResult.isMirrored()), - _readerInit(decodeResult.readerInit()) + return format() == BarcodeFormat::None ? DecodeStatus::NotFound : DecodeStatus::NoError; +} + +const ByteArray& Result::bytes() const { + return _content.bytes; +} - // TODO: add type opaque and code specific 'extra data'? (see DecoderResult::extra()) +ByteArray Result::bytesECI() const +{ + return _content.bytesECI(); +} + +std::string Result::utf8() const +{ + return _content.utf8(); +} + +std::wstring Result::utf16() const +{ + return _content.utf16(); +} + +#if 0 +std::string Result::utf8ECI() const +{ + return _content.text(TextMode::Utf8ECI); +} +#endif + +ContentType Result::contentType() const +{ + return _content.type(); +} + +bool Result::hasECI() const +{ + return _content.hasECI; } int Result::orientation() const { constexpr auto std_numbers_pi_v = 3.14159265358979323846; // TODO: c++20 - return std::lround(_position.orientation() * 180 / std_numbers_pi_v); + return narrow_cast(std::lround(_position.orientation() * 180 / std_numbers_pi_v)); +} + +std::string Result::symbologyIdentifier() const +{ + return _content.symbology.toString(); +} + +int Result::sequenceSize() const +{ + return _sai.count; +} + +int Result::sequenceIndex() const +{ + return _sai.index; +} + +std::string Result::sequenceId() const +{ + return _sai.id; +} + +Result& Result::setCharacterSet(const std::string& defaultCS) +{ + if (!defaultCS.empty()) + _content.defaultCharset = defaultCS; + return *this; } bool Result::operator==(const Result& o) const { - if (format() != o.format() || text() != o.text()) + // two symbols may be considered the same if at least one of them has an error + if (!(format() == o.format() && (bytes() == o.bytes() || error() || o.error()))) return false; - if (BarcodeFormats(BarcodeFormat::TwoDCodes).testFlag(format())) + if (BarcodeFormats(BarcodeFormat::MatrixCodes).testFlag(format())) return IsInside(Center(o.position()), position()); + // linear symbology comparisons only implemented for this->lineCount == 1 + assert(lineCount() == 1); + // if one line is less than half the length of the other away from the // latter, we consider it to belong to the same symbol auto dTop = maxAbsComponent(o.position().topLeft() - position().topLeft()); @@ -74,4 +148,45 @@ bool Result::operator==(const Result& o) const return std::min(dTop, dBot) < length / 2; } +Result MergeStructuredAppendSequence(const Results& results) +{ + if (results.empty()) + return {}; + + std::list allResults(results.begin(), results.end()); + allResults.sort([](const Result& r1, const Result& r2) { return r1.sequenceIndex() < r2.sequenceIndex(); }); + + Result res = allResults.front(); + for (auto i = std::next(allResults.begin()); i != allResults.end(); ++i) + res._content.append(i->_content); + + res._position = {}; + res._sai.index = -1; + + if (allResults.back().sequenceSize() != Size(allResults) || + !std::all_of(allResults.begin(), allResults.end(), + [&](Result& it) { return it.sequenceId() == allResults.front().sequenceId(); })) + res._error = FormatError("sequenceIDs not matching during structured append sequence merging"); + + return res; +} + +Results MergeStructuredAppendSequences(const Results& results) +{ + std::map sas; + for (auto& res : results) { + if (res.isPartOfSequence()) + sas[res.sequenceId()].push_back(res); + } + + Results saiResults; + for (auto& [id, seq] : sas) { + auto res = MergeStructuredAppendSequence(seq); + if (res.isValid()) + saiResults.push_back(std::move(res)); + } + + return saiResults; +} + } // ZXing diff --git a/core/src/Result.h b/core/src/Result.h index c44c95455c..1d60013f50 100644 --- a/core/src/Result.h +++ b/core/src/Result.h @@ -1,25 +1,17 @@ -#pragma once /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors * Copyright 2020 Axel Waggershauser -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include "BarcodeFormat.h" #include "ByteArray.h" +#include "Content.h" #include "DecodeStatus.h" +#include "Error.h" #include "Quadrilateral.h" #include "StructuredAppend.h" @@ -33,75 +25,94 @@ class DecoderResult; using Position = QuadrilateralI; /** -*

Encapsulates the result of decoding a barcode within an image.

-* -* @author Sean Owen -*/ + * @brief The Result class encapsulates the result of decoding a barcode within an image. + */ class Result { -public: - explicit Result(DecodeStatus status) : _status(status) {} + /** + * @brief utf8/utf16 is the bytes() content converted to utf8/16 based on ECI or guessed character set information + * + * Note: these two properties might only be available while transitioning text() from std::wstring to std::string. time will tell. + * see https://github.com/nu-book/zxing-cpp/issues/338 for a background discussion on the issue. + */ + std::string utf8() const; + std::wstring utf16() const; - Result(std::wstring&& text, Position&& position, BarcodeFormat format, std::string&& symbologyIdentifier = "", - ByteArray&& rawBytes = {}, StructuredAppendInfo&& sai = {}, const bool readerInit = false, - int lineCount = 0); +public: + Result() = default; - // 1D convenience constructor - Result(const std::string& text, int y, int xStart, int xStop, BarcodeFormat format, - std::string&& symbologyIdentifier = "", ByteArray&& rawBytes = {}, const bool readerInit = false); + // linear symbology convenience constructor + Result(const std::string& text, int y, int xStart, int xStop, BarcodeFormat format, SymbologyIdentifier si, Error error = {}, + ByteArray&& rawBytes = {}, bool readerInit = false, const std::string& ai = {}); Result(DecoderResult&& decodeResult, Position&& position, BarcodeFormat format); - bool isValid() const { - return StatusIsOK(_status); - } + bool isValid() const { return format() != BarcodeFormat::None && !error(); } - DecodeStatus status() const { - return _status; - } + const Error& error() const { return _error; } - BarcodeFormat format() const { - return _format; - } + [[deprecated]] DecodeStatus status() const; - const std::wstring& text() const { - return _text; - } + BarcodeFormat format() const { return _format; } - const Position& position() const { - return _position; - } - void setPosition(Position pos) { - _position = pos; - } + /** + * @brief bytes is the raw / standard content without any modifications like character set conversions + */ + const ByteArray& bytes() const; - int orientation() const; //< orientation of barcode in degree, see also Position::orientation() + /** + * @brief bytesECI is the raw / standard content following the ECI protocol + */ + ByteArray bytesECI() const; + +#ifdef ZX_USE_UTF8 + std::string text() const { return utf8(); } + std::string ecLevel() const { return _ecLevel; } +#else +#pragma message( \ + "Warning: the return type of text() and ecLevel() will change to std::string. Please #define ZX_USE_UTF8 to transition before the next release.") + std::wstring text() const { return utf16(); } + std::wstring ecLevel() const { return {_ecLevel.begin(), _ecLevel.end()}; } +#endif + +#if 0 // disabled until final API decission is made + /** + * @brief utf8ECI is the standard content following the ECI protocol with every character set ECI segment transcoded to utf8 + */ + std::string utf8ECI() const; +#endif /** - * @brief isMirrored is the symbol mirrored (currently only supported by QRCode and DataMatrix) + * @brief contentType gives a hint to the type of content found (Text/Binary/GS1/etc.) */ - bool isMirrored() const { - return _isMirrored; - } + ContentType contentType() const; - const ByteArray& rawBytes() const { - return _rawBytes; - } + /** + * @brief hasECI specifies wheter or not an ECI tag was found + */ + bool hasECI() const; + + const Position& position() const { return _position; } + void setPosition(Position pos) { _position = pos; } + + /** + * @brief orientation of barcode in degree, see also Position::orientation() + */ + int orientation() const; - int numBits() const { - return _numBits; - } + /** + * @brief isMirrored is the symbol mirrored (currently only supported by QRCode and DataMatrix) + */ + bool isMirrored() const { return _isMirrored; } - const std::wstring& ecLevel() const { - return _ecLevel; - } + /// see bytes() above for a proper replacement of rawByes + [[deprecated]] const ByteArray& rawBytes() const { return _rawBytes; } + [[deprecated]] int numBits() const { return _numBits; } /** * @brief symbologyIdentifier Symbology identifier "]cm" where "c" is symbology code character, "m" the modifier. */ - const std::string& symbologyIdentifier() const { - return _symbologyIdentifier; - } + std::string symbologyIdentifier() const; /** * @brief sequenceSize number of symbols in a structured append sequence. @@ -110,12 +121,12 @@ class Result * If it is a structured append symbol but the total number of symbols is unknown, the * returned value is 0 (see PDF417 if optional "Segment Count" not given). */ - int sequenceSize() const { return _sai.count; } + int sequenceSize() const; /** * @brief sequenceIndex the 0-based index of this symbol in a structured append sequence. */ - int sequenceIndex() const { return _sai.index; } + int sequenceIndex() const; /** * @brief sequenceId id to check if a set of symbols belongs to the same structured append sequence. @@ -124,39 +135,37 @@ class Result * For QR Code, this is the parity integer converted to a string. * For PDF417 and DataMatrix, this is the "fileId". */ - const std::string& sequenceId() const { return _sai.id; } + std::string sequenceId() const; bool isLastInSequence() const { return sequenceSize() == sequenceIndex() + 1; } - bool isPartOfSequence() const { return sequenceSize() > -1; } + bool isPartOfSequence() const { return sequenceSize() > -1 && sequenceIndex() > -1; } /** * @brief readerInit Set if Reader Initialisation/Programming symbol. */ - bool readerInit() const { - return _readerInit; - } + bool readerInit() const { return _readerInit; } /** - * @brief How many lines have been detected with this code (applies only to 1D symbologies) + * @brief How many lines have been detected with this code (applies only to linear symbologies) */ - int lineCount() const { - return _lineCount; - } - void incrementLineCount() { - ++_lineCount; - } + int lineCount() const { return _lineCount; } + + // only for internal use + void incrementLineCount() { ++_lineCount; } + Result& setCharacterSet(const std::string& defaultCS); bool operator==(const Result& o) const; + friend Result MergeStructuredAppendSequence(const std::vector& results); + private: - DecodeStatus _status = DecodeStatus::NoError; BarcodeFormat _format = BarcodeFormat::None; - std::wstring _text; + Content _content; + Error _error; Position _position; ByteArray _rawBytes; int _numBits = 0; - std::wstring _ecLevel; - std::string _symbologyIdentifier; + std::string _ecLevel; StructuredAppendInfo _sai; bool _isMirrored = false; bool _readerInit = false; @@ -165,4 +174,20 @@ class Result using Results = std::vector; +// Consider this an internal function that can change/disappear anytime without notice +inline Result FirstOrDefault(Results&& results) +{ + return results.empty() ? Result() : std::move(results.front()); +} + +/** + * @brief Merge a list of Results from one Structured Append sequence to a single result + */ +Result MergeStructuredAppendSequence(const Results& results); + +/** + * @brief Automatically merge all Structured Append sequences found in the given results + */ +Results MergeStructuredAppendSequences(const Results& results); + } // ZXing diff --git a/core/src/ResultPoint.cpp b/core/src/ResultPoint.cpp index 8ea41a47b3..134216aa01 100644 --- a/core/src/ResultPoint.cpp +++ b/core/src/ResultPoint.cpp @@ -1,19 +1,8 @@ /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "ResultPoint.h" diff --git a/core/src/ResultPoint.h b/core/src/ResultPoint.h index 12cd7bda36..067b648f11 100644 --- a/core/src/ResultPoint.h +++ b/core/src/ResultPoint.h @@ -1,20 +1,10 @@ -#pragma once /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include "Point.h" diff --git a/core/src/Scope.h b/core/src/Scope.h index 1ba2297b0f..40506fa077 100644 --- a/core/src/Scope.h +++ b/core/src/Scope.h @@ -1,19 +1,9 @@ -#pragma once /* * Copyright 2020 Axel Waggershauser -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include diff --git a/core/src/StructuredAppend.h b/core/src/StructuredAppend.h index 6a778f91b3..105d5ebd65 100644 --- a/core/src/StructuredAppend.h +++ b/core/src/StructuredAppend.h @@ -1,19 +1,9 @@ -#pragma once /* * Copyright 2021 Axel Waggershauser -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include diff --git a/core/src/TextDecoder.cpp b/core/src/TextDecoder.cpp index 27063549bd..b9835c77ad 100644 --- a/core/src/TextDecoder.cpp +++ b/core/src/TextDecoder.cpp @@ -1,18 +1,7 @@ /* * Copyright 2016 Nu-book Inc. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "TextDecoder.h" @@ -437,6 +426,9 @@ TextDecoder::GuessEncoding(const uint8_t* bytes, size_t length, CharacterSet fal else if (value == 0x80 || value == 0xA0 || value > 0xEF) { canBeShiftJIS = false; } + else if (value < 0x20 && value != 0xa && value != 0xd) { + canBeShiftJIS = false; // use non-printable ASCII as indication for binary content + } else if (value > 0xA0 && value < 0xE0) { sjisKatakanaChars++; sjisCurDoubleBytesWordLength = 0; diff --git a/core/src/TextDecoder.h b/core/src/TextDecoder.h index 7a9118d8ae..ee35251867 100644 --- a/core/src/TextDecoder.h +++ b/core/src/TextDecoder.h @@ -1,19 +1,9 @@ -#pragma once /* * Copyright 2016 Nu-book Inc. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include #include diff --git a/core/src/TextEncoder.cpp b/core/src/TextEncoder.cpp index e3553e4dfa..5ddde516bf 100644 --- a/core/src/TextEncoder.cpp +++ b/core/src/TextEncoder.cpp @@ -1,24 +1,13 @@ /* * Copyright 2016 Nu-book Inc. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "TextEncoder.h" #include "CharacterSet.h" #include "TextUtfEncoding.h" -#include "ZXContainerAlgorithms.h" +#include "ZXAlgorithms.h" #include "textcodec/Big5TextEncoder.h" #include "textcodec/GBTextEncoder.h" #include "textcodec/JPTextEncoder.h" diff --git a/core/src/TextEncoder.h b/core/src/TextEncoder.h index 83b7627cf6..d16972f104 100644 --- a/core/src/TextEncoder.h +++ b/core/src/TextEncoder.h @@ -1,19 +1,9 @@ -#pragma once /* * Copyright 2016 Nu-book Inc. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include diff --git a/core/src/TextUtfEncoding.cpp b/core/src/TextUtfEncoding.cpp index b2e3e1e4e7..500a017975 100644 --- a/core/src/TextUtfEncoding.cpp +++ b/core/src/TextUtfEncoding.cpp @@ -1,18 +1,7 @@ /* * Copyright 2016 Nu-book Inc. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "TextUtfEncoding.h" diff --git a/core/src/TextUtfEncoding.h b/core/src/TextUtfEncoding.h index ebbbca2e97..07ceca38df 100644 --- a/core/src/TextUtfEncoding.h +++ b/core/src/TextUtfEncoding.h @@ -1,19 +1,9 @@ -#pragma once /* * Copyright 2016 Nu-book Inc. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include #include diff --git a/core/src/ThresholdBinarizer.h b/core/src/ThresholdBinarizer.h index 160ff5a960..92cb1ffb56 100644 --- a/core/src/ThresholdBinarizer.h +++ b/core/src/ThresholdBinarizer.h @@ -1,19 +1,9 @@ -#pragma once /* * Copyright 2020 Axel Waggershauser -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include "BinaryBitmap.h" #include "BitMatrix.h" @@ -45,13 +35,13 @@ class ThresholdBinarizer : public BinaryBitmap for (const uint8_t* p = begin; p < end; p += stride) { bool val = *p <= _threshold; if (val != lastVal) { - res.push_back(static_cast(p - lastPos) / stride); + res.push_back(narrow_cast(p - lastPos) / stride); lastVal = val; lastPos = p; } } - res.push_back(static_cast(end - lastPos) / stride); + res.push_back(narrow_cast(end - lastPos) / stride); if (*(end - stride) <= _threshold) res.push_back(0); // last value is number of white pixels, here 0 diff --git a/core/src/TritMatrix.h b/core/src/TritMatrix.h index 584677ae30..8e70ff9fb1 100644 --- a/core/src/TritMatrix.h +++ b/core/src/TritMatrix.h @@ -1,19 +1,9 @@ -#pragma once /* * Copyright 2020 Axel Waggershauser -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include "Matrix.h" diff --git a/core/src/WhiteRectDetector.cpp b/core/src/WhiteRectDetector.cpp index 3741caaf15..87cfca924e 100644 --- a/core/src/WhiteRectDetector.cpp +++ b/core/src/WhiteRectDetector.cpp @@ -1,19 +1,8 @@ /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "WhiteRectDetector.h" @@ -129,20 +118,6 @@ static void CenterEdges(const ResultPoint& y, const ResultPoint& z, const Result } } -/** -*

-* Detects a candidate barcode-like rectangular region within an image. It -* starts around the center of the image, increases the size of the candidate -* region until it finds a white rectangular region. -*

-* -* @return {@link ResultPoint}[] describing the corners of the rectangular -* region. The first and last points are opposed on the diagonal, as -* are the second and third. The first point will be the topmost -* point and the last, the bottommost. The second point will be -* leftmost and the third, the rightmost -* @throws NotFoundException if no Data Matrix Code can be found -*/ bool DetectWhiteRect(const BitMatrix& image, int initSize, int x, int y, ResultPoint& p0, ResultPoint& p1, ResultPoint& p2, ResultPoint& p3) { diff --git a/core/src/WhiteRectDetector.h b/core/src/WhiteRectDetector.h index 3d1cf39625..db4d11f0c5 100644 --- a/core/src/WhiteRectDetector.h +++ b/core/src/WhiteRectDetector.h @@ -1,20 +1,10 @@ -#pragma once /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once namespace ZXing { @@ -37,7 +27,7 @@ class ResultPoint; * are the second and third. The first point will be the topmost * point and the last, the bottommost. The second point will be * leftmost and the third, the rightmost - * @throws NotFoundException if no Data Matrix Code can be found + * @return true iff white rect was found */ bool DetectWhiteRect(const BitMatrix& image, int initSize, int x, int y, ResultPoint& p0, ResultPoint& p1, ResultPoint& p2, ResultPoint& p3); diff --git a/core/src/ZXContainerAlgorithms.h b/core/src/ZXAlgorithms.h similarity index 71% rename from core/src/ZXContainerAlgorithms.h rename to core/src/ZXAlgorithms.h index d6e9ad59a6..f04191f10d 100644 --- a/core/src/ZXContainerAlgorithms.h +++ b/core/src/ZXAlgorithms.h @@ -1,19 +1,9 @@ -#pragma once /* * Copyright 2017 Axel Waggershauser -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include #include @@ -24,6 +14,11 @@ namespace ZXing { +template +constexpr T narrow_cast(U&& u) noexcept { + return static_cast(std::forward(u)); +} + template auto Find(Container& c, const Value& v) -> decltype(std::begin(c)) { return std::find(std::begin(c), std::end(c), v); @@ -56,23 +51,23 @@ Value Reduce(const Container& c, Value v = Value{}, Op op = {}) { // see C++20 ssize template constexpr auto Size(const Container& c) -> decltype(c.size(), int()) { - return static_cast(c.size()); + return narrow_cast(c.size()); } template constexpr int Size(const T (&)[N]) noexcept { - return static_cast(N); + return narrow_cast(N); } template int IndexOf(const Container& c, const Value& v) { auto i = Find(c, v); - return i == std::end(c) ? -1 : static_cast(std::distance(std::begin(c), i)); + return i == std::end(c) ? -1 : narrow_cast(std::distance(std::begin(c), i)); } inline int IndexOf(const char* str, char c) { auto s = strchr(str, c); - return s != nullptr ? static_cast(s - str) : -1; + return s != nullptr ? narrow_cast(s - str) : -1; } template diff --git a/core/src/ZXBigInteger.cpp b/core/src/ZXBigInteger.cpp index 1bb9ee7b70..56e67300e9 100644 --- a/core/src/ZXBigInteger.cpp +++ b/core/src/ZXBigInteger.cpp @@ -1,18 +1,7 @@ /* * Copyright 2016 Huy Cuong Nguyen -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "ZXBigInteger.h" diff --git a/core/src/ZXBigInteger.h b/core/src/ZXBigInteger.h index e9dfab0056..92aa21b0f6 100644 --- a/core/src/ZXBigInteger.h +++ b/core/src/ZXBigInteger.h @@ -1,19 +1,9 @@ -#pragma once /* * Copyright 2016 Huy Cuong Nguyen -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include #include diff --git a/core/src/ZXConfig.h b/core/src/ZXConfig.h index 434680caad..0a1e6a6ea1 100644 --- a/core/src/ZXConfig.h +++ b/core/src/ZXConfig.h @@ -1,19 +1,9 @@ -#pragma once /* * Copyright 2016 Nu-book Inc. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #define ZX_HAVE_CONFIG diff --git a/core/src/ZXNullable.h b/core/src/ZXNullable.h index 05deb694fa..8cd6bd040f 100644 --- a/core/src/ZXNullable.h +++ b/core/src/ZXNullable.h @@ -1,19 +1,9 @@ -#pragma once /* * Copyright 2016 Huy Cuong Nguyen -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include #include diff --git a/core/src/aztec/AZDecoder.cpp b/core/src/aztec/AZDecoder.cpp index 2e196ad3bc..1a71e0022f 100644 --- a/core/src/aztec/AZDecoder.cpp +++ b/core/src/aztec/AZDecoder.cpp @@ -1,40 +1,26 @@ /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. +* Copyright 2022 Axel Waggershauser */ +// SPDX-License-Identifier: Apache-2.0 #include "AZDecoder.h" #include "AZDetectorResult.h" #include "BitArray.h" #include "BitMatrix.h" -#include "CharacterSetECI.h" +#include "CharacterSet.h" #include "DecodeStatus.h" #include "DecoderResult.h" #include "GenericGF.h" #include "ReedSolomonDecoder.h" -#include "TextDecoder.h" -#include "TextUtfEncoding.h" #include "ZXTestSupport.h" -#include -#include -#include #include #include #include +#include #include namespace ZXing::Aztec { @@ -131,10 +117,7 @@ static BitArray ExtractBits(const DetectorResult& ddata) } /** -*

Performs RS error correction on an array of bits.

-* -* @return the corrected array -* @throws FormatException if the input contains too many errors +* @brief Performs RS error correction on an array of bits. */ static BitArray CorrectBits(const DetectorResult& ddata, const BitArray& rawbits) { @@ -160,12 +143,12 @@ static BitArray CorrectBits(const DetectorResult& ddata, const BitArray& rawbits int numECCodewords = numCodewords - numDataCodewords; if (numCodewords < numDataCodewords) - return {}; + throw FormatError("Invalid number of code words"); auto dataWords = ToInts(rawbits, codewordSize, numCodewords, Size(rawbits) % codewordSize); if (!ReedSolomonDecode(*gf, dataWords, numECCodewords)) - return {}; + throw ChecksumError(); // drop the ECCodewords from the dataWords array dataWords.resize(numDataCodewords); @@ -226,20 +209,21 @@ static const char* GetCharacter(Table table, int code) /** * See ISO/IEC 24778:2008 Section 10.1 */ -static int ParseECIValue(BitArray::Range& bits, const int flg) +static ECI ParseECIValue(BitArrayView& bits, const int flg) { int eci = 0; - for (int i = 0; i < flg && bits.size() >= 4; i++) - eci = 10 * eci + ReadBits(bits, 4) - 2; - return eci; + for (int i = 0; i < flg; i++) + eci = 10 * eci + bits.readBits(4) - 2; + return ECI(eci); } /** * See ISO/IEC 24778:2008 Section 8 */ -static StructuredAppendInfo ParseStructuredAppend(std::wstring& text) +static StructuredAppendInfo ParseStructuredAppend(ByteArray& bytes) { - std::wstring id; + std::string text(bytes.begin(), bytes.end()); + StructuredAppendInfo sai; std::string::size_type i = 0; if (text[0] == ' ') { // Space-delimited id @@ -247,81 +231,43 @@ static StructuredAppendInfo ParseStructuredAppend(std::wstring& text) if (sp == std::string::npos) return {}; - id = text.substr(1, sp - 1); // Strip space delimiters + sai.id = text.substr(1, sp - 1); // Strip space delimiters i = sp + 1; } if (i + 1 >= text.size() || !std::isupper(text[i]) || !std::isupper(text[i + 1])) return {}; - StructuredAppendInfo sai; sai.index = text[i] - 'A'; sai.count = text[i + 1] - 'A' + 1; if (sai.count == 1 || sai.count <= sai.index) // If info doesn't make sense sai.count = 0; // Choose to mark count as unknown - if (!id.empty()) - TextUtfEncoding::ToUtf8(id, sai.id); - text.erase(0, i + 2); // Remove + bytes = ByteArray(text); return sai; } -struct AztecData +static void DecodeContent(const BitArray& bits, Content& res) { - std::wstring text; - std::string symbologyIdentifier; - StructuredAppendInfo sai; -}; - -/** -* Gets the string encoded in the aztec code bits -* -* @return the decoded string -*/ -ZXING_EXPORT_TEST_ONLY -AztecData GetEncodedData(const BitArray& bits, const std::string& characterSet) -{ - AztecData res; Table latchTable = Table::UPPER; // table most recently latched to Table shiftTable = Table::UPPER; // table to use for the next read - std::string text; - text.reserve(20); - int symbologyIdModifier = 0; - CharacterSet encoding = CharacterSetECI::InitEncoding(characterSet); - // Check for Structured Append - need 4 5-bit words, beginning with ML UL, ending with index and count - bool haveStructuredAppend = Size(bits) > 20 && ToInt(bits, 0, 5) == 29 // ML (UPPER table) - && ToInt(bits, 5, 5) == 29; // UL (MIXED table) - bool haveFNC1 = false; - auto remBits = bits.range(); + auto remBits = BitArrayView(bits); - while (remBits) { + while (remBits.size() >= (shiftTable == Table::DIGIT ? 4 : 5)) { // see ISO/IEC 24778:2008 7.3.1.2 regarding padding bits if (shiftTable == Table::BINARY) { - if (remBits.size() < 5) - break; - int length = ReadBits(remBits, 5); - if (length == 0) { - if (remBits.size() < 11) - break; - length = ReadBits(remBits, 11) + 31; - } - for (int charCount = 0; charCount < length; charCount++) { - if (remBits.size() < 8) { - remBits.begin = remBits.end; // Force outer loop to exit - break; - } - int code = ReadBits(remBits, 8); - text.push_back((char)code); - } + int length = remBits.readBits(5); + if (length == 0) + length = remBits.readBits(11) + 31; + for (int i = 0; i < length; i++) + res.push_back(remBits.readBits(8)); // Go back to whatever mode we had been in shiftTable = latchTable; } else { int size = shiftTable == Table::DIGIT ? 4 : 5; - if (remBits.size() < size) - break; - int code = ReadBits(remBits, size); + int code = remBits.readBits(size); const char* str = GetCharacter(shiftTable, code); if (std::strncmp(str, "CTRL_", 5) == 0) { // Table changes @@ -333,75 +279,81 @@ AztecData GetEncodedData(const BitArray& bits, const std::string& characterSet) if (str[6] == 'L') latchTable = shiftTable; } else if (std::strcmp(str, "FLGN") == 0) { - if (remBits.size() < 3) - break; - int flg = ReadBits(remBits, 3); + int flg = remBits.readBits(3); if (flg == 0) { // FNC1 - haveFNC1 = true; // Will process first/second FNC1 at end after any Structured Append - text.push_back((char)29); // May be removed at end if first/second FNC1 + res.push_back(29); // May be removed at end if first/second FNC1 } else if (flg <= 6) { // FLG(1) to FLG(6) ECI - encoding = - CharacterSetECI::OnChangeAppendReset(ParseECIValue(remBits, flg), res.text, text, encoding); + res.switchEncoding(ParseECIValue(remBits, flg)); } else { // FLG(7) is invalid } shiftTable = latchTable; } else { - text.append(str); + res.append(str); // Go back to whatever mode we had been in shiftTable = latchTable; } } } +} - TextDecoder::Append(res.text, reinterpret_cast(text.data()), text.size(), encoding); - - if (!res.text.empty()) { - if (haveStructuredAppend) - res.sai = ParseStructuredAppend(res.text); - if (haveFNC1) { - // As converting character set ECIs ourselves and ignoring/skipping non-character ECIs, not using - // modifiers that indicate ECI protocol (ISO/IEC 24778:2008 Annex F Table F.1) - if (res.text.front() == 29) { - symbologyIdModifier = 1; // GS1 - res.text.erase(0, 1); // Remove FNC1 - } else if (res.text.size() > 2 && std::isupper(res.text[0]) && res.text[1] == 29) { - // FNC1 following single uppercase letter (the AIM Application Indicator) - symbologyIdModifier = 2; // AIM - res.text.erase(1, 1); // Remove FNC1 - // The AIM Application Indicator character "A"-"Z" is left in the stream (ISO/IEC 24778:2008 16.2) - } else if (res.text.size() > 3 && std::isdigit(res.text[0]) && std::isdigit(res.text[1]) && - res.text[2] == 29) { - // FNC1 following 2 digits (the AIM Application Indicator) - symbologyIdModifier = 2; // AIM - res.text.erase(2, 1); // Remove FNC1 - // The AIM Application Indicator characters "00"-"99" are left in the stream (ISO/IEC 24778:2008 16.2) - } - } - } +ZXING_EXPORT_TEST_ONLY +DecoderResult Decode(const BitArray& bits) +{ + Content res; + res.symbology = {'z', '0', 3}; - res.symbologyIdentifier = "]z" + std::to_string(symbologyIdModifier + (res.sai.index > -1 ? 6 : 0)); + try { + DecodeContent(bits, res); + } catch (const std::exception&) { // see BitArrayView::readBits + return FormatError(); + } - return res; -} + if (res.bytes.empty()) + return FormatError("Empty symbol content"); -DecoderResult Decode(const DetectorResult& detectorResult, const std::string& characterSet) -{ - BitArray bits = CorrectBits(detectorResult, ExtractBits(detectorResult)); + // Check for Structured Append - need 4 5-bit words, beginning with ML UL, ending with index and count + bool haveStructuredAppend = Size(bits) > 20 && ToInt(bits, 0, 5) == 29 // latch to MIXED (from UPPER) + && ToInt(bits, 5, 5) == 29; // latch back to UPPER (from MIXED) + + StructuredAppendInfo sai = haveStructuredAppend ? ParseStructuredAppend(res.bytes) : StructuredAppendInfo(); + + // As converting character set ECIs ourselves and ignoring/skipping non-character ECIs, not using + // modifiers that indicate ECI protocol (ISO/IEC 24778:2008 Annex F Table F.1) + if (res.bytes[0] == 29) { + res.symbology.modifier = '1'; // GS1 + res.applicationIndicator = "GS1"; + res.erase(0, 1); // Remove FNC1 + } else if (res.bytes.size() > 2 && std::isupper(res.bytes[0]) && res.bytes[1] == 29) { + // FNC1 following single uppercase letter (the AIM Application Indicator) + res.symbology.modifier = '2'; // AIM + // TODO: remove the AI from the content? + res.applicationIndicator = res.bytes.asString(0, 1); + res.erase(1, 1); // Remove FNC1, + // The AIM Application Indicator character "A"-"Z" is left in the stream (ISO/IEC 24778:2008 16.2) + } else if (res.bytes.size() > 3 && std::isdigit(res.bytes[0]) && std::isdigit(res.bytes[1]) && res.bytes[2] == 29) { + // FNC1 following 2 digits (the AIM Application Indicator) + res.symbology.modifier = '2'; // AIM + res.applicationIndicator = res.bytes.asString(0, 2); + res.erase(2, 1); // Remove FNC1 + // The AIM Application Indicator characters "00"-"99" are left in the stream (ISO/IEC 24778:2008 16.2) + } - if (!bits.size()) - return DecodeStatus::FormatError; + if (sai.index != -1) + res.symbology.modifier += 6; // TODO: this is wrong as long as we remove the sai info from the content in ParseStructuredAppend - auto data = GetEncodedData(bits, characterSet); - if (data.text.empty()) - return DecodeStatus::FormatError; + return DecoderResult(bits.toBytes(), std::move(res)).setNumBits(Size(bits)).setStructuredAppend(sai); +} - return DecoderResult(bits.toBytes(), std::move(data.text)) - .setNumBits(Size(bits)) - .setSymbologyIdentifier(std::move(data.symbologyIdentifier)) - .setStructuredAppend(data.sai) - .setReaderInit(detectorResult.readerInit()); +DecoderResult Decode(const DetectorResult& detectorResult) +{ + try { + auto bits = CorrectBits(detectorResult, ExtractBits(detectorResult)); + return Decode(bits).setReaderInit(detectorResult.readerInit()); + } catch (Error e) { + return e; + } } } // namespace ZXing::Aztec diff --git a/core/src/aztec/AZDecoder.h b/core/src/aztec/AZDecoder.h index d9eb6dd1fd..2054c2fd92 100644 --- a/core/src/aztec/AZDecoder.h +++ b/core/src/aztec/AZDecoder.h @@ -1,20 +1,10 @@ -#pragma once /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include @@ -26,10 +16,7 @@ namespace Aztec { class DetectorResult; -/** - * @brief Decode Aztec Code after locating and extracting from an image. - */ -DecoderResult Decode(const DetectorResult& detectorResult, const std::string& characterSet = ""); +DecoderResult Decode(const DetectorResult& detectorResult); } // Aztec } // ZXing diff --git a/core/src/aztec/AZDetector.cpp b/core/src/aztec/AZDetector.cpp index 6ff3089a8e..8f14fe07f6 100644 --- a/core/src/aztec/AZDetector.cpp +++ b/core/src/aztec/AZDetector.cpp @@ -1,19 +1,8 @@ /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "AZDetector.h" @@ -25,6 +14,7 @@ #include "ReedSolomonDecoder.h" #include "ResultPoint.h" #include "WhiteRectDetector.h" +#include "ZXAlgorithms.h" #include #include @@ -34,7 +24,7 @@ namespace ZXing::Aztec { template ::value>::type> static int RoundToNearest(T x) { - return static_cast(std::lround(x)); + return narrow_cast(std::lround(x)); } static const int EXPECTED_CORNER_BITS[] = { @@ -154,7 +144,7 @@ static bool GetCorrectedParameterData(int64_t parameterData, bool compact, int& * Extracts the number of data layers and data blocks from the layer around the bull's eye. * * @param bullsEyeCorners the array of bull's eye corners -* @throws NotFoundException in case of too many errors or invalid parameters +* @return false in case of too many errors or invalid parameters */ static bool ExtractParameters(const BitMatrix& image, const std::array& bullsEyeCorners, bool compact, int nbCenterLayers, int& nbLayers, int& nbDataBlocks, bool& readerInit, int& shift) @@ -340,21 +330,21 @@ static PointI GetFirstDifferent(const BitMatrix& image, const PointI& init, bool */ static void ExpandSquare(std::array& cornerPoints, float oldSide, float newSide) { - float ratio = newSide / (2 * oldSide); - float dx = cornerPoints[0].x() - cornerPoints[2].x(); - float dy = cornerPoints[0].y() - cornerPoints[2].y(); - float centerx = (cornerPoints[0].x() + cornerPoints[2].x()) / 2.0f; - float centery = (cornerPoints[0].y() + cornerPoints[2].y()) / 2.0f; + double ratio = newSide / (2.0 * oldSide); + double dx = cornerPoints[0].x() - cornerPoints[2].x(); + double dy = cornerPoints[0].y() - cornerPoints[2].y(); + double centerx = (cornerPoints[0].x() + cornerPoints[2].x()) / 2.0f; + double centery = (cornerPoints[0].y() + cornerPoints[2].y()) / 2.0f; - cornerPoints[0] = ResultPoint(centerx + ratio * dx, centery + ratio * dy); - cornerPoints[2] = ResultPoint(centerx - ratio * dx, centery - ratio * dy); + cornerPoints[0] = PointF(centerx + ratio * dx, centery + ratio * dy); + cornerPoints[2] = PointF(centerx - ratio * dx, centery - ratio * dy); dx = cornerPoints[1].x() - cornerPoints[3].x(); dy = cornerPoints[1].y() - cornerPoints[3].y(); centerx = (cornerPoints[1].x() + cornerPoints[3].x()) / 2.0f; centery = (cornerPoints[1].y() + cornerPoints[3].y()) / 2.0f; - cornerPoints[1] = ResultPoint(centerx + ratio * dx, centery + ratio * dy); - cornerPoints[3] = ResultPoint(centerx - ratio * dx, centery - ratio * dy); + cornerPoints[1] = PointF(centerx + ratio * dx, centery + ratio * dy); + cornerPoints[3] = PointF(centerx - ratio * dx, centery - ratio * dy); } @@ -365,7 +355,7 @@ static void ExpandSquare(std::array& cornerPoints, float oldSide * * @param pCenter Center point * @return The corners of the bull-eye -* @throws NotFoundException If no valid bull-eye can be found +* @return false If no valid bull-eye can be found */ static bool GetBullsEyeCorners(const BitMatrix& image, const PointI& pCenter, std::array& result, bool& compact, int& nbCenterLayers) { @@ -507,23 +497,19 @@ DetectorResult Detect(const BitMatrix& image, bool isMirror, bool isPure) std::array bullsEyeCorners; bool compact = false; int nbCenterLayers = 0; - if (!GetBullsEyeCorners(image, pCenter, bullsEyeCorners, compact, nbCenterLayers)) { + if (!GetBullsEyeCorners(image, pCenter, bullsEyeCorners, compact, nbCenterLayers)) return {}; - } - if (isMirror) { + if (isMirror) std::swap(bullsEyeCorners[0], bullsEyeCorners[2]); - } // 3. Get the size of the matrix and other parameters from the bull's eye int nbLayers = 0; int nbDataBlocks = 0; bool readerInit = false; int shift = 0; - if (!ExtractParameters(image, bullsEyeCorners, compact, nbCenterLayers, nbLayers, nbDataBlocks, readerInit, - shift)) { + if (!ExtractParameters(image, bullsEyeCorners, compact, nbCenterLayers, nbLayers, nbDataBlocks, readerInit, shift)) return {}; - } // 4. Sample the grid return {SampleGrid(image, bullsEyeCorners[(shift + 0) % 4], bullsEyeCorners[(shift + 1) % 4], diff --git a/core/src/aztec/AZDetector.h b/core/src/aztec/AZDetector.h index b8307310e1..25927e2f3f 100644 --- a/core/src/aztec/AZDetector.h +++ b/core/src/aztec/AZDetector.h @@ -1,20 +1,10 @@ -#pragma once /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once namespace ZXing { @@ -28,8 +18,6 @@ class DetectorResult; * Detects an Aztec Code in an image. * * @param isMirror if true, image is a mirror-image of original - * @return {@link AztecDetectorResult} encapsulating results of detecting an Aztec Code - * @throws NotFoundException if no Aztec Code can be found */ DetectorResult Detect(const BitMatrix& image, bool isMirror, bool isPure); diff --git a/core/src/aztec/AZDetectorResult.h b/core/src/aztec/AZDetectorResult.h index 478ccf764d..54c6c5524e 100644 --- a/core/src/aztec/AZDetectorResult.h +++ b/core/src/aztec/AZDetectorResult.h @@ -1,20 +1,10 @@ -#pragma once /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include "DetectorResult.h" diff --git a/core/src/aztec/AZEncoder.cpp b/core/src/aztec/AZEncoder.cpp index 9bf45cfac9..f45eb000db 100644 --- a/core/src/aztec/AZEncoder.cpp +++ b/core/src/aztec/AZEncoder.cpp @@ -1,19 +1,8 @@ /* * Copyright 2016 Huy Cuong Nguyen * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "AZEncoder.h" diff --git a/core/src/aztec/AZEncoder.h b/core/src/aztec/AZEncoder.h index dae27bc897..3c8d5351a3 100644 --- a/core/src/aztec/AZEncoder.h +++ b/core/src/aztec/AZEncoder.h @@ -1,20 +1,10 @@ -#pragma once /* * Copyright 2016 Huy Cuong Nguyen * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include "BitMatrix.h" diff --git a/core/src/aztec/AZEncodingState.h b/core/src/aztec/AZEncodingState.h index 95c2a996fd..71ee8d3292 100644 --- a/core/src/aztec/AZEncodingState.h +++ b/core/src/aztec/AZEncodingState.h @@ -1,20 +1,10 @@ -#pragma once /* * Copyright 2016 Huy Cuong Nguyen * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include "AZToken.h" diff --git a/core/src/aztec/AZHighLevelEncoder.cpp b/core/src/aztec/AZHighLevelEncoder.cpp index f27bac3b5f..f17b5df637 100644 --- a/core/src/aztec/AZHighLevelEncoder.cpp +++ b/core/src/aztec/AZHighLevelEncoder.cpp @@ -1,26 +1,15 @@ /* * Copyright 2016 Huy Cuong Nguyen * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "AZHighLevelEncoder.h" #include "AZEncodingState.h" #include "AZToken.h" #include "BitArray.h" -#include "ZXContainerAlgorithms.h" +#include "ZXAlgorithms.h" #include #include @@ -95,18 +84,14 @@ static const std::array, 5>& InitCharMap() charmap[MODE_DIGIT][','] = 12; charmap[MODE_DIGIT]['.'] = 13; const int8_t mixedTable[] = { - 0x00, 0x20, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, - 0x0b, 0x0c, 0x0d, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x40, 0x5c, 0x5e, - 0x5f, 0x60, 0x7c, 0x7d, 0x7f, + 0x00, 0x20, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, + 0x0d, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x40, 0x5c, 0x5e, 0x5f, 0x60, 0x7c, 0x7d, 0x7f, }; for (uint8_t i = 0; i < Size(mixedTable); i++) { charmap[MODE_MIXED][mixedTable[i]] = i; } - const char punctTable[] = { - '\0', '\r', '\0', '\0', '\0', '\0', '!', '\'', '#', '$', '%', '&', '\'', - '(', ')', '*', '+', ',', '-', '.', '/', ':', ';', '<', '=', '>', '?', - '[', ']', '{', '}' - }; + const char punctTable[] = {'\0', '\r', '\0', '\0', '\0', '\0', '!', '\'', '#', '$', '%', '&', '\'', '(', ')', '*', + '+', ',', '-', '.', '/', ':', ';', '<', '=', '>', '?', '[', ']', '{', '}'}; for (uint8_t i = 0; i < Size(punctTable); i++) { if (punctTable[i] > 0) { charmap[MODE_PUNCT][punctTable[i]] = i; diff --git a/core/src/aztec/AZHighLevelEncoder.h b/core/src/aztec/AZHighLevelEncoder.h index 62deba6a4c..5152a0938c 100644 --- a/core/src/aztec/AZHighLevelEncoder.h +++ b/core/src/aztec/AZHighLevelEncoder.h @@ -1,20 +1,10 @@ -#pragma once /* * Copyright 2016 Huy Cuong Nguyen * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include diff --git a/core/src/aztec/AZReader.cpp b/core/src/aztec/AZReader.cpp index 4cd8157778..56f45040e7 100644 --- a/core/src/aztec/AZReader.cpp +++ b/core/src/aztec/AZReader.cpp @@ -1,19 +1,8 @@ /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "AZReader.h" @@ -30,31 +19,23 @@ namespace ZXing::Aztec { -Reader::Reader(const DecodeHints& hints) - : _isPure(hints.isPure()), _characterSet(hints.characterSet()) -{ -} - Result Reader::decode(const BinaryBitmap& image) const { auto binImg = image.getBitMatrix(); - if (binImg == nullptr) { - return Result(DecodeStatus::NotFound); - } + if (binImg == nullptr) + return {}; - DetectorResult detectResult = Detect(*binImg, false, _isPure); - DecoderResult decodeResult = DecodeStatus::NotFound; - if (detectResult.isValid()) { - decodeResult = Decode(detectResult, _characterSet); - } + DetectorResult detectResult = Detect(*binImg, false, _hints.isPure()); + DecoderResult decodeResult; + if (detectResult.isValid()) + decodeResult = Decode(detectResult); //TODO: don't start detection all over again, just to swap 2 corner points if (!decodeResult.isValid()) { - detectResult = Detect(*binImg, true, _isPure); - if (detectResult.isValid()) { - decodeResult = Decode(detectResult, _characterSet); - } + detectResult = Detect(*binImg, true, _hints.isPure()); + if (detectResult.isValid()) + decodeResult = Decode(detectResult); } return Result(std::move(decodeResult), std::move(detectResult).position(), BarcodeFormat::Aztec); diff --git a/core/src/aztec/AZReader.h b/core/src/aztec/AZReader.h index d21dc6d866..0b8c2a6a29 100644 --- a/core/src/aztec/AZReader.h +++ b/core/src/aztec/AZReader.h @@ -1,46 +1,21 @@ -#pragma once /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 -#include "Reader.h" - -#include - -namespace ZXing { +#pragma once -class DecodeHints; +#include "Reader.h" -namespace Aztec { +namespace ZXing::Aztec { -/** -* This implementation can detect and decode Aztec codes in an image. -* -* @author David Olivier -*/ class Reader : public ZXing::Reader { public: - explicit Reader(const DecodeHints& hints); - Result decode(const BinaryBitmap& image) const override; + using ZXing::Reader::Reader; -private: - bool _isPure; - std::string _characterSet; + Result decode(const BinaryBitmap& image) const override; }; -} // Aztec -} // ZXing +} // namespace ZXing::Aztec diff --git a/core/src/aztec/AZToken.cpp b/core/src/aztec/AZToken.cpp index cb549fa1a9..3ea839ef02 100644 --- a/core/src/aztec/AZToken.cpp +++ b/core/src/aztec/AZToken.cpp @@ -1,19 +1,8 @@ /* * Copyright 2016 Huy Cuong Nguyen * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "AZToken.h" diff --git a/core/src/aztec/AZToken.h b/core/src/aztec/AZToken.h index 85385bb052..24b2081c12 100644 --- a/core/src/aztec/AZToken.h +++ b/core/src/aztec/AZToken.h @@ -1,20 +1,10 @@ -#pragma once /* * Copyright 2016 Huy Cuong Nguyen * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include diff --git a/core/src/aztec/AZWriter.cpp b/core/src/aztec/AZWriter.cpp index 8c29c5eab2..6e6b0ad0d7 100644 --- a/core/src/aztec/AZWriter.cpp +++ b/core/src/aztec/AZWriter.cpp @@ -1,25 +1,15 @@ /* * Copyright 2016 Huy Cuong Nguyen * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "AZWriter.h" #include "AZEncoder.h" #include "CharacterSet.h" #include "TextEncoder.h" +#include "TextUtfEncoding.h" #include @@ -40,4 +30,9 @@ Writer::encode(const std::wstring& contents, int width, int height) const return Inflate(std::move(aztec.matrix), width, height, _margin); } +BitMatrix Writer::encode(const std::string& contents, int width, int height) const +{ + return encode(TextUtfEncoding::FromUtf8(contents), width, height); +} + } // namespace ZXing::Aztec diff --git a/core/src/aztec/AZWriter.h b/core/src/aztec/AZWriter.h index deecff0b4e..aa80d46a30 100644 --- a/core/src/aztec/AZWriter.h +++ b/core/src/aztec/AZWriter.h @@ -1,20 +1,10 @@ -#pragma once /* * Copyright 2016 Huy Cuong Nguyen * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include @@ -51,6 +41,7 @@ class Writer } BitMatrix encode(const std::wstring& contents, int width, int height) const; + BitMatrix encode(const std::string& contents, int width, int height) const; private: CharacterSet _encoding; diff --git a/core/src/datamatrix/DMBitLayout.cpp b/core/src/datamatrix/DMBitLayout.cpp index 99fc86ee85..c0b0cddc7c 100644 --- a/core/src/datamatrix/DMBitLayout.cpp +++ b/core/src/datamatrix/DMBitLayout.cpp @@ -2,19 +2,8 @@ * Copyright 2016 Huy Cuong Nguyen * Copyright 2006 Jeremias Maerki * Copyright 2020 Axel Waggersauser -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "DMBitLayout.h" @@ -181,15 +170,11 @@ static BitMatrix ExtractDataBits(const Version& version, const BitMatrix& bits) * * @return bytes encoded within the Data Matrix Code */ -ByteArray CodewordsFromBitMatrix(const BitMatrix& bits) +ByteArray CodewordsFromBitMatrix(const BitMatrix& bits, const Version& version) { - const Version* version = VersionForDimensionsOf(bits); - if (version == nullptr) - return {}; - - BitMatrix dataBits = ExtractDataBits(*version, bits); + BitMatrix dataBits = ExtractDataBits(version, bits); - ByteArray result(version->totalCodewords()); + ByteArray result(version.totalCodewords()); auto codeword = result.begin(); VisitMatrix(dataBits.height(), dataBits.width(), [&codeword, &dataBits](const BitPosArray& bitPos) { diff --git a/core/src/datamatrix/DMBitLayout.h b/core/src/datamatrix/DMBitLayout.h index d2b266dbe1..92f8e291f3 100644 --- a/core/src/datamatrix/DMBitLayout.h +++ b/core/src/datamatrix/DMBitLayout.h @@ -1,19 +1,9 @@ -#pragma once /* * Copyright 2020 Axel Waggershauser -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once namespace ZXing { @@ -22,8 +12,10 @@ class ByteArray; namespace DataMatrix { +class Version; + BitMatrix BitMatrixFromCodewords(const ByteArray& codewords, int width, int height); -ByteArray CodewordsFromBitMatrix(const BitMatrix& bits); +ByteArray CodewordsFromBitMatrix(const BitMatrix& bits, const Version& version); } // namespace DataMatrix } // namespace ZXing diff --git a/core/src/datamatrix/DMDataBlock.cpp b/core/src/datamatrix/DMDataBlock.cpp index c5f96b79b7..710e67d087 100644 --- a/core/src/datamatrix/DMDataBlock.cpp +++ b/core/src/datamatrix/DMDataBlock.cpp @@ -1,24 +1,13 @@ /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "DMDataBlock.h" #include "DMVersion.h" -#include "ZXContainerAlgorithms.h" +#include "ZXAlgorithms.h" #include diff --git a/core/src/datamatrix/DMDataBlock.h b/core/src/datamatrix/DMDataBlock.h index ca13d83777..54dc7fade7 100644 --- a/core/src/datamatrix/DMDataBlock.h +++ b/core/src/datamatrix/DMDataBlock.h @@ -1,20 +1,10 @@ -#pragma once /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include "ByteArray.h" diff --git a/core/src/datamatrix/DMDecoder.cpp b/core/src/datamatrix/DMDecoder.cpp index feb469cb38..6c30613221 100644 --- a/core/src/datamatrix/DMDecoder.cpp +++ b/core/src/datamatrix/DMDecoder.cpp @@ -1,25 +1,14 @@ /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "DMDecoder.h" #include "BitMatrix.h" #include "BitSource.h" -#include "CharacterSetECI.h" +#include "CharacterSet.h" #include "DMBitLayout.h" #include "DMDataBlock.h" #include "DMVersion.h" @@ -28,7 +17,7 @@ #include "GenericGF.h" #include "ReedSolomonDecoder.h" #include "TextDecoder.h" -#include "ZXContainerAlgorithms.h" +#include "ZXAlgorithms.h" #include "ZXTestSupport.h" #include @@ -51,18 +40,6 @@ namespace ZXing::DataMatrix { */ namespace DecodedBitStreamParser { -enum Mode -{ - FORMAT_ERROR, - DONE, // reached end of code word sequence or a PAD codeword - ASCII_ENCODE, - C40_ENCODE, - TEXT_ENCODE, - ANSIX12_ENCODE, - EDIFACT_ENCODE, - BASE256_ENCODE -}; - /** * See ISO 16022:2006, Annex C Table C.1 * The C40 Basic Character Set (*'s used for placeholders for the shift values) @@ -96,17 +73,6 @@ static const char TEXT_SHIFT3_SET_CHARS[] = { 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', '{', '|', '}', '~', 127 }; -// Decoding state -struct State -{ - CharacterSet encoding; - int symbologyIdModifier = 1; // ECC 200 (ISO 16022:2006 Annex N Table N.1) - struct StructuredAppendInfo sai; - bool readerInit = false; - bool firstCodeword = true; - int firstFNC1Position = 1; -}; - struct Shift128 { bool set = false; @@ -116,19 +82,19 @@ struct Shift128 /** * See ISO 16022:2006, 5.4.1, Table 6 */ -static int ParseECIValue(BitSource& bits) +static ECI ParseECIValue(BitSource& bits) { int firstByte = bits.readBits(8); if (firstByte <= 127) - return firstByte - 1; + return ECI(firstByte - 1); int secondByte = bits.readBits(8); if (firstByte <= 191) - return (firstByte - 128) * 254 + 127 + secondByte - 1; + return ECI((firstByte - 128) * 254 + 127 + secondByte - 1); int thirdByte = bits.readBits(8); - return (firstByte - 192) * 64516 + 16383 + (secondByte - 1) * 254 + thirdByte - 1; + return ECI((firstByte - 192) * 64516 + 16383 + (secondByte - 1) * 254 + thirdByte - 1); } /** @@ -152,97 +118,6 @@ static void ParseStructuredAppend(BitSource& bits, StructuredAppendInfo& sai) sai.id = std::to_string((fileId1 << 8) | fileId2); } -/** -* See ISO 16022:2006, 5.2.3 and Annex C, Table C.2 -*/ -static Mode DecodeAsciiSegment(BitSource& bits, std::string& result, std::string& resultTrailer, - std::wstring& resultEncoded, State& state) -{ - Shift128 upperShift; - - while (bits.available() >= 8) { - int oneByte = bits.readBits(8); - switch (oneByte) { - case 0: - return Mode::FORMAT_ERROR; - case 129: // Pad - return Mode::DONE; - case 230: // Latch to C40 encodation - return Mode::C40_ENCODE; - case 231: // Latch to Base 256 encodation - return Mode::BASE256_ENCODE; - case 232: // FNC1 - if (bits.byteOffset() == state.firstFNC1Position || bits.byteOffset() == state.firstFNC1Position + 1) { - // As converting character set ECIs ourselves and ignoring/skipping non-character ECIs, not using - // modifiers that indicate ECI protocol (ISO 16022:2006 Annex N Table N.1, ISO 21471:2020 Annex G Table G.1) - - // Only recognizing an FNC1 as first/second by codeword position (aka symbol character position), not - // by decoded character position, i.e. not recognizing a C40/Text encoded FNC1 (which requires a latch - // and a shift) - if (bits.byteOffset() == state.firstFNC1Position) - state.symbologyIdModifier = 2; // GS1 - else { - state.symbologyIdModifier = 3; // AIM - // Note no AIM Application Indicator format defined, ISO 16022:2006 11.2 - } - } else - result.push_back((char)29); // translate as ASCII 29 - break; - case 233: // Structured Append - if (state.firstCodeword) { // Must be first ISO 16022:2006 5.6.1 - ParseStructuredAppend(bits, state.sai); - state.firstFNC1Position = 5; - } else - return Mode::FORMAT_ERROR; - break; - case 234: // Reader Programming - if (state.firstCodeword) // Must be first ISO 16022:2006 5.2.4.9 - state.readerInit = true; - else - return Mode::FORMAT_ERROR; - break; - case 235: // Upper Shift (shift to Extended ASCII) - upperShift.set = true; - break; - case 236: // 05 Macro - result.append("[)>\x1E""05\x1D"); - resultTrailer.insert(0, "\x1E\x04"); - break; - case 237: // 06 Macro - result.append("[)>\x1E""06\x1D"); - resultTrailer.insert(0, "\x1E\x04"); - break; - case 238: // Latch to ANSI X12 encodation - return Mode::ANSIX12_ENCODE; - case 239: // Latch to Text encodation - return Mode::TEXT_ENCODE; - case 240: // Latch to EDIFACT encodation - return Mode::EDIFACT_ENCODE; - case 241: // ECI Character - state.encoding = CharacterSetECI::OnChangeAppendReset(ParseECIValue(bits), resultEncoded, result, - state.encoding); - break; - default: - if (oneByte <= 128) { // ASCII data (ASCII value + 1) - result.push_back(upperShift(oneByte) - 1); - } else if (oneByte <= 229) { // 2-digit data 00-99 (Numeric Value + 130) - int value = oneByte - 130; - if (value < 10) // pad with '0' for single digit values - result.push_back('0'); - result.append(std::to_string(value)); - } else if (oneByte >= 242) { // Not to be used in ASCII encodation - // work around encoders that use unlatch to ASCII as last code word (ask upstream) - if (oneByte == 254 && bits.available() == 0) - break; - return Mode::FORMAT_ERROR; - } - } - state.firstCodeword = false; - } - - return Mode::DONE; -} - std::optional> DecodeNextTriple(BitSource& bits) { // Values are encoded in a 16-bit value as (1600 * C1) + (40 * C2) + C3 + 1 @@ -262,18 +137,20 @@ std::optional> DecodeNextTriple(BitSource& bits) return {{a, b, c}}; } +enum class Mode {C40, TEXT}; + /** * See ISO 16022:2006, 5.2.5 and Annex C, Table C.1 (C40) * See ISO 16022:2006, 5.2.6 and Annex C, Table C.2 (Text) */ -static bool DecodeC40OrTextSegment(BitSource& bits, std::string& result, Mode mode) +static void DecodeC40OrTextSegment(BitSource& bits, Content& result, Mode mode) { // TODO(bbrown): The Upper Shift with C40 doesn't work in the 4 value scenario all the time Shift128 upperShift; int shift = 0; - const char* BASIC_SET_CHARS = mode == Mode::C40_ENCODE ? C40_BASIC_SET_CHARS : TEXT_BASIC_SET_CHARS; - const char* SHIFT_SET_CHARS = mode == Mode::C40_ENCODE ? C40_SHIFT2_SET_CHARS : TEXT_SHIFT2_SET_CHARS; + const char* BASIC_SET_CHARS = mode == Mode::C40 ? C40_BASIC_SET_CHARS : TEXT_BASIC_SET_CHARS; + const char* SHIFT_SET_CHARS = mode == Mode::C40 ? C40_SHIFT2_SET_CHARS : TEXT_SHIFT2_SET_CHARS; while (auto triple = DecodeNextTriple(bits)) { for (int cValue : *triple) { @@ -284,7 +161,7 @@ static bool DecodeC40OrTextSegment(BitSource& bits, std::string& result, Mode mo else if (cValue < 40) // Size(BASIC_SET_CHARS) result.push_back(upperShift(BASIC_SET_CHARS[cValue])); else - return false; + throw FormatError("invalid value in C40 or Text segment"); break; case 1: result.push_back(upperShift(cValue)); break; case 2: @@ -293,35 +170,33 @@ static bool DecodeC40OrTextSegment(BitSource& bits, std::string& result, Mode mo else if (cValue == 30) // Upper Shift upperShift.set = true; else - return false; + throw FormatError("invalid value in C40 or Text segment"); break; case 3: - if (mode == Mode::C40_ENCODE) + if (mode == Mode::C40) result.push_back(upperShift(cValue + 96)); else if (cValue < Size(TEXT_SHIFT3_SET_CHARS)) result.push_back(upperShift(TEXT_SHIFT3_SET_CHARS[cValue])); else - return false; + throw FormatError("invalid value in C40 or Text segment"); break; - default: return false; + default: throw FormatError("invalid value in C40 or Text segment"); ; } } } - - return true; } /** * See ISO 16022:2006, 5.2.7 */ -static bool DecodeAnsiX12Segment(BitSource& bits, std::string& result) +static void DecodeAnsiX12Segment(BitSource& bits, Content& result) { while (auto triple = DecodeNextTriple(bits)) { for (int cValue : *triple) { // X12 segment terminator , separator *, sub-element separator >, space static const char segChars[4] = {'\r', '*', '>', ' '}; if (cValue < 0) - return false; + throw FormatError("invalid value in AnsiX12 segment"); else if (cValue < 4) result.push_back(segChars[cValue]); else if (cValue < 14) // 0 - 9 @@ -329,17 +204,15 @@ static bool DecodeAnsiX12Segment(BitSource& bits, std::string& result) else if (cValue < 40) // A - Z result.push_back((char)(cValue + 51)); else - return false; + throw FormatError("invalid value in AnsiX12 segment"); } } - - return true; } /** * See ISO 16022:2006, 5.2.8 and Annex C Table C.3 */ -static bool DecodeEdifactSegment(BitSource& bits, std::string& result) +static void DecodeEdifactSegment(BitSource& bits, Content& result) { // If there are less than 3 bytes left then it will be encoded as ASCII while (bits.available() >= 24) { @@ -351,7 +224,7 @@ static bool DecodeEdifactSegment(BitSource& bits, std::string& result) // Read rest of byte, which should be 0, and stop if (bits.bitOffset()) bits.readBits(8 - bits.bitOffset()); - return true; + return; } if ((edifactValue & 0x20) == 0) // no 1 in the leading (6th) bit @@ -359,8 +232,6 @@ static bool DecodeEdifactSegment(BitSource& bits, std::string& result) result.push_back(edifactValue); } } - - return true; } /** @@ -376,7 +247,7 @@ static int Unrandomize255State(int randomizedBase256Codeword, int base256Codewor /** * See ISO 16022:2006, 5.2.9 and Annex B, B.2 */ -static bool DecodeBase256Segment(BitSource& bits, std::string& result) +static void DecodeBase256Segment(BitSource& bits, Content& result) { // Figure out how long the Base 256 Segment is. int codewordPosition = 1 + bits.byteOffset(); // position is 1-indexed @@ -391,71 +262,105 @@ static bool DecodeBase256Segment(BitSource& bits, std::string& result) // We're seeing NegativeArraySizeException errors from users. if (count < 0) - return false; + throw FormatError("invalid count in Base256 segment"); - ByteArray bytes(count); + result.reserve(count); for (int i = 0; i < count; i++) { - // Have seen this particular error in the wild, such as at + // readBits(8) may fail, have seen this particular error in the wild, such as at // http://www.bcgen.com/demo/IDAutomationStreamingDataMatrix.aspx?MODE=3&D=Fred&PFMT=3&PT=F&X=0.3&O=0&LM=0.2 - if (bits.available() < 8) - return false; - - bytes[i] = (uint8_t)Unrandomize255State(bits.readBits(8), codewordPosition++); + result += narrow_cast(Unrandomize255State(bits.readBits(8), codewordPosition++)); } - - result.append(reinterpret_cast(bytes.data()), bytes.size()); - - return true; } ZXING_EXPORT_TEST_ONLY -DecoderResult Decode(ByteArray&& bytes, const std::string& characterSet, const bool isDMRE) +DecoderResult Decode(ByteArray&& bytes, const bool isDMRE) { BitSource bits(bytes); - std::string result; - result.reserve(100); + Content result; + Error error; + result.symbology = {'d', '1', 3}; // ECC 200 (ISO 16022:2006 Annex N Table N.1) std::string resultTrailer; - std::wstring resultEncoded; - Mode mode = Mode::ASCII_ENCODE; - State state; - state.encoding = CharacterSetECI::InitEncoding(characterSet); - - while (mode != Mode::FORMAT_ERROR && mode != Mode::DONE) { - if (mode == Mode::ASCII_ENCODE) { - mode = DecodeAsciiSegment(bits, result, resultTrailer, resultEncoded, state); - state.firstCodeword = false; - state.firstFNC1Position = -1; // Only recognize in first segment - } else { - bool decodeOK; - switch (mode) { - case C40_ENCODE: [[fallthrough]]; - case TEXT_ENCODE: decodeOK = DecodeC40OrTextSegment(bits, result, mode); break; - case ANSIX12_ENCODE: decodeOK = DecodeAnsiX12Segment(bits, result); break; - case EDIFACT_ENCODE: decodeOK = DecodeEdifactSegment(bits, result); break; - case BASE256_ENCODE: decodeOK = DecodeBase256Segment(bits, result); break; - default: decodeOK = false; break; + + struct StructuredAppendInfo sai; + bool readerInit = false; + bool firstCodeword = true; + bool done = false; + int firstFNC1Position = 1; + Shift128 upperShift; + + // See ISO 16022:2006, 5.2.3 and Annex C, Table C.2 + try { + while (!done && bits.available() >= 8) { + int oneByte = bits.readBits(8); + switch (oneByte) { + case 0: throw FormatError("invalid 0 code word"); + case 129: done = true; break; // Pad -> we are done, ignore the rest of the bits + case 230: DecodeC40OrTextSegment(bits, result, Mode::C40); break; + case 231: DecodeBase256Segment(bits, result); break; + case 232: // FNC1 + // Only recognizing an FNC1 as first/second by codeword position (aka symbol character position), not + // by decoded character position, i.e. not recognizing a C40/Text encoded FNC1 (which requires a latch + // and a shift) + if (bits.byteOffset() == firstFNC1Position) + result.symbology.modifier = '2'; // GS1 + else if (bits.byteOffset() == firstFNC1Position + 1) + result.symbology.modifier = '3'; // AIM, note no AIM Application Indicator format defined, ISO 16022:2006 11.2 + else + result.push_back((char)29); // translate as ASCII 29 + break; + case 233: // Structured Append + if (!firstCodeword) // Must be first ISO 16022:2006 5.6.1 + throw FormatError("structured append tag must be first code word"); + ParseStructuredAppend(bits, sai); + firstFNC1Position = 5; + break; + case 234: // Reader Programming + if (!firstCodeword) // Must be first ISO 16022:2006 5.2.4.9 + throw FormatError("reader programming tag must be first code word"); + readerInit = true; + break; + case 235: upperShift.set = true; break; // Upper Shift (shift to Extended ASCII) + case 236: // ISO 15434 format "05" Macro + result.append("[)>\x1E" "05\x1D"); + resultTrailer.insert(0, "\x1E\x04"); + break; + case 237: // ISO 15434 format "06" Macro + result.append("[)>\x1E" "06\x1D"); + resultTrailer.insert(0, "\x1E\x04"); + break; + case 238: DecodeAnsiX12Segment(bits, result); break; + case 239: DecodeC40OrTextSegment(bits, result, Mode::TEXT); break; + case 240: DecodeEdifactSegment(bits, result); break; + case 241: result.switchEncoding(ParseECIValue(bits)); break; + default: + if (oneByte <= 128) { // ASCII data (ASCII value + 1) + result.push_back(upperShift(oneByte) - 1); + } else if (oneByte <= 229) { // 2-digit data 00-99 (Numeric Value + 130) + int value = oneByte - 130; + if (value < 10) // pad with '0' for single digit values + result.push_back('0'); + result.append(std::to_string(value)); + } else if (oneByte >= 242) { // Not to be used in ASCII encodation + // work around encoders that use unlatch to ASCII as last code word (ask upstream) + if (oneByte == 254 && bits.available() == 0) + break; + throw FormatError("invalid code word"); + } } - mode = decodeOK ? Mode::ASCII_ENCODE : Mode::FORMAT_ERROR; + firstCodeword = false; } + } catch (Error e) { + error = std::move(e); } - if (mode == Mode::FORMAT_ERROR) - return DecodeStatus::FormatError; - - if (state.readerInit && state.sai.index > -1) // Not allowed together ISO 16022:2006 5.2.4.9 - return DecodeStatus::FormatError; - - if (resultTrailer.length() > 0) - result.append(resultTrailer); - - TextDecoder::Append(resultEncoded, reinterpret_cast(result.data()), result.size(), state.encoding); - - std::string symbologyIdentifier("]d" + std::to_string(state.symbologyIdModifier + (isDMRE ? 6 : 0))); + result.append(resultTrailer); + result.applicationIndicator = result.symbology.modifier == '2' ? "GS1" : ""; + result.symbology.modifier += isDMRE * 6; - return DecoderResult(std::move(bytes), std::move(resultEncoded)) - .setSymbologyIdentifier(std::move(symbologyIdentifier)) - .setStructuredAppend(state.sai) - .setReaderInit(state.readerInit); + return DecoderResult(std::move(bytes), std::move(result)) + .setError(std::move(error)) + .setStructuredAppend(sai) + .setReaderInit(readerInit); } } // namespace DecodedBitStreamParser @@ -466,7 +371,7 @@ DecoderResult Decode(ByteArray&& bytes, const std::string& characterSet, const b * * @param codewordBytes data and error correction codewords * @param numDataCodewords number of codewords that are data bytes -* @throws ChecksumException if error correction fails +* @return false if error correction fails */ static bool CorrectErrors(ByteArray& codewordBytes, int numDataCodewords) @@ -485,22 +390,22 @@ CorrectErrors(ByteArray& codewordBytes, int numDataCodewords) return true; } -static DecoderResult DoDecode(const BitMatrix& bits, const std::string& characterSet) +static DecoderResult DoDecode(const BitMatrix& bits) { // Construct a parser and read version, error-correction level const Version* version = VersionForDimensionsOf(bits); if (version == nullptr) - return DecodeStatus::FormatError; + return FormatError("Invalid matrix dimension"); // Read codewords - ByteArray codewords = CodewordsFromBitMatrix(bits); + ByteArray codewords = CodewordsFromBitMatrix(bits, *version); if (codewords.empty()) - return DecodeStatus::FormatError; + return FormatError("Invalid number of code words"); // Separate into data blocks std::vector dataBlocks = GetDataBlocks(codewords, *version); if (dataBlocks.empty()) - return DecodeStatus::FormatError; + return FormatError("Invalid number of data blocks"); // Count total number of data bytes ByteArray resultBytes(TransformReduce(dataBlocks, 0, [](const auto& db) { return db.numDataCodewords; })); @@ -512,7 +417,7 @@ static DecoderResult DoDecode(const BitMatrix& bits, const std::string& characte ByteArray& codewordBytes = dataBlock.codewords; int numDataCodewords = dataBlock.numDataCodewords; if (!CorrectErrors(codewordBytes, numDataCodewords)) - return DecodeStatus::ChecksumError; + return ChecksumError(); for (int i = 0; i < numDataCodewords; i++) { // De-interlace data blocks. @@ -521,7 +426,7 @@ static DecoderResult DoDecode(const BitMatrix& bits, const std::string& characte } // Decode the contents of that stream of bytes - return DecodedBitStreamParser::Decode(std::move(resultBytes), characterSet, version->isDMRE()); + return DecodedBitStreamParser::Decode(std::move(resultBytes), version->isDMRE()); } static BitMatrix FlippedL(const BitMatrix& bits) @@ -533,16 +438,16 @@ static BitMatrix FlippedL(const BitMatrix& bits) return res; } -DecoderResult Decode(const BitMatrix& bits, const std::string& characterSet) +DecoderResult Decode(const BitMatrix& bits) { - auto res = DoDecode(bits, characterSet); + auto res = DoDecode(bits); if (res.isValid()) return res; //TODO: // * unify bit mirroring helper code with QRReader? // * rectangular symbols with the a size of 8 x Y are not supported a.t.m. - if (auto mirroredRes = DoDecode(FlippedL(bits), characterSet); mirroredRes.isValid()) { + if (auto mirroredRes = DoDecode(FlippedL(bits)); mirroredRes.isValid()) { mirroredRes.setIsMirrored(true); return mirroredRes; } diff --git a/core/src/datamatrix/DMDecoder.h b/core/src/datamatrix/DMDecoder.h index cdd135cd96..e8aac914f6 100644 --- a/core/src/datamatrix/DMDecoder.h +++ b/core/src/datamatrix/DMDecoder.h @@ -1,20 +1,10 @@ -#pragma once /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include @@ -25,17 +15,7 @@ class BitMatrix; namespace DataMatrix { -/** - * @brief Decodes a Data Matrix Code represented as a {@link BitMatrix}. A 1 or "true" is taken - * to mean a black module. - * - * @param bits booleans representing white/black Data Matrix Code modules - * @param characterSet initial character encoding to use as a {@link CharacterSetECI} name string - * @return text and bytes encoded within the Data Matrix Code - * @throws FormatException if the Data Matrix Code cannot be decoded - * @throws ChecksumException if error correction fails - */ -DecoderResult Decode(const BitMatrix& bits, const std::string& characterSet = ""); +DecoderResult Decode(const BitMatrix& bits); } // DataMatrix } // ZXing diff --git a/core/src/datamatrix/DMDetector.cpp b/core/src/datamatrix/DMDetector.cpp index 68cc5fff5f..47078d6986 100644 --- a/core/src/datamatrix/DMDetector.cpp +++ b/core/src/datamatrix/DMDetector.cpp @@ -2,19 +2,8 @@ * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors * Copyright 2017 Axel Waggershauser -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "DMDetector.h" @@ -260,9 +249,8 @@ static void OrderByBestPatterns(const ResultPoint*& p0, const ResultPoint*& p1, static DetectorResult DetectOld(const BitMatrix& image) { ResultPoint pointA, pointB, pointC, pointD; - if (!DetectWhiteRect(image, pointA, pointB, pointC, pointD)) { + if (!DetectWhiteRect(image, pointA, pointB, pointC, pointD)) return {}; - } // Point A and D are across the diagonal from one another, // as are B and C. Figure out which are the solid black lines @@ -281,6 +269,10 @@ static DetectorResult DetectOld(const BitMatrix& image) const auto& lSideOne = transitions[0]; const auto& lSideTwo = transitions[1]; + // We accept at most 4 transisions inside the L pattern (i.e. 2 corruptions) to reduce false positive FormatErrors + if (lSideTwo.transitions > 2) + return {}; + // Figure out which point is their intersection by tallying up the number of times we see the // endpoints in the four endpoints. One will show up twice. std::map pointCount; @@ -307,9 +299,8 @@ static DetectorResult DetectOld(const BitMatrix& image) } } - if (bottomRight == nullptr || bottomLeft == nullptr || topLeft == nullptr) { + if (bottomRight == nullptr || bottomLeft == nullptr || topLeft == nullptr) return {}; - } // Bottom left is correct but top left and bottom right might be switched // Use the dot product trick to sort them out @@ -786,7 +777,7 @@ static DetectorResult Scan(EdgeTracer startTracer, std::array 144 || dimR < 8 || dimR > 144 || - std::abs(modSizeX - modSizeY) > 1 || - !image.isIn(PointF{left + modSizeX / 2 + (dimT - 1) * modSize, top + modSizeY / 2 + (dimR - 1) * modSize})) + if (dimT % 2 != 0 || dimR % 2 != 0 || dimT < 10 || dimT > 144 || dimR < 8 || dimR > 144 + || std::abs(modSizeX - modSizeY) > 1 + || !image.isIn(PointF{left + modSizeX / 2 + (dimT - 1) * modSize, top + modSizeY / 2 + (dimR - 1) * modSize})) return {}; int right = left + width - 1; @@ -876,8 +875,24 @@ static DetectorResult DetectPure(const BitMatrix& image) {{left, top}, {right, top}, {right, bottom}, {left, bottom}}}; } -DetectorResult Detect(const BitMatrix& image, bool tryHarder, bool tryRotate, bool isPure) +DetectorResults Detect(const BitMatrix& image, bool tryHarder, bool tryRotate, bool isPure) { +#ifdef __cpp_impl_coroutine + if (isPure) { + co_yield DetectPure(image); + } else { + bool found = false; + for (auto&& r : DetectNew(image, tryHarder, tryRotate)) { + found = true; + co_yield std::move(r); + } + if (!found) { + auto r = DetectOld(image); + if (r.isValid()) + co_yield std::move(r); + } + } +#else if (isPure) return DetectPure(image); @@ -885,6 +900,7 @@ DetectorResult Detect(const BitMatrix& image, bool tryHarder, bool tryRotate, bo if (!result.isValid() && tryHarder) result = DetectOld(image); return result; +#endif } } // namespace ZXing::DataMatrix diff --git a/core/src/datamatrix/DMDetector.h b/core/src/datamatrix/DMDetector.h index 18d727a28b..52668698be 100644 --- a/core/src/datamatrix/DMDetector.h +++ b/core/src/datamatrix/DMDetector.h @@ -1,20 +1,15 @@ -#pragma once /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#ifdef __cpp_impl_coroutine +#include +#include +#endif namespace ZXing { @@ -23,10 +18,13 @@ class DetectorResult; namespace DataMatrix { -/** - * @brief Detects a Data Matrix symbol in an image. - */ -DetectorResult Detect(const BitMatrix& image, bool tryHarder, bool tryRotate, bool isPure); +#ifdef __cpp_impl_coroutine +using DetectorResults = Generator; +#else +using DetectorResults = DetectorResult; +#endif + +DetectorResults Detect(const BitMatrix& image, bool tryHarder, bool tryRotate, bool isPure); } // DataMatrix } // ZXing diff --git a/core/src/datamatrix/DMECEncoder.cpp b/core/src/datamatrix/DMECEncoder.cpp index bedf09442d..484a1d6e5a 100644 --- a/core/src/datamatrix/DMECEncoder.cpp +++ b/core/src/datamatrix/DMECEncoder.cpp @@ -1,19 +1,8 @@ /* * Copyright 2016 Huy Cuong Nguyen * Copyright 2006 Jeremias Maerki. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "DMECEncoder.h" diff --git a/core/src/datamatrix/DMECEncoder.h b/core/src/datamatrix/DMECEncoder.h index a06a298503..aea7d3bce4 100644 --- a/core/src/datamatrix/DMECEncoder.h +++ b/core/src/datamatrix/DMECEncoder.h @@ -1,20 +1,10 @@ -#pragma once /* * Copyright 2016 Huy Cuong Nguyen * Copyright 2006 Jeremias Maerki. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once namespace ZXing { diff --git a/core/src/datamatrix/DMEncoderContext.h b/core/src/datamatrix/DMEncoderContext.h index 5f19b85727..ecd9b0b032 100644 --- a/core/src/datamatrix/DMEncoderContext.h +++ b/core/src/datamatrix/DMEncoderContext.h @@ -1,25 +1,15 @@ -#pragma once /* * Copyright 2016 Huy Cuong Nguyen * Copyright 2006-2007 Jeremias Maerki. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include "ByteArray.h" #include "DMSymbolInfo.h" #include "DMSymbolShape.h" -#include "ZXContainerAlgorithms.h" +#include "ZXAlgorithms.h" #include #include @@ -113,7 +103,7 @@ class EncoderContext } int totalMessageCharCount() const { - return static_cast(_msg.length() - _skipAtEnd); + return narrow_cast(_msg.length() - _skipAtEnd); } int remainingCharacters() const { diff --git a/core/src/datamatrix/DMHighLevelEncoder.cpp b/core/src/datamatrix/DMHighLevelEncoder.cpp index 0b43f6a7eb..9741de5473 100644 --- a/core/src/datamatrix/DMHighLevelEncoder.cpp +++ b/core/src/datamatrix/DMHighLevelEncoder.cpp @@ -1,19 +1,8 @@ /* * Copyright 2016 Huy Cuong Nguyen * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "DMHighLevelEncoder.h" @@ -21,7 +10,7 @@ #include "CharacterSet.h" #include "DMEncoderContext.h" #include "TextEncoder.h" -#include "ZXContainerAlgorithms.h" +#include "ZXAlgorithms.h" #include #include @@ -127,7 +116,7 @@ static uint8_t Randomize253State(uint8_t ch, int codewordPosition) { int pseudoRandom = ((149 * codewordPosition) % 253) + 1; int tempVariable = ch + pseudoRandom; - return static_cast(tempVariable <= 254 ? tempVariable : (tempVariable - 254)); + return narrow_cast(tempVariable <= 254 ? tempVariable : (tempVariable - 254)); } static int FindMinimums(const std::array& intCharCounts, int min, std::array& mins) @@ -168,7 +157,8 @@ static int LookAheadTest(const std::string& msg, size_t startpos, int currentMod //step K if ((startpos + charsProcessed) == msg.length()) { int min = std::numeric_limits::max(); - std::transform(charCounts.begin(), charCounts.end(), intCharCounts.begin(), [](float x) { return static_cast(std::ceil(x)); }); + std::transform(charCounts.begin(), charCounts.end(), intCharCounts.begin(), + [](float x) { return static_cast(std::ceil(x)); }); min = FindMinimums(intCharCounts, min, mins); int minCount = Reduce(mins); @@ -260,7 +250,8 @@ static int LookAheadTest(const std::string& msg, size_t startpos, int currentMod //step R if (charsProcessed >= 4) { - std::transform(charCounts.begin(), charCounts.end(), intCharCounts.begin(), [](float x) { return static_cast(std::ceil(x)); }); + std::transform(charCounts.begin(), charCounts.end(), intCharCounts.begin(), + [](float x) { return static_cast(std::ceil(x)); }); FindMinimums(intCharCounts, std::numeric_limits::max(), mins); int minCount = Reduce(mins); @@ -331,7 +322,7 @@ namespace ASCIIEncoder { static int DetermineConsecutiveDigitCount(const std::string& msg, int startpos) { auto begin = msg.begin() + startpos; - return static_cast(std::find_if_not(begin, msg.end(), IsDigit) - begin); + return narrow_cast(std::find_if_not(begin, msg.end(), IsDigit) - begin); } static uint8_t EncodeASCIIDigits(int digit1, int digit2) @@ -421,7 +412,8 @@ namespace C40Encoder { return len; } - static int BacktrackOneCharacter(EncoderContext& context, std::string& buffer, std::string& removed, int lastCharSize, std::function encodeChar) + static int BacktrackOneCharacter(EncoderContext& context, std::string& buffer, std::string& removed, int lastCharSize, + std::function encodeChar) { buffer.resize(buffer.size() - lastCharSize); context.setCurrentPos(context.currentPos() - 1); @@ -436,8 +428,8 @@ namespace C40Encoder { int c2 = sb.at(startPos + 1); int c3 = sb.at(startPos + 2); int v = (1600 * c1) + (40 * c2) + c3 + 1; - context.addCodeword(static_cast(v / 256)); - context.addCodeword(static_cast(v % 256)); + context.addCodeword(narrow_cast(v / 256)); + context.addCodeword(narrow_cast(v % 256)); } static void WriteNextTriplet(EncoderContext& context, std::string& buffer) @@ -502,7 +494,7 @@ namespace C40Encoder { int c = context.currentChar(); context.setCurrentPos(context.currentPos() + 1); int lastCharSize = encodeChar(c, buffer); - int unwritten = static_cast(buffer.length() / 3) * 2; + int unwritten = narrow_cast(buffer.length() / 3) * 2; int curCodewordCount = context.codewordCount() + unwritten; auto symbolInfo = context.updateSymbolInfo(curCodewordCount); int available = symbolInfo->dataCapacity() - curCodewordCount; @@ -690,17 +682,17 @@ namespace EdifactEncoder { int c4 = len >= 4 ? sb.at(startPos + 3) : 0; int v = (c1 << 18) + (c2 << 12) + (c3 << 6) + c4; - int cw1 = (v >> 16) & 255; - int cw2 = (v >> 8) & 255; - int cw3 = v & 255; + uint8_t cw1 = (v >> 16) & 255; + uint8_t cw2 = (v >> 8) & 255; + uint8_t cw3 = v & 255; ByteArray res; res.reserve(3); - res.push_back(static_cast(cw1)); + res.push_back(cw1); if (len >= 2) { - res.push_back(static_cast(cw2)); + res.push_back(cw2); } if (len >= 3) { - res.push_back(static_cast(cw3)); + res.push_back(cw3); } return res; } diff --git a/core/src/datamatrix/DMHighLevelEncoder.h b/core/src/datamatrix/DMHighLevelEncoder.h index ae5f09abb5..1a17587300 100644 --- a/core/src/datamatrix/DMHighLevelEncoder.h +++ b/core/src/datamatrix/DMHighLevelEncoder.h @@ -1,20 +1,10 @@ -#pragma once /* * Copyright 2016 Huy Cuong Nguyen * Copyright 2006-2007 Jeremias Maerki. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include diff --git a/core/src/datamatrix/DMReader.cpp b/core/src/datamatrix/DMReader.cpp index d134f778bb..06d21a9cce 100644 --- a/core/src/datamatrix/DMReader.cpp +++ b/core/src/datamatrix/DMReader.cpp @@ -1,19 +1,8 @@ /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "DMReader.h" @@ -29,34 +18,38 @@ namespace ZXing::DataMatrix { -Reader::Reader(const DecodeHints& hints) - : _tryRotate(hints.tryRotate()), _tryHarder(hints.tryHarder()), _isPure(hints.isPure()), - _characterSet(hints.characterSet()) +Result Reader::decode(const BinaryBitmap& image) const { +#ifdef __cpp_impl_coroutine + return FirstOrDefault(decode(image, 1)); +#else + auto binImg = image.getBitMatrix(); + if (binImg == nullptr) + return {}; + + auto detectorResult = Detect(*binImg, _hints.tryHarder(), _hints.tryRotate(), _hints.isPure()); + if (!detectorResult.isValid()) + return {}; + + return Result(Decode(detectorResult.bits()), std::move(detectorResult).position(), BarcodeFormat::DataMatrix); +#endif } -/** -* Locates and decodes a Data Matrix code in an image. -* -* @return a string representing the content encoded by the Data Matrix code -* @throws NotFoundException if a Data Matrix code cannot be found -* @throws FormatException if a Data Matrix code cannot be decoded -* @throws ChecksumException if error correction fails -*/ -Result -Reader::decode(const BinaryBitmap& image) const +#ifdef __cpp_impl_coroutine +Results Reader::decode(const BinaryBitmap& image, int maxSymbols) const { auto binImg = image.getBitMatrix(); - if (binImg == nullptr) { - return Result(DecodeStatus::NotFound); + if (binImg == nullptr) + return {}; + + Results results; + for (auto&& res : Detect(*binImg, maxSymbols > 1, _hints.tryRotate(), _hints.isPure())) { + results.push_back(Result(Decode(res.bits()), std::move(res).position(), BarcodeFormat::DataMatrix)); + if (maxSymbols > 0 && Size(results) >= maxSymbols) + break; } - auto detectorResult = Detect(*binImg, _tryHarder, _tryRotate, _isPure); - if (!detectorResult.isValid()) - return Result(DecodeStatus::NotFound); - - return Result(Decode(detectorResult.bits(), _characterSet), - std::move(detectorResult).position(), BarcodeFormat::DataMatrix); + return results; } - +#endif } // namespace ZXing::DataMatrix diff --git a/core/src/datamatrix/DMReader.h b/core/src/datamatrix/DMReader.h index 8a3e0070db..62f67142e1 100644 --- a/core/src/datamatrix/DMReader.h +++ b/core/src/datamatrix/DMReader.h @@ -1,43 +1,24 @@ -#pragma once /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 -#include "Reader.h" -#include - -namespace ZXing { +#pragma once -class DecodeHints; +#include "Reader.h" -namespace DataMatrix { +namespace ZXing::DataMatrix { -/** -* This implementation can detect and decode Data Matrix codes in an image. -* -* @author bbrown@google.com (Brian Brown) -*/ class Reader : public ZXing::Reader { - bool _tryRotate, _tryHarder, _isPure; - std::string _characterSet; public: - explicit Reader(const DecodeHints& hints); + using ZXing::Reader::Reader; + Result decode(const BinaryBitmap& image) const override; +#ifdef __cpp_impl_coroutine + Results decode(const BinaryBitmap& image, int maxSymbols) const override; +#endif }; -} // DataMatrix -} // ZXing +} // namespace ZXing::DataMatrix diff --git a/core/src/datamatrix/DMSymbolInfo.cpp b/core/src/datamatrix/DMSymbolInfo.cpp index 344a0d4832..f3505a69a5 100644 --- a/core/src/datamatrix/DMSymbolInfo.cpp +++ b/core/src/datamatrix/DMSymbolInfo.cpp @@ -1,24 +1,13 @@ /* * Copyright 2016 Huy Cuong Nguyen * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "DMSymbolInfo.h" #include "DMSymbolShape.h" -#include "ZXContainerAlgorithms.h" +#include "ZXAlgorithms.h" #include "ZXTestSupport.h" #include @@ -26,7 +15,7 @@ namespace ZXing::DataMatrix { -static const SymbolInfo PROD_SYMBOLS[] = { +static constexpr const SymbolInfo PROD_SYMBOLS[] = { { false, 3, 5, 8, 8, 1 }, { false, 5, 7, 10, 10, 1 }, { true, 5, 7, 16, 6, 1 }, diff --git a/core/src/datamatrix/DMSymbolInfo.h b/core/src/datamatrix/DMSymbolInfo.h index feb5276b67..fa366da4a1 100644 --- a/core/src/datamatrix/DMSymbolInfo.h +++ b/core/src/datamatrix/DMSymbolInfo.h @@ -1,20 +1,10 @@ -#pragma once /* * Copyright 2016 Huy Cuong Nguyen * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once namespace ZXing { namespace DataMatrix { @@ -33,15 +23,21 @@ class SymbolInfo int _rsBlockError; public: - SymbolInfo(bool rectangular, int dataCapacity, int errorCodewords, int matrixWidth, int matrixHeight, int dataRegions) : - SymbolInfo(rectangular, dataCapacity, errorCodewords, matrixWidth, matrixHeight, dataRegions, dataCapacity, errorCodewords) {} - - SymbolInfo(bool rectangular, int dataCapacity, int errorCodewords, int matrixWidth, int matrixHeight, int dataRegions, int rsBlockData, int rsBlockError) : - _rectangular(rectangular), _dataCapacity(dataCapacity), _errorCodewords(errorCodewords), - _matrixWidth(matrixWidth), _matrixHeight(matrixHeight), _dataRegions(dataRegions), - _rsBlockData(rsBlockData), _rsBlockError(rsBlockError) - { - } + constexpr SymbolInfo(bool rectangular, int dataCapacity, int errorCodewords, int matrixWidth, int matrixHeight, int dataRegions) + : SymbolInfo(rectangular, dataCapacity, errorCodewords, matrixWidth, matrixHeight, dataRegions, dataCapacity, errorCodewords) + {} + + constexpr SymbolInfo(bool rectangular, int dataCapacity, int errorCodewords, int matrixWidth, int matrixHeight, int dataRegions, + int rsBlockData, int rsBlockError) + : _rectangular(rectangular), + _dataCapacity(dataCapacity), + _errorCodewords(errorCodewords), + _matrixWidth(matrixWidth), + _matrixHeight(matrixHeight), + _dataRegions(dataRegions), + _rsBlockData(rsBlockData), + _rsBlockError(rsBlockError) + {} static const SymbolInfo* Lookup(int dataCodewords); static const SymbolInfo* Lookup(int dataCodewords, SymbolShape shape); @@ -52,57 +48,32 @@ class SymbolInfo int verticalDataRegions() const; - int symbolDataWidth() const { - return horizontalDataRegions() * _matrixWidth; - } + int symbolDataWidth() const { return horizontalDataRegions() * _matrixWidth; } - int symbolDataHeight() const { - return verticalDataRegions() * _matrixHeight; - } + int symbolDataHeight() const { return verticalDataRegions() * _matrixHeight; } - int symbolWidth() const { - return symbolDataWidth() + (horizontalDataRegions() * 2); - } + int symbolWidth() const { return symbolDataWidth() + (horizontalDataRegions() * 2); } - int symbolHeight() const { - return symbolDataHeight() + (verticalDataRegions() * 2); - } + int symbolHeight() const { return symbolDataHeight() + (verticalDataRegions() * 2); } - int matrixWidth() const { - return _matrixWidth; - } + int matrixWidth() const { return _matrixWidth; } - int matrixHeight() const { - return _matrixHeight; - } + int matrixHeight() const { return _matrixHeight; } - int codewordCount() const { - return _dataCapacity + _errorCodewords; - } + int codewordCount() const { return _dataCapacity + _errorCodewords; } - int interleavedBlockCount() const { - if (_rsBlockData > 0) - return _dataCapacity / _rsBlockData; - return 10; // Symbol 144 - } + int interleavedBlockCount() const { return _rsBlockData > 0 ? _dataCapacity / _rsBlockData : 10; /* Symbol 144 */ } - int dataCapacity() const { - return _dataCapacity; - } + int dataCapacity() const { return _dataCapacity; } - int errorCodewords() const { - return _errorCodewords; - } + int errorCodewords() const { return _errorCodewords; } - int dataLengthForInterleavedBlock(int index) const { - if (_rsBlockData > 0) - return _rsBlockData; - return index <= 8 ? 156 : 155; // Symbol 144 + int dataLengthForInterleavedBlock(int index) const + { + return _rsBlockData > 0 ? _rsBlockData : (index <= 8 ? 156 : 155); /* Symbol 144 */ } - int errorLengthForInterleavedBlock() const { - return _rsBlockError; - } + int errorLengthForInterleavedBlock() const { return _rsBlockError; } }; } // DataMatrix diff --git a/core/src/datamatrix/DMSymbolShape.h b/core/src/datamatrix/DMSymbolShape.h index 383c1421ca..3c15f5d156 100644 --- a/core/src/datamatrix/DMSymbolShape.h +++ b/core/src/datamatrix/DMSymbolShape.h @@ -1,20 +1,10 @@ -#pragma once /* * Copyright 2016 Huy Cuong Nguyen * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once namespace ZXing { namespace DataMatrix { diff --git a/core/src/datamatrix/DMVersion.cpp b/core/src/datamatrix/DMVersion.cpp index f119e82865..79426eeb41 100644 --- a/core/src/datamatrix/DMVersion.cpp +++ b/core/src/datamatrix/DMVersion.cpp @@ -1,19 +1,8 @@ /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "DMVersion.h" diff --git a/core/src/datamatrix/DMVersion.h b/core/src/datamatrix/DMVersion.h index 87e22fa519..ad9837a78b 100644 --- a/core/src/datamatrix/DMVersion.h +++ b/core/src/datamatrix/DMVersion.h @@ -1,20 +1,10 @@ -#pragma once /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once namespace ZXing::DataMatrix { diff --git a/core/src/datamatrix/DMWriter.cpp b/core/src/datamatrix/DMWriter.cpp index fe79e603cb..8c8f7bd3d3 100644 --- a/core/src/datamatrix/DMWriter.cpp +++ b/core/src/datamatrix/DMWriter.cpp @@ -1,19 +1,8 @@ /* * Copyright 2016 Huy Cuong Nguyen * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "DMWriter.h" @@ -24,6 +13,7 @@ #include "DMHighLevelEncoder.h" #include "DMSymbolInfo.h" #include "DMSymbolShape.h" +#include "TextUtfEncoding.h" #include #include @@ -121,4 +111,9 @@ Writer::encode(const std::wstring& contents, int width, int height) const return Inflate(std::move(result), width, height, _quietZone); } +BitMatrix Writer::encode(const std::string& contents, int width, int height) const +{ + return encode(TextUtfEncoding::FromUtf8(contents), width, height); +} + } // namespace ZXing::DataMatrix diff --git a/core/src/datamatrix/DMWriter.h b/core/src/datamatrix/DMWriter.h index e90e8bfda7..f126e6eb35 100644 --- a/core/src/datamatrix/DMWriter.h +++ b/core/src/datamatrix/DMWriter.h @@ -1,20 +1,10 @@ -#pragma once /* * Copyright 2016 Huy Cuong Nguyen * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include @@ -54,6 +44,7 @@ class Writer } BitMatrix encode(const std::wstring& contents, int width, int height) const; + BitMatrix encode(const std::string& contents, int width, int height) const; private: SymbolShape _shapeHint; diff --git a/core/src/maxicode/MCBitMatrixParser.cpp b/core/src/maxicode/MCBitMatrixParser.cpp index 895f2f7544..6b9ee368f7 100644 --- a/core/src/maxicode/MCBitMatrixParser.cpp +++ b/core/src/maxicode/MCBitMatrixParser.cpp @@ -1,19 +1,8 @@ /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "MCBitMatrixParser.h" diff --git a/core/src/maxicode/MCBitMatrixParser.h b/core/src/maxicode/MCBitMatrixParser.h index 5d405926f9..16c8867cdf 100644 --- a/core/src/maxicode/MCBitMatrixParser.h +++ b/core/src/maxicode/MCBitMatrixParser.h @@ -1,20 +1,10 @@ -#pragma once /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once namespace ZXing { diff --git a/core/src/maxicode/MCDecoder.cpp b/core/src/maxicode/MCDecoder.cpp index 15b9a7bfa5..794409da26 100644 --- a/core/src/maxicode/MCDecoder.cpp +++ b/core/src/maxicode/MCDecoder.cpp @@ -1,24 +1,13 @@ /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "MCDecoder.h" #include "ByteArray.h" -#include "CharacterSetECI.h" +#include "CharacterSet.h" #include "DecoderResult.h" #include "DecodeStatus.h" #include "GenericGF.h" @@ -52,9 +41,8 @@ static bool CorrectErrors(ByteArray& codewordBytes, int start, int dataCodewords // First read into an array of ints std::vector codewordsInts(codewords / divisor, 0); for (int i = 0; i < codewords; i++) { - if ((mode == ALL) || (i % 2 == (mode - 1))) { + if ((mode == ALL) || (i % 2 == (mode - 1))) codewordsInts[i / divisor] = codewordBytes[i + start]; - } } if (!ReedSolomonDecode(GenericGF::MaxiCodeField64(), codewordsInts, ecCodewords / divisor)) @@ -63,10 +51,10 @@ static bool CorrectErrors(ByteArray& codewordBytes, int start, int dataCodewords // Copy back into array of bytes -- only need to worry about the bytes that were data // We don't care about errors in the error-correction codewords for (int i = 0; i < dataCodewords; i++) { - if ((mode == ALL) || (i % 2 == (mode - 1))) { - codewordBytes[i + start] = static_cast(codewordsInts[i / divisor]); - } + if ((mode == ALL) || (i % 2 == (mode - 1))) + codewordBytes[i + start] = narrow_cast(codewordsInts[i / divisor]); } + return true; } @@ -77,271 +65,248 @@ static bool CorrectErrors(ByteArray& codewordBytes, int start, int dataCodewords * @author mike32767 * @author Manuel Kasten */ -namespace DecodedBitStreamParser +namespace DecodedBitStreamParser { + +static const short SHI0 = 0x100; +static const short SHI1 = 0x101; +static const short SHI2 = 0x102; +static const short SHI3 = 0x103; +static const short SHI4 = 0x104; +static const short TWSA = 0x105; // two shift A +static const short TRSA = 0x106; // three shift A +static const short LCHA = 0x107; // latch A +static const short LCHB = 0x108; // latch B +static const short LOCK = 0x109; +static const short ECI = 0x10A; +static const short NS = 0x10B; +static const short PAD = 0x10C; + +static const char FS = 0x1C; +static const char GS = 0x1D; +static const char RS = 0x1E; + +// clang-format off +const static std::array CHARSETS[] = { + { // set 0 (A) + '\n', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', + 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', ECI, FS, GS, RS, NS, + ' ', PAD, '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/', + '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', SHI1, SHI2, SHI3, SHI4, LCHB, + }, + { // set 1 (B) + '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', + 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', ECI, FS, GS, RS, NS, + '{', PAD, '}', '~', 0x7F, ';', '<', '=', '>', '?', '[', '\\', ']', '^', '_', ' ', + ',', '.', '/', ':', '@', '!', '|', PAD, TWSA, TRSA, PAD, SHI0, SHI2, SHI3, SHI4, LCHA, + }, + { // set 2 (C) + 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, + 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, ECI, FS, GS, RS, NS, // Note that in original code in Java, NS is not there, which seems to be a bug + 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, 0xAA, 0xAC, 0xB1, 0xB2, 0xB3, 0xB5, 0xB9, 0xBA, 0xBC, 0xBD, 0xBE, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, LCHA, 0x20, LOCK, SHI3, SHI4, LCHB, + }, + { // set 3 (D) + 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, + 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, ECI, FS, GS, RS, NS, + 0xFB, 0xFC, 0xFD, 0xFE, 0xFF, 0xA1, 0xA8, 0xAB, 0xAF, 0xB0, 0xB4, 0xB7, 0xB8, 0xBB, 0xBF, 0x8A, + 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94, LCHA, 0x20, SHI2, LOCK, SHI4, LCHB, + }, + { // set 4 (E) + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, ECI, PAD, PAD, 0x1B, NS, + FS, GS, RS, 0x1F, 0x9F, 0xA0, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA9, 0xAD, 0xAE, 0xB6, + 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, LCHA, 0x20, SHI2, SHI3, LOCK, LCHB, + }, +}; +// clang-format on + +static int GetBit(int bit, const ByteArray& bytes) { - static const short SHI0 = 0x100; - static const short SHI1 = 0x101; - static const short SHI2 = 0x102; - static const short SHI3 = 0x103; - static const short SHI4 = 0x104; - static const short TWSA = 0x105; // two shift A - static const short TRSA = 0x106; // three shift A - static const short LCHA = 0x107; // latch A - static const short LCHB = 0x108; // latch B - static const short LOCK = 0x109; - static const short ECI = 0x10A; - static const short NS = 0x10B; - static const short PAD = 0x10C; - - static const char FS = 0x1C; - static const char GS = 0x1D; - static const char RS = 0x1E; - - const static std::array CHARSETS[] = { - { // set 0 (A) - '\n', 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', - 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', ECI, FS, GS, RS, NS, - ' ', PAD, '"', '#', '$', '%', '&', '\'', '(', ')', '*', '+', ',', '-', '.', '/', - '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', ':', SHI1, SHI2, SHI3, SHI4, LCHB, - }, - { // set 1 (B) - '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', - 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', ECI, FS, GS, RS, NS, - '{', PAD, '}', '~', 0x7F, ';', '<', '=', '>', '?', '[', '\\', ']', '^', '_', ' ', - ',', '.', '/', ':', '@', '!', '|', PAD, TWSA, TRSA, PAD, SHI0, SHI2, SHI3, SHI4, LCHA, - }, - { // set 2 (C) - 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, - 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, ECI, FS, GS, RS, NS, // Note that in original code in Java, NS is not there, which seems to be a bug - 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, 0xAA, 0xAC, 0xB1, 0xB2, 0xB3, 0xB5, 0xB9, 0xBA, 0xBC, 0xBD, 0xBE, - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, LCHA, 0x20, LOCK, SHI3, SHI4, LCHB, - }, - { // set 3 (D) - 0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, - 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8, 0xF9, 0xFA, ECI, FS, GS, RS, NS, - 0xFB, 0xFC, 0xFD, 0xFE, 0xFF, 0xA1, 0xA8, 0xAB, 0xAF, 0xB0, 0xB4, 0xB7, 0xB8, 0xBB, 0xBF, 0x8A, - 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94, LCHA, 0x20, SHI2, LOCK, SHI4, LCHB, - }, - { // set 4 (E) - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, ECI, PAD, PAD, 0x1B, NS, - FS, GS, RS, 0x1F, 0x9F, 0xA0, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA9, 0xAD, 0xAE, 0xB6, - 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, LCHA, 0x20, SHI2, SHI3, LOCK, LCHB, - }, - }; + bit--; + return (bytes[bit / 6] & (1 << (5 - (bit % 6)))) == 0 ? 0 : 1; +} - static int GetBit(int bit, const ByteArray& bytes) - { - bit--; - return (bytes[bit / 6] & (1 << (5 - (bit % 6)))) == 0 ? 0 : 1; - } +static int GetInt(const ByteArray& bytes, const ByteArray& x) +{ + int len = Size(x); + int val = 0; + for (int i = 0; i < len; i++) + val += GetBit(x[i], bytes) << (len - i - 1); - static int GetInt(const ByteArray& bytes, const ByteArray& x) - { - int len = Size(x); - int val = 0; - for (int i = 0; i < len; i++) { - val += GetBit(x[i], bytes) << (len - i - 1); - } - return val; - } + return val; +} - static int GetPostCode2(const ByteArray& bytes) - { - return GetInt(bytes, { 33, 34, 35, 36, 25, 26, 27, 28, 29, 30, 19, 20, 21, 22, 23, 24, 13, 14, 15, 16, 17, 18, 7, 8, 9, 10, 11, 12, 1, 2 }); - } +static int GetPostCode2(const ByteArray& bytes) +{ + return GetInt(bytes, + {33, 34, 35, 36, 25, 26, 27, 28, 29, 30, 19, 20, 21, 22, 23, 24, 13, 14, 15, 16, 17, 18, 7, 8, 9, 10, 11, 12, 1, 2}); +} - static int GetPostCode2Length(const ByteArray& bytes) { - return GetInt(bytes, { 39, 40, 41, 42, 31, 32 }); - } - - static std::string GetPostCode3(const ByteArray& bytes) - { - return { - (char) CHARSETS[0].at(GetInt(bytes, { 39, 40, 41, 42, 31, 32 })), - (char) CHARSETS[0].at(GetInt(bytes, { 33, 34, 35, 36, 25, 26 })), - (char) CHARSETS[0].at(GetInt(bytes, { 27, 28, 29, 30, 19, 20 })), - (char) CHARSETS[0].at(GetInt(bytes, { 21, 22, 23, 24, 13, 14 })), - (char) CHARSETS[0].at(GetInt(bytes, { 15, 16, 17, 18, 7, 8 })), - (char) CHARSETS[0].at(GetInt(bytes, { 9, 10, 11, 12, 1, 2 })), - }; - } +static int GetPostCode2Length(const ByteArray& bytes) +{ + return GetInt(bytes, {39, 40, 41, 42, 31, 32}); +} +static std::string GetPostCode3(const ByteArray& bytes) +{ + return { + (char) CHARSETS[0].at(GetInt(bytes, { 39, 40, 41, 42, 31, 32 })), + (char) CHARSETS[0].at(GetInt(bytes, { 33, 34, 35, 36, 25, 26 })), + (char) CHARSETS[0].at(GetInt(bytes, { 27, 28, 29, 30, 19, 20 })), + (char) CHARSETS[0].at(GetInt(bytes, { 21, 22, 23, 24, 13, 14 })), + (char) CHARSETS[0].at(GetInt(bytes, { 15, 16, 17, 18, 7, 8 })), + (char) CHARSETS[0].at(GetInt(bytes, { 9, 10, 11, 12, 1, 2 })), + }; +} - static std::string ToString(int x, int width) - { - std::stringstream buf; - buf << std::setw(width) << std::setfill('0') << x; - return buf.str(); - } +static std::string ToString(int x, int width) +{ + std::stringstream buf; + buf << std::setw(width) << std::setfill('0') << x; + return buf.str(); +} - static int GetCountry(const ByteArray& bytes) - { - return GetInt(bytes, { 53, 54, 43, 44, 45, 46, 47, 48, 37, 38 }); - } +static int GetCountry(const ByteArray& bytes) +{ + return GetInt(bytes, {53, 54, 43, 44, 45, 46, 47, 48, 37, 38}); +} - static int GetServiceClass(const ByteArray& bytes) - { - return GetInt(bytes, { 55, 56, 57, 58, 59, 60, 49, 50, 51, 52 }); - } +static int GetServiceClass(const ByteArray& bytes) +{ + return GetInt(bytes, {55, 56, 57, 58, 59, 60, 49, 50, 51, 52}); +} - /** - * See ISO/IEC 16023:2000 Section 4.6 Table 3 - */ - static int ParseECIValue(const ByteArray& bytes, int& i) - { - int firstByte = bytes[++i]; - if ((firstByte & 0x20) == 0) { - return firstByte; - } - int secondByte = bytes[++i]; - if ((firstByte & 0x10) == 0) { - return ((firstByte & 0x0F) << 6) | secondByte; - } - int thirdByte = bytes[++i]; - if ((firstByte & 0x08) == 0) { - return ((firstByte & 0x07) << 12) | (secondByte << 6) | thirdByte; - } - int fourthByte = bytes[++i]; - return ((firstByte & 0x03) << 18) | (secondByte << 12) | (thirdByte << 6) | fourthByte; - } +/** + * See ISO/IEC 16023:2000 Section 4.6 Table 3 + */ +static ZXing::ECI ParseECIValue(const ByteArray& bytes, int& i) +{ + int firstByte = bytes[++i]; + if ((firstByte & 0x20) == 0) + return ZXing::ECI(firstByte); - /** - * See ISO/IEC 16023:2000 Section 4.9.1 Table 5 - */ - static void ParseStructuredAppend(const ByteArray& bytes, int& i, StructuredAppendInfo& sai) - { - const int byte = bytes[++i]; - sai.index = (byte >> 3) & 0x07; - sai.count = (byte & 0x07) + 1; - if (sai.count == 1 || sai.count <= sai.index) { // If info doesn't make sense - sai.count = 0; // Choose to mark count as unknown - } - // No id - } + int secondByte = bytes[++i]; + if ((firstByte & 0x10) == 0) + return ZXing::ECI(((firstByte & 0x0F) << 6) | secondByte); - static std::wstring GetMessage(const ByteArray& bytes, int start, int len, const std::string& characterSet, - StructuredAppendInfo& sai) - { - std::string sb; - std::wstring sbEncoded; - int shift = -1; - int set = 0; - int lastset = 0; - CharacterSet encoding = CharacterSetECI::InitEncoding(characterSet); - - for (int i = start; i < start + len; i++) { - int c = CHARSETS[set].at(bytes[i]); - switch (c) { - case LCHA: - set = 0; - shift = -1; - break; - case LCHB: - set = 1; - shift = -1; - break; - case SHI0: - case SHI1: - case SHI2: - case SHI3: - case SHI4: - lastset = set; - set = c - SHI0; - shift = 1; - break; - case TWSA: - lastset = set; - set = 0; - shift = 2; - break; - case TRSA: - lastset = set; - set = 0; - shift = 3; - break; - case NS: - sb.append(ToString((bytes[i+1] << 24) + (bytes[i+2] << 18) + (bytes[i+3] << 12) + (bytes[i+4] << 6) + bytes[i+5], 9)); - i += 5; - break; - case LOCK: - shift = -1; - break; - case ECI: - encoding = CharacterSetECI::OnChangeAppendReset(ParseECIValue(bytes, i), sbEncoded, sb, encoding); - break; - case PAD: - if (i == start) { - ParseStructuredAppend(bytes, i, sai); - } - shift = -1; - break; - default: - sb.push_back((unsigned char) c); - } - if (shift-- == 0) { - set = lastset; - } - } - TextDecoder::Append(sbEncoded, reinterpret_cast(sb.data()), sb.size(), encoding); - return sbEncoded; - } + int thirdByte = bytes[++i]; + if ((firstByte & 0x08) == 0) + return ZXing::ECI(((firstByte & 0x07) << 12) | (secondByte << 6) | thirdByte); - ZXING_EXPORT_TEST_ONLY - DecoderResult Decode(ByteArray&& bytes, const int mode, const std::string& characterSet) - { - std::wstring result; - result.reserve(144); - StructuredAppendInfo sai; - switch (mode) { - case 2: - case 3: { - auto postcode = mode == 2 ? ToString(GetPostCode2(bytes), GetPostCode2Length(bytes)) : GetPostCode3(bytes); - auto country = ToString(GetCountry(bytes), 3); - auto service = ToString(GetServiceClass(bytes), 3); - result.append(GetMessage(bytes, 10, 84, characterSet, sai)); - if (result.size() >= 9 && result.compare(0, 7, L"[)>\u001E01\u001D") == 0) { // "[)>" + RS + "01" + GS - result.insert(9, TextDecoder::FromLatin1(postcode + GS + country + GS + service + GS)); - } else { - result.insert(0, TextDecoder::FromLatin1(postcode + GS + country + GS + service + GS)); - } - break; - } - case 4: - case 6: result.append(GetMessage(bytes, 1, 93, characterSet, sai)); break; - case 5: result.append(GetMessage(bytes, 1, 77, characterSet, sai)); break; - } + int fourthByte = bytes[++i]; + return ZXing::ECI(((firstByte & 0x03) << 18) | (secondByte << 12) | (thirdByte << 6) | fourthByte); +} - // As converting character set ECIs ourselves and ignoring/skipping non-character ECIs, not using modifiers - // that indicate ECI protocol (ISO/IEC 16023:2000 Annexe E Table E1) - std::string symbologyIdentifier; - if (mode == 4 || mode == 5) { - symbologyIdentifier = "]U0"; - } - else if (mode == 2 || mode == 3) { - symbologyIdentifier = "]U1"; +/** + * See ISO/IEC 16023:2000 Section 4.9.1 Table 5 + */ +static void ParseStructuredAppend(const ByteArray& bytes, int& i, StructuredAppendInfo& sai) +{ + int byte = bytes[++i]; + sai.index = (byte >> 3) & 0x07; + sai.count = (byte & 0x07) + 1; + if (sai.count == 1 || sai.count <= sai.index) // If info doesn't make sense + sai.count = 0; // Choose to mark count as unknown + // No id +} + +static void GetMessage(const ByteArray& bytes, int start, int len, Content& result, StructuredAppendInfo& sai) +{ + int shift = -1; + int set = 0; + int lastset = 0; + + for (int i = start; i < start + len; i++) { + int c = CHARSETS[set].at(bytes[i]); + switch (c) { + case LCHA: + set = 0; + shift = -1; + break; + case LCHB: + set = 1; + shift = -1; + break; + case SHI0: + case SHI1: + case SHI2: + case SHI3: + case SHI4: + lastset = set; + set = c - SHI0; + shift = 1; + break; + case TWSA: + lastset = set; + set = 0; + shift = 2; + break; + case TRSA: + lastset = set; + set = 0; + shift = 3; + break; + case NS: + result.append( + ToString((bytes[i + 1] << 24) + (bytes[i + 2] << 18) + (bytes[i + 3] << 12) + (bytes[i + 4] << 6) + bytes[i + 5], 9)); + i += 5; + break; + case LOCK: shift = -1; break; + case ECI: result.switchEncoding(ParseECIValue(bytes, i)); break; + case PAD: + if (i == start) + ParseStructuredAppend(bytes, i, sai); + shift = -1; + break; + default: result.push_back(c); } - // No identifier defined for mode 6 - return DecoderResult(std::move(bytes), std::move(result)) - .setEcLevel(std::to_wstring(mode)) - .setSymbologyIdentifier(std::move(symbologyIdentifier)) - .setStructuredAppend(sai) - .setReaderInit(mode == 6); + if (shift-- == 0) + set = lastset; } +} +ZXING_EXPORT_TEST_ONLY +DecoderResult Decode(ByteArray&& bytes, const int mode) +{ + Content result; + result.symbology = {'U', (mode == 2 || mode == 3) ? '1' : '0', 2}; // TODO: No identifier defined for mode 6? + result.defaultCharset = "ISO8859_1"; + StructuredAppendInfo sai; + switch (mode) { + case 2: + case 3: { + auto postcode = mode == 2 ? ToString(GetPostCode2(bytes), GetPostCode2Length(bytes)) : GetPostCode3(bytes); + auto country = ToString(GetCountry(bytes), 3); + auto service = ToString(GetServiceClass(bytes), 3); + GetMessage(bytes, 10, 84, result, sai); + if (result.bytes.asString().compare(0, 7, "[)>\u001E01\u001D") == 0) // "[)>" + RS + "01" + GS + result.insert(9, postcode + GS + country + GS + service + GS); + else + result.insert(0, postcode + GS + country + GS + service + GS); + break; + } + case 4: + case 6: GetMessage(bytes, 1, 93, result, sai); break; + case 5: GetMessage(bytes, 1, 77, result, sai); break; + } + + return DecoderResult(std::move(bytes), std::move(result)) + .setEcLevel(std::to_string(mode)) + .setStructuredAppend(sai) + .setReaderInit(mode == 6); +} } // DecodedBitStreamParser -DecoderResult -Decoder::Decode(const BitMatrix& bits, const std::string& characterSet) +DecoderResult Decode(const BitMatrix& bits) { ByteArray codewords = BitMatrixParser::ReadCodewords(bits); - if (!CorrectErrors(codewords, 0, 10, 10, ALL)) { - return DecodeStatus::ChecksumError; - } + if (!CorrectErrors(codewords, 0, 10, 10, ALL)) + return ChecksumError(); + int mode = codewords[0] & 0x0F; ByteArray datawords; switch (mode) { @@ -349,26 +314,24 @@ Decoder::Decode(const BitMatrix& bits, const std::string& characterSet) case 3: // Structured Carrier Message (alphanumeric postcode) case 4: // Standard Symbol case 6: // Reader Programming - if (CorrectErrors(codewords, 20, 84, 40, EVEN) && CorrectErrors(codewords, 20, 84, 40, ODD)) { + if (CorrectErrors(codewords, 20, 84, 40, EVEN) && CorrectErrors(codewords, 20, 84, 40, ODD)) datawords.resize(94, 0); - } else { - return DecodeStatus::ChecksumError; - } + else + return ChecksumError(); break; case 5: // Full ECC - if (CorrectErrors(codewords, 20, 68, 56, EVEN) && CorrectErrors(codewords, 20, 68, 56, ODD)) { + if (CorrectErrors(codewords, 20, 68, 56, EVEN) && CorrectErrors(codewords, 20, 68, 56, ODD)) datawords.resize(78, 0); - } else { - return DecodeStatus::ChecksumError; - } + else + return ChecksumError(); break; - default: return DecodeStatus::FormatError; + default: return FormatError("Invalid mode"); } std::copy_n(codewords.begin(), 10, datawords.begin()); std::copy_n(codewords.begin() + 20, datawords.size() - 10, datawords.begin() + 10); - return DecodedBitStreamParser::Decode(std::move(datawords), mode, characterSet); + return DecodedBitStreamParser::Decode(std::move(datawords), mode); } } // namespace ZXing::MaxiCode diff --git a/core/src/maxicode/MCDecoder.h b/core/src/maxicode/MCDecoder.h index cbc8bc6d0b..e53f533766 100644 --- a/core/src/maxicode/MCDecoder.h +++ b/core/src/maxicode/MCDecoder.h @@ -1,20 +1,10 @@ -#pragma once /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include @@ -25,17 +15,7 @@ class BitMatrix; namespace MaxiCode { -/** -*

The main class which implements MaxiCode decoding -- as opposed to locating and extracting -* the MaxiCode from an image.

-* -* @author Manuel Kasten -*/ -class Decoder -{ -public: - static DecoderResult Decode(const BitMatrix& bits, const std::string& characterSet); -}; +DecoderResult Decode(const BitMatrix& bits); } // MaxiCode } // ZXing diff --git a/core/src/maxicode/MCReader.cpp b/core/src/maxicode/MCReader.cpp index 36c5a53607..a03e8c76de 100644 --- a/core/src/maxicode/MCReader.cpp +++ b/core/src/maxicode/MCReader.cpp @@ -1,19 +1,8 @@ /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "MCReader.h" @@ -36,9 +25,8 @@ namespace ZXing::MaxiCode { static BitMatrix ExtractPureBits(const BitMatrix& image) { int left, top, width, height; - if (!image.findBoundingBox(left, top, width, height, BitMatrixParser::MATRIX_WIDTH)) { + if (!image.findBoundingBox(left, top, width, height, BitMatrixParser::MATRIX_WIDTH)) return {}; - } // Now just read off the bits BitMatrix result(BitMatrixParser::MATRIX_WIDTH, BitMatrixParser::MATRIX_HEIGHT); @@ -54,23 +42,19 @@ static BitMatrix ExtractPureBits(const BitMatrix& image) return result; } -Reader::Reader(const DecodeHints& hints) : _isPure(hints.isPure()), _characterSet(hints.characterSet()) {} - Result Reader::decode(const BinaryBitmap& image) const { auto binImg = image.getBitMatrix(); - if (binImg == nullptr) { - return Result(DecodeStatus::NotFound); - } + if (binImg == nullptr) + return {}; //TODO: this only works with effectively 'pure' barcodes. Needs proper detector. BitMatrix bits = ExtractPureBits(*binImg); - if (bits.empty()) { - return Result(DecodeStatus::NotFound); - } + if (bits.empty()) + return {}; - return Result(Decoder::Decode(bits, _characterSet), {}, BarcodeFormat::MaxiCode); + return Result(Decode(bits), {}, BarcodeFormat::MaxiCode); } } // namespace ZXing::MaxiCode diff --git a/core/src/maxicode/MCReader.h b/core/src/maxicode/MCReader.h index 5503c856b9..f3cfd75a57 100644 --- a/core/src/maxicode/MCReader.h +++ b/core/src/maxicode/MCReader.h @@ -1,40 +1,21 @@ -#pragma once /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 -#include "Reader.h" - -#include - -namespace ZXing { +#pragma once -class DecodeHints; +#include "Reader.h" -namespace MaxiCode { +namespace ZXing::MaxiCode { class Reader : public ZXing::Reader { - bool _isPure; - std::string _characterSet; - public: - explicit Reader(const DecodeHints& hints); + using ZXing::Reader::Reader; + Result decode(const BinaryBitmap& image) const override; }; -} // MaxiCode -} // ZXing +} // namespace ZXing::MaxiCode diff --git a/core/src/oned/ODCodabarReader.cpp b/core/src/oned/ODCodabarReader.cpp index 354f068511..f72b6ad44c 100644 --- a/core/src/oned/ODCodabarReader.cpp +++ b/core/src/oned/ODCodabarReader.cpp @@ -2,25 +2,14 @@ * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors * Copyright 2020 Axel Waggershauser -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "ODCodabarReader.h" #include "DecodeHints.h" #include "Result.h" -#include "ZXContainerAlgorithms.h" +#include "ZXAlgorithms.h" #include #include @@ -41,11 +30,6 @@ static_assert(Size(ALPHABET) - 1 == Size(CHARACTER_ENCODINGS), "table size misma // some industries use a checksum standard but this is not part of the original codabar standard // for more information see : http://www.mecsw.com/specs/codabar.html -CodabarReader::CodabarReader(const DecodeHints& hints) -{ - _returnStartEnd = hints.returnCodabarStartEnd(); -} - // each character has 4 bars and 3 spaces constexpr int CHAR_LEN = 7; // quiet zone is half the width of a character symbol @@ -72,7 +56,7 @@ CodabarReader::decodePattern(int rowNumber, PatternView& next, std::unique_ptr(next, minCharCount * CHAR_LEN, IsLeftGuard); if (!next.isValid()) - return Result(DecodeStatus::NotFound); + return {}; int xStart = next.pixelsInFront(); int maxInterCharacterSpace = next.sum() / 2; // spec actually says 1 narrow space, width/2 is about 4 @@ -82,33 +66,33 @@ CodabarReader::decodePattern(int rowNumber, PatternView& next, std::unique_ptrDecodes Codabar barcodes.

-* -* @author Bas Vijfwinkel -* @author David Walker -*/ class CodabarReader : public RowReader { public: - explicit CodabarReader(const DecodeHints& hints); - Result decodePattern(int rowNumber, PatternView& next, std::unique_ptr& state) const override; + using RowReader::RowReader; -private: - bool _returnStartEnd; + Result decodePattern(int rowNumber, PatternView& next, std::unique_ptr& state) const override; }; -} // OneD -} // ZXing +} // namespace ZXing::OneD diff --git a/core/src/oned/ODCodabarWriter.cpp b/core/src/oned/ODCodabarWriter.cpp index 48ad392b05..46a50569f9 100644 --- a/core/src/oned/ODCodabarWriter.cpp +++ b/core/src/oned/ODCodabarWriter.cpp @@ -1,24 +1,14 @@ /* * Copyright 2016 Huy Cuong Nguyen * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "ODCodabarWriter.h" #include "ODWriterHelper.h" -#include "ZXContainerAlgorithms.h" +#include "TextUtfEncoding.h" +#include "ZXAlgorithms.h" #include #include @@ -137,4 +127,9 @@ CodabarWriter::encode(const std::wstring& contents_, int width, int height) cons return WriterHelper::RenderResult(result, width, height, _sidesMargin >= 0 ? _sidesMargin : 10); } +BitMatrix CodabarWriter::encode(const std::string& contents, int width, int height) const +{ + return encode(TextUtfEncoding::FromUtf8(contents), width, height); +} + } // namespace ZXing::OneD diff --git a/core/src/oned/ODCodabarWriter.h b/core/src/oned/ODCodabarWriter.h index c4a3f960e8..10914313a7 100644 --- a/core/src/oned/ODCodabarWriter.h +++ b/core/src/oned/ODCodabarWriter.h @@ -1,20 +1,10 @@ -#pragma once /* * Copyright 2016 Huy Cuong Nguyen * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include @@ -34,6 +24,7 @@ class CodabarWriter public: CodabarWriter& setMargin(int sidesMargin) { _sidesMargin = sidesMargin; return *this; } BitMatrix encode(const std::wstring& contents, int width, int height) const; + BitMatrix encode(const std::string& contents, int width, int height) const; private: int _sidesMargin = -1; diff --git a/core/src/oned/ODCode128Patterns.cpp b/core/src/oned/ODCode128Patterns.cpp index 1e9a354057..4500398e1e 100644 --- a/core/src/oned/ODCode128Patterns.cpp +++ b/core/src/oned/ODCode128Patterns.cpp @@ -1,19 +1,8 @@ /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "ODCode128Patterns.h" diff --git a/core/src/oned/ODCode128Patterns.h b/core/src/oned/ODCode128Patterns.h index aeafd2e3cb..391e9be30d 100644 --- a/core/src/oned/ODCode128Patterns.h +++ b/core/src/oned/ODCode128Patterns.h @@ -1,20 +1,10 @@ -#pragma once /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include diff --git a/core/src/oned/ODCode128Reader.cpp b/core/src/oned/ODCode128Reader.cpp index f730999853..9f9f788e2f 100644 --- a/core/src/oned/ODCode128Reader.cpp +++ b/core/src/oned/ODCode128Reader.cpp @@ -1,25 +1,14 @@ /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "ODCode128Reader.h" #include "ODCode128Patterns.h" #include "Result.h" -#include "ZXContainerAlgorithms.h" +#include "ZXAlgorithms.h" #include #include @@ -52,8 +41,9 @@ static const int CODE_STOP = 106; class Raw2TxtDecoder { int codeSet = 0; - std::string _symbologyIdentifier = "]C0"; // ISO/IEC 15417:2007 Annex C Table C.1 + SymbologyIdentifier _symbologyIdentifier = {'C', '0'}; // ISO/IEC 15417:2007 Annex C Table C.1 bool _readerInit = false; + std::string _applicationIndicator; std::string txt; size_t lastTxtSize = 0; @@ -66,17 +56,19 @@ class Raw2TxtDecoder if (txt.empty()) { // ISO/IEC 15417:2007 Annex B.1 and GS1 General Specifications 21.0.1 Section 5.4.3.7 // If the first char after the start code is FNC1 then this is GS1-128. - _symbologyIdentifier = "]C1"; + _symbologyIdentifier.modifier = '1'; // GS1 General Specifications Section 5.4.6.4 // "Transmitted data ... is prefixed by the symbology identifier ]C1, if used." // Choosing not to use symbology identifier, i.e. to not prefix to data. + _applicationIndicator = "GS1"; } else if ((isCodeSetC && txt.size() == 2 && txt[0] >= '0' && txt[0] <= '9' && txt[1] >= '0' && txt[1] <= '9') || (!isCodeSetC && txt.size() == 1 && ((txt[0] >= 'A' && txt[0] <= 'Z') || (txt[0] >= 'a' && txt[0] <= 'z')))) { // ISO/IEC 15417:2007 Annex B.2 // FNC1 in second position following Code Set C "00-99" or Code Set A/B "A-Za-z" - AIM - _symbologyIdentifier = "]C2"; + _symbologyIdentifier.modifier = '2'; + _applicationIndicator = txt; } else { // ISO/IEC 15417:2007 Annex B.3. Otherwise FNC1 is returned as ASCII 29 (GS) @@ -164,8 +156,8 @@ class Raw2TxtDecoder return txt.substr(0, lastTxtSize); } - std::string symbologyIdentifier() const { return _symbologyIdentifier; } - + SymbologyIdentifier symbologyIdentifier() const { return _symbologyIdentifier; } + std::string applicationIndicator() const { return _applicationIndicator; } bool readerInit() const { return _readerInit; } }; @@ -235,57 +227,58 @@ Result Code128Reader::decodePattern(int rowNumber, PatternView& next, std::uniqu next = FindLeftGuard(next, minCharCount * CHAR_LEN, START_PATTERN_PREFIX, QUIET_ZONE); if (!next.isValid()) - return Result(DecodeStatus::NotFound); + return {}; next = next.subView(0, CHAR_LEN); int startCode = decodePattern(next, true); if (!(CODE_START_A <= startCode && startCode <= CODE_START_C)) - return Result(DecodeStatus::NotFound); + return {}; int xStart = next.pixelsInFront(); ByteArray rawCodes; rawCodes.reserve(20); - rawCodes.push_back(static_cast(startCode)); + rawCodes.push_back(narrow_cast(startCode)); Raw2TxtDecoder raw2txt(startCode); while (true) { if (!next.skipSymbol()) - return Result(DecodeStatus::NotFound); + return {}; // Decode another code from image int code = decodePattern(next); if (code == -1) - return Result(DecodeStatus::NotFound); + return {}; if (code == CODE_STOP) break; if (code >= CODE_START_A) - return Result(DecodeStatus::FormatError); + return {}; if (!raw2txt.decode(code)) - return Result(DecodeStatus::FormatError); + return {}; - rawCodes.push_back(static_cast(code)); + rawCodes.push_back(narrow_cast(code)); } if (Size(rawCodes) < minCharCount - 1) // stop code is missing in rawCodes - return Result(DecodeStatus::NotFound); + return {}; // check termination bar (is present and not wider than about 2 modules) and quiet zone (next is now 13 modules // wide, require at least 8) next = next.subView(0, CHAR_LEN + 1); if (!next.isValid() || next[CHAR_LEN] > next.sum(CHAR_LEN) / 4 || !next.hasQuietZoneAfter(QUIET_ZONE/13)) - return Result(DecodeStatus::NotFound); + return {}; + Error error; int checksum = rawCodes.front(); for (int i = 1; i < Size(rawCodes) - 1; ++i) checksum += i * rawCodes[i]; - // the second last code is the checksum (last one is the stop code): + // the last code is the checksum: if (checksum % 103 != rawCodes.back()) - return Result(DecodeStatus::ChecksumError); + error = ChecksumError(); int xStop = next.pixelsTillEnd(); - return Result(raw2txt.text(), rowNumber, xStart, xStop, BarcodeFormat::Code128, raw2txt.symbologyIdentifier(), - std::move(rawCodes), raw2txt.readerInit()); + return Result(raw2txt.text(), rowNumber, xStart, xStop, BarcodeFormat::Code128, raw2txt.symbologyIdentifier(), error, + std::move(rawCodes), raw2txt.readerInit(), raw2txt.applicationIndicator()); } } // namespace ZXing::OneD diff --git a/core/src/oned/ODCode128Reader.h b/core/src/oned/ODCode128Reader.h index ebdc6bf19f..60526fa469 100644 --- a/core/src/oned/ODCode128Reader.h +++ b/core/src/oned/ODCode128Reader.h @@ -1,39 +1,21 @@ -#pragma once /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 -#include "ODRowReader.h" - -namespace ZXing { +#pragma once -class DecodeHints; +#include "ODRowReader.h" -namespace OneD { +namespace ZXing::OneD { -/** -*

Decodes Code 128 barcodes.

-* -* @author Sean Owen -*/ class Code128Reader : public RowReader { public: + using RowReader::RowReader; + Result decodePattern(int rowNumber, PatternView& next, std::unique_ptr&) const override; }; -} // OneD -} // ZXing +} // namespace ZXing::OneD diff --git a/core/src/oned/ODCode128Writer.cpp b/core/src/oned/ODCode128Writer.cpp index 24a097e3bf..b737af2fca 100644 --- a/core/src/oned/ODCode128Writer.cpp +++ b/core/src/oned/ODCode128Writer.cpp @@ -1,24 +1,14 @@ /* * Copyright 2016 Huy Cuong Nguyen * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "ODCode128Writer.h" #include "ODCode128Patterns.h" #include "ODWriterHelper.h" +#include "TextUtfEncoding.h" #include #include @@ -30,10 +20,10 @@ namespace ZXing::OneD { static const int CODE_START_A = 103; static const int CODE_START_B = 104; static const int CODE_START_C = 105; -static const int CODE_CODE_A = 101; -static const int CODE_CODE_B = 100; -static const int CODE_CODE_C = 99; -static const int CODE_STOP = 106; +static const int CODE_CODE_A = 101; +static const int CODE_CODE_B = 100; +static const int CODE_CODE_C = 99; +static const int CODE_STOP = 106; // Dummy characters used to specify control characters in input static const auto ESCAPE_FNC_1 = L'\u00f1'; @@ -41,14 +31,15 @@ static const auto ESCAPE_FNC_2 = L'\u00f2'; static const auto ESCAPE_FNC_3 = L'\u00f3'; static const auto ESCAPE_FNC_4 = L'\u00f4'; -static const int CODE_FNC_1 = 102; // Code A, Code B, Code C -static const int CODE_FNC_2 = 97; // Code A, Code B -static const int CODE_FNC_3 = 96; // Code A, Code B +static const int CODE_FNC_1 = 102; // Code A, Code B, Code C +static const int CODE_FNC_2 = 97; // Code A, Code B +static const int CODE_FNC_3 = 96; // Code A, Code B static const int CODE_FNC_4_A = 101; // Code A static const int CODE_FNC_4_B = 100; // Code B - // Results of minimal lookahead for code C -enum class CType { +// Results of minimal lookahead for code C +enum class CType +{ UNCODABLE, ONE_DIGIT, TWO_DIGITS, @@ -262,4 +253,9 @@ Code128Writer::encode(const std::wstring& contents, int width, int height) const return WriterHelper::RenderResult(result, width, height, _sidesMargin >= 0 ? _sidesMargin : 10); } +BitMatrix Code128Writer::encode(const std::string& contents, int width, int height) const +{ + return encode(TextUtfEncoding::FromUtf8(contents), width, height); +} + } // namespace ZXing::OneD diff --git a/core/src/oned/ODCode128Writer.h b/core/src/oned/ODCode128Writer.h index 4efb1c52cd..386bf5cefc 100644 --- a/core/src/oned/ODCode128Writer.h +++ b/core/src/oned/ODCode128Writer.h @@ -1,20 +1,10 @@ -#pragma once /* * Copyright 2016 Huy Cuong Nguyen * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include @@ -34,6 +24,7 @@ class Code128Writer public: Code128Writer& setMargin(int sidesMargin) { _sidesMargin = sidesMargin; return *this; } BitMatrix encode(const std::wstring& contents, int width, int height) const; + BitMatrix encode(const std::string& contents, int width, int height) const; private: int _sidesMargin = -1; diff --git a/core/src/oned/ODCode39Reader.cpp b/core/src/oned/ODCode39Reader.cpp index 58c1a70871..6824075fe0 100644 --- a/core/src/oned/ODCode39Reader.cpp +++ b/core/src/oned/ODCode39Reader.cpp @@ -1,25 +1,15 @@ /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "ODCode39Reader.h" #include "DecodeHints.h" +#include "DecoderResult.h" #include "Result.h" -#include "ZXContainerAlgorithms.h" +#include "ZXAlgorithms.h" #include @@ -85,17 +75,10 @@ DecodeExtendedCode39AndCode93(std::string& encoded, const char ctrl[4]) return true; } - -Code39Reader::Code39Reader(const DecodeHints& hints) : - _extendedMode(hints.tryCode39ExtendedMode()), - _validateCheckSum(hints.validateCode39CheckSum()) -{ -} - Result Code39Reader::decodePattern(int rowNumber, PatternView& next, std::unique_ptr&) const { // minimal number of characters that must be present (including start, stop and checksum characters) - int minCharCount = _validateCheckSum ? 4 : 3; + int minCharCount = _hints.validateCode39CheckSum() ? 4 : 3; auto isStartOrStopSymbol = [](char c) { return c == '*'; }; // provide the indices with the narrow bars/spaces which have to be equally wide @@ -105,10 +88,10 @@ Result Code39Reader::decodePattern(int rowNumber, PatternView& next, std::unique next = FindLeftGuard(next, minCharCount * CHAR_LEN, START_PATTERN, QUIET_ZONE_SCALE * 12); if (!next.isValid()) - return Result(DecodeStatus::NotFound); + return {}; if (!isStartOrStopSymbol(DecodeNarrowWidePattern(next, CHARACTER_ENCODINGS, ALPHABET))) // read off the start pattern - return Result(DecodeStatus::NotFound); + return {}; int xStart = next.pixelsInFront(); int maxInterCharacterSpace = next.sum() / 2; // spec actually says 1 narrow space, width/2 is about 4 @@ -119,38 +102,37 @@ Result Code39Reader::decodePattern(int rowNumber, PatternView& next, std::unique do { // check remaining input width and inter-character space if (!next.skipSymbol() || !next.skipSingle(maxInterCharacterSpace)) - return Result(DecodeStatus::NotFound); + return {}; txt += DecodeNarrowWidePattern(next, CHARACTER_ENCODINGS, ALPHABET); if (txt.back() == 0) - return Result(DecodeStatus::NotFound); + return {}; } while (!isStartOrStopSymbol(txt.back())); txt.pop_back(); // remove asterisk // check txt length and whitespace after the last char. See also FindStartPattern. if (Size(txt) < minCharCount - 2 || !next.hasQuietZoneAfter(QUIET_ZONE_SCALE)) - return Result(DecodeStatus::NotFound); + return {}; - if (_validateCheckSum) { + Error error; + if (_hints.validateCode39CheckSum()) { auto checkDigit = txt.back(); txt.pop_back(); int checksum = TransformReduce(txt, 0, [](char c) { return IndexOf(ALPHABET, c); }); if (checkDigit != ALPHABET[checksum % 43]) - return Result(DecodeStatus::ChecksumError); + error = ChecksumError(); } - if (_extendedMode && !DecodeExtendedCode39AndCode93(txt, "$%/+")) - return Result(DecodeStatus::FormatError); + if (!error && _hints.tryCode39ExtendedMode() && !DecodeExtendedCode39AndCode93(txt, "$%/+")) + error = FormatError("Decoding extended Code39/Code93 failed"); // Symbology identifier modifiers ISO/IEC 16388:2007 Annex C Table C.1 - static const int symbologyModifiers[4] = { 0, 3 /*checksum*/, 4 /*extended*/, 7 /*checksum,extended*/ }; - int symbologyIdModifier = symbologyModifiers[(int)_extendedMode * 2 + (int)_validateCheckSum]; - - std::string symbologyIdentifier("]A" + std::to_string(symbologyIdModifier)); + constexpr const char symbologyModifiers[4] = { '0', '3' /*checksum*/, '4' /*extended*/, '7' /*checksum,extended*/ }; + SymbologyIdentifier symbologyIdentifier = {'A', symbologyModifiers[(int)_hints.tryCode39ExtendedMode() * 2 + (int)_hints.validateCode39CheckSum()]}; int xStop = next.pixelsTillEnd(); - return Result(txt, rowNumber, xStart, xStop, BarcodeFormat::Code39, std::move(symbologyIdentifier)); + return Result(std::move(txt), rowNumber, xStart, xStop, BarcodeFormat::Code39, symbologyIdentifier, error); } } // namespace ZXing::OneD diff --git a/core/src/oned/ODCode39Reader.h b/core/src/oned/ODCode39Reader.h index 5c5daef9f8..51b7139fe8 100644 --- a/core/src/oned/ODCode39Reader.h +++ b/core/src/oned/ODCode39Reader.h @@ -1,35 +1,15 @@ -#pragma once /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 -#include "ODRowReader.h" - -namespace ZXing { +#pragma once -class DecodeHints; +#include "ODRowReader.h" -namespace OneD { +namespace ZXing::OneD { -/** -*

Decodes Code 39 barcodes. Supports "Full ASCII Code 39" if extendedMode is true.

-* -* @author Sean Owen -* @see Code93Reader -*/ class Code39Reader : public RowReader { public: @@ -37,20 +17,10 @@ class Code39Reader : public RowReader * Creates a reader that can be configured to check the last character as a check digit, * or optionally attempt to decode "extended Code 39" sequences that are used to encode * the full ASCII character set. - * - * @param usingCheckDigit if true, treat the last data character as a check digit, not - * data, and verify that the checksum passes. - * @param extendedMode if true, will attempt to decode extended Code 39 sequences in the - * text. */ - explicit Code39Reader(const DecodeHints& hints); - - Result decodePattern(int rowNumber, PatternView& next, std::unique_ptr&) const override; + using RowReader::RowReader; -private: - bool _extendedMode; - bool _validateCheckSum; + Result decodePattern(int rowNumber, PatternView& next, std::unique_ptr&) const override; }; -} // OneD -} // ZXing +} // namespace ZXing::OneD diff --git a/core/src/oned/ODCode39Writer.cpp b/core/src/oned/ODCode39Writer.cpp index 919e59f250..49347f3964 100644 --- a/core/src/oned/ODCode39Writer.cpp +++ b/core/src/oned/ODCode39Writer.cpp @@ -1,26 +1,16 @@ /* * Copyright 2016 Huy Cuong Nguyen * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "ODCode39Writer.h" #include "CharacterSet.h" #include "ODWriterHelper.h" #include "TextEncoder.h" -#include "ZXContainerAlgorithms.h" +#include "TextUtfEncoding.h" +#include "ZXAlgorithms.h" #include #include @@ -178,4 +168,9 @@ Code39Writer::encode(const std::wstring& contents, int width, int height) const return WriterHelper::RenderResult(result, width, height, _sidesMargin >= 0 ? _sidesMargin : 10); } +BitMatrix Code39Writer::encode(const std::string& contents, int width, int height) const +{ + return encode(TextUtfEncoding::FromUtf8(contents), width, height); +} + } // namespace ZXing::OneD diff --git a/core/src/oned/ODCode39Writer.h b/core/src/oned/ODCode39Writer.h index 6d57e493d5..20194b572f 100644 --- a/core/src/oned/ODCode39Writer.h +++ b/core/src/oned/ODCode39Writer.h @@ -1,20 +1,10 @@ -#pragma once /* * Copyright 2016 Huy Cuong Nguyen * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include @@ -34,6 +24,7 @@ class Code39Writer public: Code39Writer& setMargin(int sidesMargin) { _sidesMargin = sidesMargin; return *this; } BitMatrix encode(const std::wstring& contents, int width, int height) const; + BitMatrix encode(const std::string& contents, int width, int height) const; private: int _sidesMargin = -1; diff --git a/core/src/oned/ODCode93Reader.cpp b/core/src/oned/ODCode93Reader.cpp index d9f3dd6859..cfeaa0db3f 100644 --- a/core/src/oned/ODCode93Reader.cpp +++ b/core/src/oned/ODCode93Reader.cpp @@ -2,24 +2,13 @@ * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors * Copyright 2020 Axel Waggershauser -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "ODCode93Reader.h" #include "Result.h" -#include "ZXContainerAlgorithms.h" +#include "ZXAlgorithms.h" #include #include @@ -98,7 +87,7 @@ Result Code93Reader::decodePattern(int rowNumber, PatternView& next, std::unique next = FindLeftGuard(next, minCharCount * CHAR_LEN, IsStartGuard); if (!next.isValid()) - return Result(DecodeStatus::NotFound); + return {}; int xStart = next.pixelsInFront(); @@ -108,37 +97,38 @@ Result Code93Reader::decodePattern(int rowNumber, PatternView& next, std::unique do { // check remaining input width if (!next.skipSymbol()) - return Result(DecodeStatus::NotFound); + return {}; txt += LookupBitPattern(OneToFourBitPattern(next), CHARACTER_ENCODINGS, ALPHABET); if (txt.back() == 0) - return Result(DecodeStatus::NotFound); + return {}; } while (txt.back() != '*'); txt.pop_back(); // remove asterisk if (Size(txt) < minCharCount - 2) - return Result(DecodeStatus::NotFound); + return {}; // check termination bar (is present and not wider than about 2 modules) and quiet zone next = next.subView(0, CHAR_LEN + 1); if (!next.isValid() || next[CHAR_LEN] > next.sum(CHAR_LEN) / 4 || !next.hasQuietZoneAfter(QUIET_ZONE_SCALE)) - return Result(DecodeStatus::NotFound); + return {}; + Error error; if (!CheckChecksums(txt)) - return Result(DecodeStatus::ChecksumError); + error = ChecksumError(); // Remove checksum digits txt.resize(txt.size() - 2); - if (!DecodeExtendedCode39AndCode93(txt, "abcd")) - return Result(DecodeStatus::FormatError); + if (!error && !DecodeExtendedCode39AndCode93(txt, "abcd")) + error = FormatError("Decoding extended Code39/Code93 failed"); // Symbology identifier ISO/IEC 15424:2008 4.4.10 no modifiers - std::string symbologyIdentifier("]G0"); + SymbologyIdentifier symbologyIdentifier = {'G', '0'}; int xStop = next.pixelsTillEnd(); - return Result(txt, rowNumber, xStart, xStop, BarcodeFormat::Code93, std::move(symbologyIdentifier)); + return Result(txt, rowNumber, xStart, xStop, BarcodeFormat::Code93, symbologyIdentifier, error); } } // namespace ZXing::OneD diff --git a/core/src/oned/ODCode93Reader.h b/core/src/oned/ODCode93Reader.h index 95a385e0ad..b8ea6125d0 100644 --- a/core/src/oned/ODCode93Reader.h +++ b/core/src/oned/ODCode93Reader.h @@ -1,37 +1,21 @@ -#pragma once /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include "ODRowReader.h" -namespace ZXing { -namespace OneD { +namespace ZXing::OneD { -/** -*

Decodes Code 93 barcodes.

-* -* @author Sean Owen -* @see Code39Reader -*/ class Code93Reader : public RowReader { public: + using RowReader::RowReader; + Result decodePattern(int rowNumber, PatternView& next, std::unique_ptr&) const override; }; -} // OneD -} // ZXing +} // namespace ZXing::OneD diff --git a/core/src/oned/ODCode93Writer.cpp b/core/src/oned/ODCode93Writer.cpp index dfc42113aa..9cca0771db 100644 --- a/core/src/oned/ODCode93Writer.cpp +++ b/core/src/oned/ODCode93Writer.cpp @@ -1,24 +1,14 @@ /* * Copyright 2016 Huy Cuong Nguyen * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "ODCode93Writer.h" #include "ODWriterHelper.h" -#include "ZXContainerAlgorithms.h" +#include "TextUtfEncoding.h" +#include "ZXAlgorithms.h" #include "ZXTestSupport.h" #include @@ -194,4 +184,9 @@ Code93Writer::encode(const std::wstring& contents_, int width, int height) const return WriterHelper::RenderResult(result, width, height, _sidesMargin >= 0 ? _sidesMargin : 10); } +BitMatrix Code93Writer::encode(const std::string& contents, int width, int height) const +{ + return encode(TextUtfEncoding::FromUtf8(contents), width, height); +} + } // namespace ZXing::OneD diff --git a/core/src/oned/ODCode93Writer.h b/core/src/oned/ODCode93Writer.h index 1a6dd09e46..40654c8ccf 100644 --- a/core/src/oned/ODCode93Writer.h +++ b/core/src/oned/ODCode93Writer.h @@ -1,20 +1,10 @@ -#pragma once /* * Copyright 2016 Huy Cuong Nguyen * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include @@ -32,6 +22,7 @@ class Code93Writer public: Code93Writer& setMargin(int sidesMargin) { _sidesMargin = sidesMargin; return *this; } BitMatrix encode(const std::wstring& contents, int width, int height) const; + BitMatrix encode(const std::string& contents, int width, int height) const; private: int _sidesMargin = -1; diff --git a/core/src/oned/ODDataBarCommon.cpp b/core/src/oned/ODDataBarCommon.cpp index aba8505311..57773f9dc6 100644 --- a/core/src/oned/ODDataBarCommon.cpp +++ b/core/src/oned/ODDataBarCommon.cpp @@ -1,18 +1,7 @@ /* * Copyright 2020 Axel Waggershauser -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "ODDataBarCommon.h" diff --git a/core/src/oned/ODDataBarCommon.h b/core/src/oned/ODDataBarCommon.h index 08669b208e..f1a53a3dcf 100644 --- a/core/src/oned/ODDataBarCommon.h +++ b/core/src/oned/ODDataBarCommon.h @@ -1,19 +1,9 @@ -#pragma once /* * Copyright 2020 Axel Waggershauser -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include "ODRowReader.h" #include "Pattern.h" diff --git a/core/src/oned/ODDataBarExpandedBitDecoder.cpp b/core/src/oned/ODDataBarExpandedBitDecoder.cpp new file mode 100644 index 0000000000..c31e7f681f --- /dev/null +++ b/core/src/oned/ODDataBarExpandedBitDecoder.cpp @@ -0,0 +1,262 @@ +/* +* Copyright 2016 Nu-book Inc. +* Copyright 2016 ZXing authors +* Copyright 2022 Axel Waggershauser +*/ +// SPDX-License-Identifier: Apache-2.0 + +#include "ODDataBarExpandedBitDecoder.h" + +#include "BitArray.h" +#include "Error.h" +#include "GTIN.h" + +#include + +namespace ZXing::OneD::DataBar { + +constexpr char GS = 29; // FNC1 + +static std::string DecodeGeneralPurposeBits(BitArrayView& bits) +{ + enum State { NUMERIC, ALPHA, ISO_IEC_646 }; + State state = NUMERIC; + std::string res; + + auto decode5Bits = [](State& state, std::string& res, BitArrayView& bits) { + int v = bits.readBits(5); + if (v == 4) { + state = state == ALPHA ? ISO_IEC_646 : ALPHA; + } else if (v == 15) { // FNC1 + latch to Numeric + res.push_back(GS); + state = NUMERIC; + // Allow for some generators incorrectly placing a numeric latch "000" after an FNC1 + if (bits.size() >= 7 && bits.peakBits(7) < 8) + bits.skipBits(3); + } else { + res.push_back(v + 43); + } + }; + + auto isPadding = [](State state, BitArrayView& bits) { + bool res = (state == NUMERIC) ? bits.size() < 4 + : bits.size() < 5 && (0b00100 >> (5 - bits.size()) == bits.peakBits(bits.size())); + if (res) + bits.skipBits(bits.size()); + return res; + }; + + while(bits.size() >= 3) { + switch(state) { + case NUMERIC: + if (isPadding(state, bits)) + break; + if (bits.size() < 7) { + int v = bits.readBits(4); + if (v > 0) + res.push_back('0' + v - 1); + } else if (bits.peakBits(4) == 0) { + bits.skipBits(4); + state = ALPHA; + } else { + int v = bits.readBits(7); + for (int digit : {(v - 8) / 11, (v - 8) % 11}) + res.push_back(digit == 10 ? GS : '0' + digit); + } + break; + case ALPHA: + if (isPadding(state, bits)) + break; + if (bits.peakBits(1) == 1) { + constexpr char const* lut58to62 = R"(*,-./)"; + int v = bits.readBits(6); + if (v < 58) + res.push_back(v + 33); + else if (v < 63) + res.push_back(lut58to62[v - 58]); + else + throw FormatError(); + } else if (bits.peakBits(3) == 0) { + bits.skipBits(3); + state = NUMERIC; + } else { + decode5Bits(state, res, bits); + } + break; + case ISO_IEC_646: + if (isPadding(state, bits)) + break; + if (bits.peakBits(3) == 0) { + bits.skipBits(3); + state = NUMERIC; + } else { + int v = bits.peakBits(5); + if (v < 16) { + decode5Bits(state, res, bits); + } else if (v < 29) { + v = bits.readBits(7); + res.push_back(v < 90 ? v + 1 : v + 7); + } else { + constexpr char const* lut232to252 = R"(!"%&'()*+,-./:;<=>?_ )"; + v = bits.readBits(8); + if (v < 232 || 252 < v) + throw FormatError(); + res.push_back(lut232to252[v - 232]); + } + } + break; + } + } + + // in NUMERIC encodation there might be a trailing FNC1 that needs to be ignored + if (res.size() && res.back() == GS) + res.pop_back(); + + return res; +} + +static void AppendNDigits(std::string& s, int v, int n) +{ + int div = std::pow(10, n-1); + while (v / div == 0 && div > 1) { + s.push_back('0'); + div /= 10; + } + s.append(std::to_string(v)); +} + +static std::string DecodeCompressedGTIN(std::string prefix, BitArrayView& bits) +{ + for (int i = 0; i < 4; ++i) + AppendNDigits(prefix, bits.readBits(10), 3); + + prefix.push_back(GTIN::ComputeCheckDigit(prefix.substr(2))); + + return prefix; +} + +static std::string DecodeAI01GTIN(BitArrayView& bits) +{ + return DecodeCompressedGTIN("019", bits); +} + +static std::string DecodeAI01AndOtherAIs(BitArrayView& bits) +{ + bits.skipBits(2); // Variable length symbol bit field + + auto header = DecodeCompressedGTIN("01" + std::to_string(bits.readBits(4)), bits); + auto trailer = DecodeGeneralPurposeBits(bits); + if (trailer.empty()) + return {}; + + return header + trailer; +} + +static std::string DecodeAnyAI(BitArrayView& bits) +{ + bits.skipBits(2); // Variable length symbol bit field + + return DecodeGeneralPurposeBits(bits); +} + +static std::string DecodeAI013103(BitArrayView& bits) +{ + std::string buffer = DecodeAI01GTIN(bits); + buffer.append("3103"); + AppendNDigits(buffer, bits.readBits(15), 6); + + return buffer; +} + +static std::string DecodeAI01320x(BitArrayView& bits) +{ + std::string buffer = DecodeAI01GTIN(bits); + int weight = bits.readBits(15); + buffer.append(weight < 10000 ? "3202" : "3203"); + AppendNDigits(buffer, weight < 10000 ? weight : weight - 10000, 6); + + return buffer; +} + +static std::string DecodeAI0139yx(BitArrayView& bits, char y) +{ + bits.skipBits(2); // Variable length symbol bit field + + std::string buffer = DecodeAI01GTIN(bits); + buffer.append("39"); + buffer.push_back(y); + buffer.append(std::to_string(bits.readBits(2))); + + if (y == '3') + AppendNDigits(buffer, bits.readBits(10), 3); + + auto trailer = DecodeGeneralPurposeBits(bits); + if (trailer.empty()) + return {}; + + return buffer + trailer; +} + +static std::string DecodeAI013x0x1x(BitArrayView& bits, const char* aiPrefix, const char* dateCode) +{ + std::string buffer = DecodeAI01GTIN(bits); + buffer.append(aiPrefix); + + int weight = bits.readBits(20); + buffer.append(std::to_string(weight / 100000)); + AppendNDigits(buffer, weight % 100000, 6); + + int date = bits.readBits(16); + if (date != 38400) { + buffer.append(dateCode); + + int day = date % 32; + date /= 32; + int month = date % 12 + 1; + date /= 12; + int year = date; + + AppendNDigits(buffer, year, 2); + AppendNDigits(buffer, month, 2); + AppendNDigits(buffer, day, 2); + } + + return buffer; +} + +std::string DecodeExpandedBits(const BitArray& _bits) +{ + auto bits = BitArrayView(_bits); + bits.readBits(1); // skip linkage bit + + if (bits.peakBits(1) == 1) + return DecodeAI01AndOtherAIs(bits.skipBits(1)); + + if (bits.peakBits(2) == 0) + return DecodeAnyAI(bits.skipBits(2)); + + switch (bits.peakBits(4)) { + case 4: return DecodeAI013103(bits.skipBits(4)); + case 5: return DecodeAI01320x(bits.skipBits(4)); + } + + switch (bits.peakBits(5)) { + case 12: return DecodeAI0139yx(bits.skipBits(5), '2'); + case 13: return DecodeAI0139yx(bits.skipBits(5), '3'); + } + + switch (bits.readBits(7)) { + case 56: return DecodeAI013x0x1x(bits, "310", "11"); + case 57: return DecodeAI013x0x1x(bits, "320", "11"); + case 58: return DecodeAI013x0x1x(bits, "310", "13"); + case 59: return DecodeAI013x0x1x(bits, "320", "13"); + case 60: return DecodeAI013x0x1x(bits, "310", "15"); + case 61: return DecodeAI013x0x1x(bits, "320", "15"); + case 62: return DecodeAI013x0x1x(bits, "310", "17"); + case 63: return DecodeAI013x0x1x(bits, "320", "17"); + } + + return {}; +} + +} // namespace ZXing::OneD::DataBar diff --git a/core/src/oned/ODDataBarExpandedBitDecoder.h b/core/src/oned/ODDataBarExpandedBitDecoder.h new file mode 100644 index 0000000000..71653a6659 --- /dev/null +++ b/core/src/oned/ODDataBarExpandedBitDecoder.h @@ -0,0 +1,19 @@ +/* +* Copyright 2022 Axel Waggershauser +*/ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#include + +namespace ZXing { + +class BitArray; + +namespace OneD::DataBar { + +std::string DecodeExpandedBits(const BitArray& bits); + +} // namespace OneD::DataBar +} // namespace ZXing diff --git a/core/src/oned/ODDataBarExpandedReader.cpp b/core/src/oned/ODDataBarExpandedReader.cpp index 769b279648..7565e50388 100644 --- a/core/src/oned/ODDataBarExpandedReader.cpp +++ b/core/src/oned/ODDataBarExpandedReader.cpp @@ -2,27 +2,18 @@ * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors * Copyright 2020 Axel Waggershauser -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "ODDataBarExpandedReader.h" #include "BarcodeFormat.h" +#include "DecoderResult.h" +#include "GS1.h" #include "ODDataBarCommon.h" +#include "ODDataBarExpandedBitDecoder.h" #include "Result.h" #include "TextDecoder.h" -#include "rss/ODRSSExpandedBinaryDecoder.h" #include #include @@ -31,9 +22,6 @@ namespace ZXing::OneD { using namespace DataBar; -DataBarExpandedReader::DataBarExpandedReader(const DecodeHints&) {} -DataBarExpandedReader::~DataBarExpandedReader() = default; - static bool IsFinderPattern(int a, int b, int c, int d, int e) { return IsFinder(a, b, c, d, e) && (c > 3 * e); @@ -350,7 +338,7 @@ Result DataBarExpandedReader::decodePattern(int rowNumber, PatternView& view, auto pairs = ReadRowOfPairs(view, rowNumber); if (pairs.empty() || !ChecksumIsValid(pairs)) - return Result(DecodeStatus::NotFound); + return {}; #else if (!state) state.reset(new DBERState); @@ -370,27 +358,26 @@ Result DataBarExpandedReader::decodePattern(int rowNumber, PatternView& view, // L R L R | r | l if (!Insert(allPairs, ReadRowOfPairs(view, rowNumber))) - return Result(DecodeStatus::NotFound); + return {}; auto pairs = FindValidSequence(allPairs); if (pairs.empty()) - return Result(DecodeStatus::NotFound); + return {}; #endif auto txt = DecodeExpandedBits(BuildBitArray(pairs)); + // TODO: remove this to make it return standard conform content -> needs lots of blackbox test fixes + txt = HRIFromGS1(txt); if (txt.empty()) - return Result(DecodeStatus::NotFound); + return {}; RemovePairs(allPairs, pairs); - // Symbology identifier ISO/IEC 24724:2011 Section 9 and GS1 General Specifications 5.1.3 Figure 5.1.3-2 - std::string symbologyIdentifier("]e0"); - // TODO: EstimatePosition misses part of the symbol in the stacked case where the last row contains less pairs than // the first - return {TextDecoder::FromLatin1(txt), EstimatePosition(pairs.front(), pairs.back()), - BarcodeFormat::DataBarExpanded, std::move(symbologyIdentifier), {}, {}, false, - EstimateLineCount(pairs.front(), pairs.back())}; + // Symbology identifier: ISO/IEC 24724:2011 Section 9 and GS1 General Specifications 5.1.3 Figure 5.1.3-2 + return {DecoderResult({}, Content(ByteArray(txt), {'e', '0'})).setLineCount(EstimateLineCount(pairs.front(), pairs.back())), + EstimatePosition(pairs.front(), pairs.back()), BarcodeFormat::DataBarExpanded}; } } // namespace ZXing::OneD diff --git a/core/src/oned/ODDataBarExpandedReader.h b/core/src/oned/ODDataBarExpandedReader.h index a2e9a306d6..65c523636c 100644 --- a/core/src/oned/ODDataBarExpandedReader.h +++ b/core/src/oned/ODDataBarExpandedReader.h @@ -1,40 +1,25 @@ -#pragma once /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors * Copyright 2020 Axel Waggershauser -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once -#include "DecodeHints.h" #include "ODRowReader.h" -namespace ZXing { -namespace OneD { +namespace ZXing::OneD { /** * Decodes DataBarExpandedReader (formerly known as RSS) sybmols, including truncated and stacked variants. See ISO/IEC 24724:2006. */ class DataBarExpandedReader : public RowReader { - public: - explicit DataBarExpandedReader(const DecodeHints& hints); - ~DataBarExpandedReader() override; + using RowReader::RowReader; Result decodePattern(int rowNumber, PatternView& next, std::unique_ptr& state) const override; }; -} // OneD -} // ZXing +} // namespace ZXing::OneD diff --git a/core/src/oned/ODDataBarReader.cpp b/core/src/oned/ODDataBarReader.cpp index f418fd64e8..aa647ffb67 100644 --- a/core/src/oned/ODDataBarReader.cpp +++ b/core/src/oned/ODDataBarReader.cpp @@ -2,23 +2,13 @@ * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors * Copyright 2020 Axel Waggershauser -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "ODDataBarReader.h" #include "BarcodeFormat.h" +#include "DecoderResult.h" #include "GTIN.h" #include "ODDataBarCommon.h" #include "Result.h" @@ -32,9 +22,6 @@ namespace ZXing::OneD { using namespace DataBar; -DataBarReader::DataBarReader(const DecodeHints&) {} -DataBarReader::~DataBarReader() = default; - static bool IsCharacterPair(PatternView v, int modsLeft, int modsRight) { float modSizeRef = ModSizeFinder(v); @@ -167,7 +154,7 @@ Result DataBarReader::decodePattern(int rowNumber, PatternView& next, std::unique_ptr& state) const { #if 0 // non-stacked version - next = next.subView(-1, FULL_PAIR_SIZE); + next = next.subView(-1, FULL_PAIR_SIZE + 1); // +1 reflects the guard pattern on the right, see IsRightPair()); // yes: the first view we test is at index 1 (black bar at 0 would be the guard pattern) while (next.shift(2)) { if (IsLeftPair(next)) { @@ -184,7 +171,7 @@ Result DataBarReader::decodePattern(int rowNumber, PatternView& next, state.reset(new State); auto* prevState = static_cast(state.get()); - next = next.subView(0, FULL_PAIR_SIZE); + next = next.subView(0, FULL_PAIR_SIZE + 1); // +1 reflects the guard pattern on the right, see IsRightPair() // yes: the first view we test is at index 1 (black bar at 0 would be the guard pattern) while (next.shift(1)) { if (IsLeftPair(next)) { @@ -208,12 +195,9 @@ Result DataBarReader::decodePattern(int rowNumber, PatternView& next, for (const auto& rightPair : prevState->rightPairs) if (ChecksumIsValid(leftPair, rightPair)) { // Symbology identifier ISO/IEC 24724:2011 Section 9 and GS1 General Specifications 5.1.3 Figure 5.1.3-2 - std::string symbologyIdentifier("]e0"); - - Result res{TextDecoder::FromLatin1(ConstructText(leftPair, rightPair)), - EstimatePosition(leftPair, rightPair), BarcodeFormat::DataBar, - std::move(symbologyIdentifier), {}, {}, false, - EstimateLineCount(leftPair, rightPair)}; + Result res{DecoderResult({}, Content(ByteArray(ConstructText(leftPair, rightPair)), {'e', '0'})) + .setLineCount(EstimateLineCount(leftPair, rightPair)), + EstimatePosition(leftPair, rightPair), BarcodeFormat::DataBar}; prevState->leftPairs.erase(leftPair); prevState->rightPairs.erase(rightPair); @@ -224,7 +208,7 @@ Result DataBarReader::decodePattern(int rowNumber, PatternView& next, // guaratee progress (see loop in ODReader.cpp) next = {}; - return Result(DecodeStatus::NotFound); + return {}; } } // namespace ZXing::OneD diff --git a/core/src/oned/ODDataBarReader.h b/core/src/oned/ODDataBarReader.h index 2da0109691..0e64bb2f9a 100644 --- a/core/src/oned/ODDataBarReader.h +++ b/core/src/oned/ODDataBarReader.h @@ -1,40 +1,25 @@ -#pragma once /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors * Copyright 2020 Axel Waggershauser -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once -#include "DecodeHints.h" #include "ODRowReader.h" -namespace ZXing { -namespace OneD { +namespace ZXing::OneD { /** * Decodes DataBar (formerly known as RSS) sybmols, including truncated and stacked variants. See ISO/IEC 24724:2006. */ class DataBarReader : public RowReader { - public: - explicit DataBarReader(const DecodeHints& hints); - ~DataBarReader() override; + using RowReader::RowReader; Result decodePattern(int rowNumber, PatternView& next, std::unique_ptr& state) const override; }; -} // OneD -} // ZXing +} // namespace ZXing::OneD diff --git a/core/src/oned/ODEAN13Writer.cpp b/core/src/oned/ODEAN13Writer.cpp index aa36f8e851..cf99be12cc 100644 --- a/core/src/oned/ODEAN13Writer.cpp +++ b/core/src/oned/ODEAN13Writer.cpp @@ -1,24 +1,14 @@ /* * Copyright 2016 Huy Cuong Nguyen * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "ODEAN13Writer.h" #include "ODUPCEANCommon.h" #include "ODWriterHelper.h" +#include "TextUtfEncoding.h" #include #include @@ -64,4 +54,9 @@ EAN13Writer::encode(const std::wstring& contents, int width, int height) const return WriterHelper::RenderResult(result, width, height, _sidesMargin >= 0 ? _sidesMargin : 9); } +BitMatrix EAN13Writer::encode(const std::string& contents, int width, int height) const +{ + return encode(TextUtfEncoding::FromUtf8(contents), width, height); +} + } // namespace ZXing::OneD diff --git a/core/src/oned/ODEAN13Writer.h b/core/src/oned/ODEAN13Writer.h index 8ba0c652f9..c9086941d6 100644 --- a/core/src/oned/ODEAN13Writer.h +++ b/core/src/oned/ODEAN13Writer.h @@ -1,20 +1,10 @@ -#pragma once /* * Copyright 2016 Huy Cuong Nguyen * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include @@ -34,6 +24,7 @@ class EAN13Writer public: EAN13Writer& setMargin(int sidesMargin) { _sidesMargin = sidesMargin; return *this; } BitMatrix encode(const std::wstring& contents, int width, int height) const; + BitMatrix encode(const std::string& contents, int width, int height) const; private: int _sidesMargin = -1; diff --git a/core/src/oned/ODEAN8Writer.cpp b/core/src/oned/ODEAN8Writer.cpp index 1533e94d4d..652c26f719 100644 --- a/core/src/oned/ODEAN8Writer.cpp +++ b/core/src/oned/ODEAN8Writer.cpp @@ -1,24 +1,14 @@ /* * Copyright 2016 Huy Cuong Nguyen * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "ODEAN8Writer.h" #include "ODUPCEANCommon.h" #include "ODWriterHelper.h" +#include "TextUtfEncoding.h" #include @@ -53,4 +43,9 @@ EAN8Writer::encode(const std::wstring& contents, int width, int height) const return WriterHelper::RenderResult(result, width, height, _sidesMargin >= 0 ? _sidesMargin : 9); } +BitMatrix EAN8Writer::encode(const std::string& contents, int width, int height) const +{ + return encode(TextUtfEncoding::FromUtf8(contents), width, height); +} + } // namespace ZXing::OneD diff --git a/core/src/oned/ODEAN8Writer.h b/core/src/oned/ODEAN8Writer.h index c1c1044173..8c42ea969c 100644 --- a/core/src/oned/ODEAN8Writer.h +++ b/core/src/oned/ODEAN8Writer.h @@ -1,20 +1,10 @@ -#pragma once /* * Copyright 2016 Huy Cuong Nguyen * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include @@ -34,6 +24,7 @@ class EAN8Writer public: EAN8Writer& setMargin(int sidesMargin) { _sidesMargin = sidesMargin; return *this; } BitMatrix encode(const std::wstring& contents, int width, int height) const; + BitMatrix encode(const std::string& contents, int width, int height) const; private: int _sidesMargin = -1; diff --git a/core/src/oned/ODITFReader.cpp b/core/src/oned/ODITFReader.cpp index e314b99368..f2e8078196 100644 --- a/core/src/oned/ODITFReader.cpp +++ b/core/src/oned/ODITFReader.cpp @@ -1,42 +1,20 @@ /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "ODITFReader.h" #include "DecodeHints.h" #include "GTIN.h" #include "Result.h" -#include "ZXContainerAlgorithms.h" +#include "ZXAlgorithms.h" #include namespace ZXing::OneD { -/** Valid ITF lengths. Anything longer than the largest value is also allowed. */ -constexpr auto DEFAULT_ALLOWED_LENGTHS = { 6, 8, 10, 12, 14 }; - -ITFReader::ITFReader(const DecodeHints& hints) : - _allowedLengths(hints.allowedLengths()), - _validateCheckSum(hints.validateITFCheckSum()) -{ - if (_allowedLengths.empty()) - _allowedLengths.assign(DEFAULT_ALLOWED_LENGTHS.begin(), DEFAULT_ALLOWED_LENGTHS.end()); -} - constexpr auto START_PATTERN_ = FixedPattern<4, 4>{1, 1, 1, 1}; constexpr auto STOP_PATTERN_1 = FixedPattern<3, 4>{2, 1, 1}; constexpr auto STOP_PATTERN_2 = FixedPattern<3, 5>{3, 1, 1}; @@ -48,7 +26,7 @@ Result ITFReader::decodePattern(int rowNumber, PatternView& next, std::unique_pt next = FindLeftGuard(next, 4 + minCharCount/2 + 3, START_PATTERN_, minQuietZone); if (!next.isValid()) - return Result(DecodeStatus::NotFound); + return {}; std::string txt; txt.reserve(20); @@ -82,23 +60,24 @@ Result ITFReader::decodePattern(int rowNumber, PatternView& next, std::unique_pt next = next.subView(0, 3); if (Size(txt) < minCharCount || !next.isValid()) - return Result(DecodeStatus::NotFound); + return {}; if (!IsRightGuard(next, STOP_PATTERN_1, minQuietZone) && !IsRightGuard(next, STOP_PATTERN_2, minQuietZone)) - return Result(DecodeStatus::NotFound); + return {}; - if (_validateCheckSum && !GTIN::IsCheckDigitValid(txt)) - return Result(DecodeStatus::ChecksumError); + Error error; + if (_hints.validateITFCheckSum() && !GTIN::IsCheckDigitValid(txt)) + error = ChecksumError(); // Symbology identifier ISO/IEC 16390:2007 Annex C Table C.1 // See also GS1 General Specifications 5.1.3 Figure 5.1.3-2 - std::string symbologyIdentifier("]I0"); // No check character validation + SymbologyIdentifier symbologyIdentifier = {'I', '0'}; // No check character validation - if (_validateCheckSum || (txt.size() == 14 && GTIN::IsCheckDigitValid(txt))) // If no hint test if valid ITF-14 - symbologyIdentifier = "]I1"; // Modulo 10 symbol check character validated and transmitted + if (_hints.validateITFCheckSum() || (txt.size() == 14 && GTIN::IsCheckDigitValid(txt))) // If no hint test if valid ITF-14 + symbologyIdentifier.modifier = '1'; // Modulo 10 symbol check character validated and transmitted int xStop = next.pixelsTillEnd(); - return Result(txt, rowNumber, xStart, xStop, BarcodeFormat::ITF, std::move(symbologyIdentifier)); + return Result(txt, rowNumber, xStart, xStop, BarcodeFormat::ITF, symbologyIdentifier, error); } } // namespace ZXing::OneD diff --git a/core/src/oned/ODITFReader.h b/core/src/oned/ODITFReader.h index 322ee17d20..e71d0ea25e 100644 --- a/core/src/oned/ODITFReader.h +++ b/core/src/oned/ODITFReader.h @@ -1,56 +1,33 @@ -#pragma once /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 -#include "ODRowReader.h" - -#include - -namespace ZXing { +#pragma once -class DecodeHints; +#include "ODRowReader.h" -namespace OneD { +namespace ZXing::OneD { /** *

Implements decoding of the ITF format, or Interleaved Two of Five.

* *

This Reader will scan ITF barcodes of certain lengths only. -* At the moment it reads length 6, 8, 10, 12, 14, 16, 18, 20, 24, and 44 as these have appeared "in the wild". Not all -* lengths are scanned, especially shorter ones, to avoid false positives. This in turn is due to a lack of -* required checksum function.

+* At the moment it reads length >= 6. Not all lengths are scanned, especially shorter ones, to avoid false positives. +* This in turn is due to a lack of required checksum function.

* -*

The checksum is optional and is only applied by this Reader if the assumeITFCheckDigit hint is given.

+*

The checksum is optional and is only checked if the validateITFCheckSum hint is given.

* *

http://en.wikipedia.org/wiki/Interleaved_2_of_5 * is a great reference for Interleaved 2 of 5 information.

-* -* @author kevin.osullivan@sita.aero, SITA Lab. */ class ITFReader : public RowReader { public: - explicit ITFReader(const DecodeHints& hints); - Result decodePattern(int rowNumber, PatternView& next, std::unique_ptr&) const override; + using RowReader::RowReader; -private: - std::vector _allowedLengths; - bool _validateCheckSum; + Result decodePattern(int rowNumber, PatternView& next, std::unique_ptr&) const override; }; -} // OneD -} // ZXing +} // namespace ZXing::OneD diff --git a/core/src/oned/ODITFWriter.cpp b/core/src/oned/ODITFWriter.cpp index 34f49a12d6..1f3e6f611d 100644 --- a/core/src/oned/ODITFWriter.cpp +++ b/core/src/oned/ODITFWriter.cpp @@ -1,23 +1,13 @@ /* * Copyright 2016 Huy Cuong Nguyen * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "ODITFWriter.h" #include "ODWriterHelper.h" +#include "TextUtfEncoding.h" #include #include @@ -80,4 +70,9 @@ ITFWriter::encode(const std::wstring& contents, int width, int height) const return WriterHelper::RenderResult(result, width, height, _sidesMargin >= 0 ? _sidesMargin : 10); } +BitMatrix ITFWriter::encode(const std::string& contents, int width, int height) const +{ + return encode(TextUtfEncoding::FromUtf8(contents), width, height); +} + } // namespace ZXing::OneD diff --git a/core/src/oned/ODITFWriter.h b/core/src/oned/ODITFWriter.h index fcf699d4e2..f4cab9bb39 100644 --- a/core/src/oned/ODITFWriter.h +++ b/core/src/oned/ODITFWriter.h @@ -1,20 +1,10 @@ -#pragma once /* * Copyright 2016 Huy Cuong Nguyen * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include @@ -34,6 +24,7 @@ class ITFWriter public: ITFWriter& setMargin(int sidesMargin) { _sidesMargin = sidesMargin; return *this; } BitMatrix encode(const std::wstring& contents, int width, int height) const; + BitMatrix encode(const std::string& contents, int width, int height) const; private: int _sidesMargin = -1; diff --git a/core/src/oned/ODMultiUPCEANReader.cpp b/core/src/oned/ODMultiUPCEANReader.cpp index e567a07a84..bba83cdc23 100644 --- a/core/src/oned/ODMultiUPCEANReader.cpp +++ b/core/src/oned/ODMultiUPCEANReader.cpp @@ -2,19 +2,8 @@ * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors * Copyright 2020 Axel Waggershauser -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "ODMultiUPCEANReader.h" @@ -27,26 +16,15 @@ namespace ZXing::OneD { -MultiUPCEANReader::MultiUPCEANReader(const DecodeHints& hints) : _hints(hints) -{ - _canReturnUPCA = _hints.formats().empty() || _hints.hasFormat(BarcodeFormat::UPCA); - if (_hints.formats().empty()) - _hints.setFormats(BarcodeFormat::Any); -} - -MultiUPCEANReader::~MultiUPCEANReader() = default; - constexpr int CHAR_LEN = 4; -constexpr auto END_PATTERN = FixedPattern<3, 3>{1, 1, 1}; -constexpr auto MID_PATTERN = FixedPattern<5, 5>{1, 1, 1, 1, 1}; -constexpr auto UPCE_END_PATTERN = FixedPattern<6, 6>{1, 1, 1, 1, 1, 1}; -constexpr auto EXT_START_PATTERN = FixedPattern<3, 4>{1, 1, 2}; +constexpr auto END_PATTERN = FixedPattern<3, 3>{1, 1, 1}; +constexpr auto MID_PATTERN = FixedPattern<5, 5>{1, 1, 1, 1, 1}; +constexpr auto UPCE_END_PATTERN = FixedPattern<6, 6>{1, 1, 1, 1, 1, 1}; +constexpr auto EXT_START_PATTERN = FixedPattern<3, 4>{1, 1, 2}; constexpr auto EXT_SEPARATOR_PATTERN = FixedPattern<2, 2>{1, 1}; -static const int FIRST_DIGIT_ENCODINGS[] = { - 0x00, 0x0B, 0x0D, 0x0E, 0x13, 0x19, 0x1C, 0x15, 0x16, 0x1A -}; +static const int FIRST_DIGIT_ENCODINGS[] = {0x00, 0x0B, 0x0D, 0x0E, 0x13, 0x19, 0x1C, 0x15, 0x16, 0x1A}; // The GS1 specification has the following to say about quiet zones // Type: EAN-13 | EAN-8 | UPC-A | UPC-E | EAN Add-on | UPC Add-on @@ -69,10 +47,9 @@ static bool DecodeDigit(const PatternView& view, std::string& txt, int* lgPatter static constexpr float MAX_AVG_VARIANCE = 0.48f; static constexpr float MAX_INDIVIDUAL_VARIANCE = 0.7f; - int bestMatch = lgPattern ? RowReader::DecodeDigit(view, UPCEANCommon::L_AND_G_PATTERNS, MAX_AVG_VARIANCE, - MAX_INDIVIDUAL_VARIANCE, false) - : RowReader::DecodeDigit(view, UPCEANCommon::L_PATTERNS, MAX_AVG_VARIANCE, - MAX_INDIVIDUAL_VARIANCE, false); + int bestMatch = + lgPattern ? RowReader::DecodeDigit(view, UPCEANCommon::L_AND_G_PATTERNS, MAX_AVG_VARIANCE, MAX_INDIVIDUAL_VARIANCE, false) + : RowReader::DecodeDigit(view, UPCEANCommon::L_PATTERNS, MAX_AVG_VARIANCE, MAX_INDIVIDUAL_VARIANCE, false); txt += '0' + (bestMatch % 10); if (lgPattern) AppendBit(*lgPattern, bestMatch >= 10); @@ -284,7 +261,7 @@ Result MultiUPCEANReader::decodePattern(int rowNumber, PatternView& next, std::u next = FindLeftGuard(next, minSize, END_PATTERN, QUIET_ZONE_LEFT); if (!next.isValid()) - return Result(DecodeStatus::NotFound); + return {}; PartialResult res; auto begin = next; @@ -292,15 +269,16 @@ Result MultiUPCEANReader::decodePattern(int rowNumber, PatternView& next, std::u if (!(((_hints.hasFormat(BarcodeFormat::EAN13 | BarcodeFormat::UPCA)) && EAN13(res, begin)) || (_hints.hasFormat(BarcodeFormat::EAN8) && EAN8(res, begin)) || (_hints.hasFormat(BarcodeFormat::UPCE) && UPCE(res, begin)))) - return Result(DecodeStatus::NotFound); + return {}; + Error error; if (!GTIN::IsCheckDigitValid(res.format == BarcodeFormat::UPCE ? UPCEANCommon::ConvertUPCEtoUPCA(res.txt) : res.txt)) - return Result(DecodeStatus::ChecksumError); + error = ChecksumError(); // If UPC-A was a requested format and we detected a EAN-13 code with a leading '0', then we drop the '0' and call it // a UPC-A code. // TODO: this is questionable - if (_canReturnUPCA && res.format == BarcodeFormat::EAN13 && res.txt.front() == '0') { + if (_hints.hasFormat(BarcodeFormat::UPCA) && res.format == BarcodeFormat::EAN13 && res.txt.front() == '0') { res.txt = res.txt.substr(1); res.format = BarcodeFormat::UPCA; } @@ -308,29 +286,27 @@ Result MultiUPCEANReader::decodePattern(int rowNumber, PatternView& next, std::u // Symbology identifier modifiers ISO/IEC 15420:2009 Annex B Table B.1 // ISO/IEC 15420:2009 (& GS1 General Specifications 5.1.3) states that the content for "]E0" should be 13 digits, // i.e. converted to EAN-13 if UPC-A/E, but not doing this here to maintain backward compatibility - std::string symbologyIdentifier(res.format == BarcodeFormat::EAN8 ? "]E4" : "]E0"); + SymbologyIdentifier symbologyIdentifier = {'E', res.format == BarcodeFormat::EAN8 ? '4' : '0'}; auto ext = res.end; PartialResult addOnRes; - if (_hints.eanAddOnSymbol() != EanAddOnSymbol::Ignore && ext.skipSymbol() && - ext.skipSingle(static_cast(begin.sum() * 3.5)) && (AddOn(addOnRes, ext, 5) || AddOn(addOnRes, ext, 2))) { - + if (_hints.eanAddOnSymbol() != EanAddOnSymbol::Ignore && ext.skipSymbol() && ext.skipSingle(static_cast(begin.sum() * 3.5)) + && (AddOn(addOnRes, ext, 5) || AddOn(addOnRes, ext, 2))) { // ISO/IEC 15420:2009 states that the content for "]E3" should be 15 or 18 digits, i.e. converted to EAN-13 // and extended with no separator, and that the content for "]E4" should be 8 digits, i.e. no add-on //TODO: extend position in include extension res.txt += " " + addOnRes.txt; if (res.format != BarcodeFormat::EAN8) // Keeping EAN-8 with add-on as "]E4" - symbologyIdentifier = "]E3"; // Combined packet, EAN-13, UPC-A, UPC-E, with add-on + symbologyIdentifier.modifier = '3'; // Combined packet, EAN-13, UPC-A, UPC-E, with add-on } next = res.end; if (_hints.eanAddOnSymbol() == EanAddOnSymbol::Require && !addOnRes.isValid()) - return Result(DecodeStatus::NotFound); + return {}; - return { - res.txt, rowNumber, begin.pixelsInFront(), res.end.pixelsTillEnd(), res.format, std::move(symbologyIdentifier)}; + return Result(res.txt, rowNumber, begin.pixelsInFront(), res.end.pixelsTillEnd(), res.format, symbologyIdentifier, error); } } // namespace ZXing::OneD diff --git a/core/src/oned/ODMultiUPCEANReader.h b/core/src/oned/ODMultiUPCEANReader.h index 9d3154331e..9ec795d51c 100644 --- a/core/src/oned/ODMultiUPCEANReader.h +++ b/core/src/oned/ODMultiUPCEANReader.h @@ -1,47 +1,24 @@ -#pragma once /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once -#include "BarcodeFormat.h" -#include "DecodeHints.h" #include "ODRowReader.h" -namespace ZXing { -namespace OneD { +namespace ZXing::OneD { /** -*

A reader that can read all available UPC/EAN formats. If a caller wants to try to -* read all such formats, it is most efficient to use this implementation rather than invoke -* individual readers.

-* -* @author Sean Owen +* @brief A reader that can read all available UPC/EAN formats. */ class MultiUPCEANReader : public RowReader { public: - explicit MultiUPCEANReader(const DecodeHints& hints); - ~MultiUPCEANReader() override; + using RowReader::RowReader; Result decodePattern(int rowNumber, PatternView& next, std::unique_ptr&) const override; - -private: - bool _canReturnUPCA = false; - DecodeHints _hints; }; -} // OneD -} // ZXing +} // namespace ZXing::OneD diff --git a/core/src/oned/ODReader.cpp b/core/src/oned/ODReader.cpp index eb4d4fbcdb..a616029413 100644 --- a/core/src/oned/ODReader.cpp +++ b/core/src/oned/ODReader.cpp @@ -2,19 +2,8 @@ * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors * Copyright 2020 Axel Waggershauser -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "ODReader.h" @@ -35,11 +24,7 @@ namespace ZXing::OneD { -Reader::Reader(const DecodeHints& hints) : - _tryHarder(hints.tryHarder()), - _tryRotate(hints.tryRotate()), - _isPure(hints.isPure()), - _minLineCount(hints.minLineCount()) +Reader::Reader(const DecodeHints& hints) : ZXing::Reader(hints) { _readers.reserve(8); @@ -51,9 +36,9 @@ Reader::Reader(const DecodeHints& hints) : if (formats.testFlag(BarcodeFormat::Code39)) _readers.emplace_back(new Code39Reader(hints)); if (formats.testFlag(BarcodeFormat::Code93)) - _readers.emplace_back(new Code93Reader()); + _readers.emplace_back(new Code93Reader(hints)); if (formats.testFlag(BarcodeFormat::Code128)) - _readers.emplace_back(new Code128Reader()); + _readers.emplace_back(new Code128Reader(hints)); if (formats.testFlag(BarcodeFormat::ITF)) _readers.emplace_back(new ITFReader(hints)); if (formats.testFlag(BarcodeFormat::Codabar)) @@ -76,7 +61,7 @@ Reader::~Reader() = default; * image if "trying harder". */ static Results DoDecode(const std::vector>& readers, const BinaryBitmap& image, - bool tryHarder, bool rotate, bool isPure, int maxSymbols, int minLineCount) + bool tryHarder, bool rotate, bool isPure, int maxSymbols, int minLineCount, bool returnErrors) { Results res; @@ -108,6 +93,7 @@ static Results DoDecode(const std::vector>& readers, int rowStepsAboveOrBelow = (i + 1) / 2; bool isAbove = (i & 0x01) == 0; // i.e. is x even? int rowNumber = middle + rowStep * (isAbove ? rowStepsAboveOrBelow : -rowStepsAboveOrBelow); + bool isCheckRow = false; if (rowNumber < 0 || rowNumber >= height) { // Oops, if we run off the top or bottom, stop break; @@ -118,6 +104,7 @@ static Results DoDecode(const std::vector>& readers, --i; rowNumber = checkRows.back(); checkRows.pop_back(); + isCheckRow = true; if (rowNumber < 0 || rowNumber >= height) continue; } @@ -147,7 +134,7 @@ static Results DoDecode(const std::vector>& readers, PatternView next(bars); do { Result result = readers[r]->decodePattern(rowNumber, next, decodingState[r]); - if (result.isValid()) { + if (result.isValid() || (returnErrors && result.error())) { result.incrementLineCount(); if (upsideDown) { // update position (flip horizontally). @@ -167,7 +154,7 @@ static Results DoDecode(const std::vector>& readers, // check if we know this code already for (auto& other : res) { - if (other == result) { + if (result == other) { // merge the position information auto dTop = maxAbsComponent(other.position().topLeft() - result.position().topLeft()); auto dBot = maxAbsComponent(other.position().bottomLeft() - result.position().topLeft()); @@ -183,12 +170,12 @@ static Results DoDecode(const std::vector>& readers, other.setPosition(points); other.incrementLineCount(); // clear the result, so we don't insert it again below - result = Result(DecodeStatus::NotFound); + result = Result(); break; } } - if (result.isValid()) + if (result.format() != BarcodeFormat::None) res.push_back(std::move(result)); if (maxSymbols && Reduce(res, 0, [&](int s, const Result& r) { @@ -199,7 +186,7 @@ static Results DoDecode(const std::vector>& readers, // if we found a valid code but have a minLineCount > 1, add additional check rows above and // below the current one - if (checkRows.empty() && minLineCount > 1 && rowStep > 1) { + if (!isCheckRow && minLineCount > 1 && rowStep > 1) { checkRows = {rowNumber - 1, rowNumber + 1}; if (rowStep > 2) checkRows.insert(checkRows.end(), {rowNumber - 2, rowNumber + 2}); @@ -222,10 +209,10 @@ static Results DoDecode(const std::vector>& readers, for (auto a = res.begin(); a != res.end(); ++a) for (auto b = std::next(a); b != res.end(); ++b) if (HaveIntersectingBoundingBoxes(a->position(), b->position())) - *(a->lineCount() < b->lineCount() ? a : b) = Result(DecodeStatus::NotFound); + *(a->lineCount() < b->lineCount() ? a : b) = Result(); //TODO: C++20 res.erase_if() - it = std::remove_if(res.begin(), res.end(), [](auto&& r) { return r.status() == DecodeStatus::NotFound; }); + it = std::remove_if(res.begin(), res.end(), [](auto&& r) { return r.format() == BarcodeFormat::None; }); res.erase(it, res.end()); return res; @@ -234,19 +221,22 @@ static Results DoDecode(const std::vector>& readers, Result Reader::decode(const BinaryBitmap& image) const { - auto result = DoDecode(_readers, image, _tryHarder, false, _isPure, 1, _minLineCount); + auto result = + DoDecode(_readers, image, _hints.tryHarder(), false, _hints.isPure(), 1, _hints.minLineCount(), _hints.returnErrors()); - if (result.empty() && _tryRotate) - result = DoDecode(_readers, image, _tryHarder, true, _isPure, 1, _minLineCount); + if (result.empty() && _hints.tryRotate()) + result = DoDecode(_readers, image, _hints.tryHarder(), true, _hints.isPure(), 1, _hints.minLineCount(), _hints.returnErrors()); - return result.empty() ? Result(DecodeStatus::NotFound) : result.front(); + return FirstOrDefault(std::move(result)); } Results Reader::decode(const BinaryBitmap& image, int maxSymbols) const { - auto resH = DoDecode(_readers, image, _tryHarder, false, _isPure, maxSymbols, _minLineCount); - if ((!maxSymbols || Size(resH) < maxSymbols) && _tryRotate) { - auto resV = DoDecode(_readers, image, _tryHarder, true, _isPure, maxSymbols - Size(resH), _minLineCount); + auto resH = DoDecode(_readers, image, _hints.tryHarder(), false, _hints.isPure(), maxSymbols, _hints.minLineCount(), + _hints.returnErrors()); + if ((!maxSymbols || Size(resH) < maxSymbols) && _hints.tryRotate()) { + auto resV = DoDecode(_readers, image, _hints.tryHarder(), true, _hints.isPure(), maxSymbols - Size(resH), + _hints.minLineCount(), _hints.returnErrors()); resH.insert(resH.end(), resV.begin(), resV.end()); } return resH; diff --git a/core/src/oned/ODReader.h b/core/src/oned/ODReader.h index e07d8d4e57..5ccf2b43a0 100644 --- a/core/src/oned/ODReader.h +++ b/core/src/oned/ODReader.h @@ -1,20 +1,10 @@ -#pragma once /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include "Reader.h" @@ -29,10 +19,6 @@ namespace OneD { class RowReader; -/** -* @author dswitkin@google.com (Daniel Switkin) -* @author Sean Owen -*/ class Reader : public ZXing::Reader { public: @@ -44,10 +30,6 @@ class Reader : public ZXing::Reader private: std::vector> _readers; - bool _tryHarder; - bool _tryRotate; - bool _isPure; - int _minLineCount; }; } // OneD diff --git a/core/src/oned/ODRowReader.cpp b/core/src/oned/ODRowReader.cpp index de0febc20e..339ec0d56d 100644 --- a/core/src/oned/ODRowReader.cpp +++ b/core/src/oned/ODRowReader.cpp @@ -1,18 +1,7 @@ /* * Copyright 2020 Axel Waggershauser -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "ODRowReader.h" @@ -32,10 +21,10 @@ Result RowReader::decodeSingleRow(int rowNumber, const BitArray& row) const if (*i) res.push_back(0); while ((i = row.getNextSetTo(i, !*i)) != row.end()) { - res.push_back(static_cast(i - li)); + res.push_back(narrow_cast(i - li)); li = i; } - res.push_back(static_cast(i - li)); + res.push_back(narrow_cast(i - li)); if (*(i-1)) res.push_back(0); diff --git a/core/src/oned/ODRowReader.h b/core/src/oned/ODRowReader.h index ec6bc2882e..98e61a22d7 100644 --- a/core/src/oned/ODRowReader.h +++ b/core/src/oned/ODRowReader.h @@ -1,24 +1,13 @@ -#pragma once /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors * Copyright 2020 Axel Waggershauser -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include "BitArray.h" -#include "DecodeStatus.h" #include "Pattern.h" #include @@ -48,6 +37,7 @@ RSSExp.: v?-74d/?-41c namespace ZXing { +class DecodeHints; class Result; namespace OneD { @@ -58,7 +48,12 @@ namespace OneD { */ class RowReader { +protected: + const DecodeHints& _hints; + public: + explicit RowReader(const DecodeHints& hints) : _hints(hints) {} + explicit RowReader(DecodeHints&& hints) = delete; struct DecodingState { diff --git a/core/src/oned/ODUPCAWriter.cpp b/core/src/oned/ODUPCAWriter.cpp index c5eedd925c..16574022fb 100644 --- a/core/src/oned/ODUPCAWriter.cpp +++ b/core/src/oned/ODUPCAWriter.cpp @@ -1,24 +1,14 @@ /* * Copyright 2016 Huy Cuong Nguyen * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "ODUPCAWriter.h" #include "BitMatrix.h" #include "ODEAN13Writer.h" +#include "TextUtfEncoding.h" #include @@ -35,4 +25,9 @@ UPCAWriter::encode(const std::wstring& contents, int width, int height) const return EAN13Writer().setMargin(_sidesMargin).encode(L'0' + contents, width, height); } +BitMatrix UPCAWriter::encode(const std::string& contents, int width, int height) const +{ + return encode(TextUtfEncoding::FromUtf8(contents), width, height); +} + } // namespace ZXing::OneD diff --git a/core/src/oned/ODUPCAWriter.h b/core/src/oned/ODUPCAWriter.h index 8d6bfb799c..22dacdac20 100644 --- a/core/src/oned/ODUPCAWriter.h +++ b/core/src/oned/ODUPCAWriter.h @@ -1,20 +1,10 @@ -#pragma once /* * Copyright 2016 Huy Cuong Nguyen * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include @@ -34,6 +24,7 @@ class UPCAWriter public: UPCAWriter& setMargin(int sidesMargin) { _sidesMargin = sidesMargin; return *this; } BitMatrix encode(const std::wstring& contents, int width, int height) const; + BitMatrix encode(const std::string& contents, int width, int height) const; private: int _sidesMargin = -1; diff --git a/core/src/oned/ODUPCEANCommon.cpp b/core/src/oned/ODUPCEANCommon.cpp index 997249baf1..7a9b4a8daa 100644 --- a/core/src/oned/ODUPCEANCommon.cpp +++ b/core/src/oned/ODUPCEANCommon.cpp @@ -1,19 +1,8 @@ /* * Copyright 2016 Huy Cuong Nguyen * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "ODUPCEANCommon.h" diff --git a/core/src/oned/ODUPCEANCommon.h b/core/src/oned/ODUPCEANCommon.h index f2b8113f31..3c0eb59ac3 100644 --- a/core/src/oned/ODUPCEANCommon.h +++ b/core/src/oned/ODUPCEANCommon.h @@ -1,20 +1,10 @@ -#pragma once /* * Copyright 2016 Huy Cuong Nguyen * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include "GTIN.h" diff --git a/core/src/oned/ODUPCEWriter.cpp b/core/src/oned/ODUPCEWriter.cpp index b76b990080..ea23e32290 100644 --- a/core/src/oned/ODUPCEWriter.cpp +++ b/core/src/oned/ODUPCEWriter.cpp @@ -1,24 +1,14 @@ /* * Copyright 2016 Huy Cuong Nguyen * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "ODUPCEWriter.h" #include "ODUPCEANCommon.h" #include "ODWriterHelper.h" +#include "TextUtfEncoding.h" #include #include @@ -58,4 +48,9 @@ UPCEWriter::encode(const std::wstring& contents, int width, int height) const return WriterHelper::RenderResult(result, width, height, _sidesMargin >= 0 ? _sidesMargin : 9); } +BitMatrix UPCEWriter::encode(const std::string& contents, int width, int height) const +{ + return encode(TextUtfEncoding::FromUtf8(contents), width, height); +} + } // namespace ZXing::OneD diff --git a/core/src/oned/ODUPCEWriter.h b/core/src/oned/ODUPCEWriter.h index b7f6177bfd..90fd7b0b8c 100644 --- a/core/src/oned/ODUPCEWriter.h +++ b/core/src/oned/ODUPCEWriter.h @@ -1,20 +1,10 @@ -#pragma once /* * Copyright 2016 Huy Cuong Nguyen * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include @@ -34,6 +24,7 @@ class UPCEWriter public: UPCEWriter& setMargin(int sidesMargin) { _sidesMargin = sidesMargin; return *this; } BitMatrix encode(const std::wstring& contents, int width, int height) const; + BitMatrix encode(const std::string& contents, int width, int height) const; private: int _sidesMargin = -1; diff --git a/core/src/oned/ODWriterHelper.cpp b/core/src/oned/ODWriterHelper.cpp index dc99babea5..e0f0a33bf8 100644 --- a/core/src/oned/ODWriterHelper.cpp +++ b/core/src/oned/ODWriterHelper.cpp @@ -1,19 +1,8 @@ /* * Copyright 2016 Huy Cuong Nguyen * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "ODWriterHelper.h" diff --git a/core/src/oned/ODWriterHelper.h b/core/src/oned/ODWriterHelper.h index 63a2cbb060..f50f644df1 100644 --- a/core/src/oned/ODWriterHelper.h +++ b/core/src/oned/ODWriterHelper.h @@ -1,20 +1,10 @@ -#pragma once /* * Copyright 2016 Huy Cuong Nguyen * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include "BitMatrix.h" diff --git a/core/src/oned/rss/ODRSSExpandedBinaryDecoder.cpp b/core/src/oned/rss/ODRSSExpandedBinaryDecoder.cpp deleted file mode 100644 index f2785d6be0..0000000000 --- a/core/src/oned/rss/ODRSSExpandedBinaryDecoder.cpp +++ /dev/null @@ -1,341 +0,0 @@ -/* -* Copyright 2016 Nu-book Inc. -* Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -/* -* These authors would like to acknowledge the Spanish Ministry of Industry, -* Tourism and Trade, for the support in the project TSI020301-2008-2 -* "PIRAmIDE: Personalizable Interactions with Resources on AmI-enabled -* Mobile Dynamic Environments", led by Treelogic -* ( http://www.treelogic.com/ ): -* -* http://www.piramidepse.com/ -*/ - -#include "ODRSSExpandedBinaryDecoder.h" - -#include "BitArray.h" -#include "DecodeStatus.h" -#include "ODRSSGenericAppIdDecoder.h" - -#include - -namespace ZXing::OneD::DataBar { - -static const int AI01_GTIN_SIZE = 40; - -static void -AI01AppendCheckDigit(std::string& buffer, int currentPos) -{ - int checkDigit = 0; - for (int i = 0; i < 13; i++) { - int digit = buffer[i + currentPos] - '0'; - checkDigit += (i & 0x01) == 0 ? 3 * digit : digit; - } - - checkDigit = 10 - (checkDigit % 10); - if (checkDigit == 10) { - checkDigit = 0; - } - buffer.append(std::to_string(checkDigit)); -} - -static void -AI01EncodeCompressedGtinWithoutAI(std::string& buffer, const BitArray& bits, int currentPos, int initialBufferPosition) -{ - for (int i = 0; i < 4; ++i) { - int currentBlock = ToInt(bits, currentPos + 10 * i, 10); - if (currentBlock / 100 == 0) { - buffer.push_back('0'); - } - if (currentBlock / 10 == 0) { - buffer.push_back('0'); - } - buffer.append(std::to_string(currentBlock)); - } - AI01AppendCheckDigit(buffer, initialBufferPosition); -} - -static void -AI01EncodeCompressedGtin(std::string& buffer, const BitArray& bits, int currentPos) -{ - buffer.append("(01)"); - int initialPosition = Size(buffer); - buffer.push_back('9'); - AI01EncodeCompressedGtinWithoutAI(buffer, bits, currentPos, initialPosition); -} - -using AddWeightCodeFunc = const std::function; -using CheckWeightFunc = const std::function; - -static void AI01EncodeCompressedWeight(std::string& buffer, const BitArray& bits, int currentPos, int weightSize, - const AddWeightCodeFunc& addWeightCode, const CheckWeightFunc& checkWeight) -{ - int originalWeightNumeric = ToInt(bits, currentPos, weightSize); - addWeightCode(buffer, originalWeightNumeric); - - int weightNumeric = checkWeight(originalWeightNumeric); - - int currentDivisor = 100000; - for (int i = 0; i < 5; ++i) { - if (weightNumeric / currentDivisor == 0) { - buffer.push_back('0'); - } - currentDivisor /= 10; - } - buffer.append(std::to_string(weightNumeric)); -} - -/** -* @author Pablo Orduña, University of Deusto (pablo.orduna@deusto.es) -* @author Eduardo Castillejo, University of Deusto (eduardo.castillejo@deusto.es) -*/ -static std::string -DecodeAI01AndOtherAIs(const BitArray& bits) -{ - static const int HEADER_SIZE = 1 + 1 + 2; // first bit encodes the linkage flag, the second one is the encodation - // method, and the other two are for the variable length - - if (bits.size() < HEADER_SIZE + 44) - return {}; - - std::string buffer; - buffer.append("(01)"); - int initialGtinPosition = Size(buffer); - int firstGtinDigit = ToInt(bits, HEADER_SIZE, 4); - buffer.append(std::to_string(firstGtinDigit)); - - AI01EncodeCompressedGtinWithoutAI(buffer, bits, HEADER_SIZE + 4, initialGtinPosition); - if (StatusIsOK(DecodeAppIdAllCodes(bits, HEADER_SIZE + 44, -1, buffer))) { - return buffer; - } - return {}; -} - -static std::string -DecodeAnyAI(const BitArray& bits) -{ - static const int HEADER_SIZE = 2 + 1 + 2; - std::string buffer; - if (StatusIsOK(DecodeAppIdAllCodes(bits, HEADER_SIZE, -1, buffer))) { - return buffer; - } - return std::string(); -} - -static std::string -DecodeAI013103(const BitArray& bits) -{ - static const int HEADER_SIZE = 4 + 1; - static const int WEIGHT_SIZE = 15; - - if (bits.size() != HEADER_SIZE + AI01_GTIN_SIZE + WEIGHT_SIZE) { - return std::string(); - } - - std::string buffer; - AI01EncodeCompressedGtin(buffer, bits, HEADER_SIZE); - AI01EncodeCompressedWeight(buffer, bits, HEADER_SIZE + AI01_GTIN_SIZE, WEIGHT_SIZE, - // addWeightCode - [](std::string& buf, int) { buf.append("(3103)"); }, - // checkWeight - [](int weight) { return weight; }); - - return buffer; -} - -static std::string -DecodeAI01320x(const BitArray& bits) -{ - static const int HEADER_SIZE = 4 + 1; - static const int WEIGHT_SIZE = 15; - - if (bits.size() != HEADER_SIZE + AI01_GTIN_SIZE + WEIGHT_SIZE) { - return std::string(); - } - - std::string buffer; - AI01EncodeCompressedGtin(buffer, bits, HEADER_SIZE); - AI01EncodeCompressedWeight(buffer, bits, HEADER_SIZE + AI01_GTIN_SIZE, WEIGHT_SIZE, - // addWeightCode - [](std::string& buf, int weight) { buf.append(weight < 10000 ? "(3202)" : "(3203)"); }, - // checkWeight - [](int weight) { return weight < 10000 ? weight : weight - 10000; }); - - return buffer; -} - -static std::string -DecodeAI01392x(const BitArray& bits) -{ - static const int HEADER_SIZE = 5 + 1 + 2; - static const int LAST_DIGIT_SIZE = 2; - - if (bits.size() < HEADER_SIZE + AI01_GTIN_SIZE) { - return std::string(); - } - - std::string buffer; - AI01EncodeCompressedGtin(buffer, bits, HEADER_SIZE); - - int lastAIdigit = ToInt(bits, HEADER_SIZE + AI01_GTIN_SIZE, LAST_DIGIT_SIZE); - buffer.append("(392"); - buffer.append(std::to_string(lastAIdigit)); - buffer.push_back(')'); - - int pos = HEADER_SIZE + AI01_GTIN_SIZE + LAST_DIGIT_SIZE; - int remainingValue = -1; - if (StatusIsOK(DecodeAppIdGeneralPurposeField(bits, pos, remainingValue, buffer)) - && StatusIsOK(DecodeAppIdAllCodes(bits, pos, remainingValue, buffer))) { - return buffer; - } - return std::string(); -} - -static std::string -DecodeAI01393x(const BitArray& bits) -{ - static const int HEADER_SIZE = 5 + 1 + 2; - static const int LAST_DIGIT_SIZE = 2; - static const int FIRST_THREE_DIGITS_SIZE = 10; - - if (bits.size() < HEADER_SIZE + AI01_GTIN_SIZE) { - return std::string(); - } - - std::string buffer; - AI01EncodeCompressedGtin(buffer, bits, HEADER_SIZE); - - int lastAIdigit = ToInt(bits, HEADER_SIZE + AI01_GTIN_SIZE, LAST_DIGIT_SIZE); - - buffer.append("(393"); - buffer.append(std::to_string(lastAIdigit)); - buffer.push_back(')'); - - int firstThreeDigits = ToInt(bits, HEADER_SIZE + AI01_GTIN_SIZE + LAST_DIGIT_SIZE, FIRST_THREE_DIGITS_SIZE); - if (firstThreeDigits / 100 == 0) { - buffer.push_back('0'); - } - if (firstThreeDigits / 10 == 0) { - buffer.push_back('0'); - } - buffer.append(std::to_string(firstThreeDigits)); - - int pos = HEADER_SIZE + AI01_GTIN_SIZE + LAST_DIGIT_SIZE + FIRST_THREE_DIGITS_SIZE; - int remainingValue = -1; - if (StatusIsOK(DecodeAppIdGeneralPurposeField(bits, pos, remainingValue, buffer)) - && StatusIsOK(DecodeAppIdAllCodes(bits, pos, remainingValue, buffer))) { - return buffer; - } - return std::string(); -} - -static std::string -DecodeAI013x0x1x(const BitArray& bits, const char* firstAIdigits, const char* dateCode) -{ - static const int HEADER_SIZE = 7 + 1; - static const int WEIGHT_SIZE = 20; - static const int DATE_SIZE = 16; - - if (bits.size() != HEADER_SIZE + AI01_GTIN_SIZE + WEIGHT_SIZE + DATE_SIZE) { - return std::string(); - } - - std::string buffer; - AI01EncodeCompressedGtin(buffer, bits, HEADER_SIZE); - AI01EncodeCompressedWeight(buffer, bits, HEADER_SIZE + AI01_GTIN_SIZE, WEIGHT_SIZE, - // addWeightCode - [firstAIdigits](std::string& buf, int weight) { - buf.push_back('('); - buf.append(firstAIdigits); - buf.append(std::to_string(weight / 100000)); - buf.push_back(')'); - }, - // checkWeight - [](int weight) { - return weight % 100000; - }); - - // encode compressed date - int numericDate = ToInt(bits, HEADER_SIZE + AI01_GTIN_SIZE + WEIGHT_SIZE, DATE_SIZE); - if (numericDate != 38400) { - buffer.push_back('('); - buffer.append(dateCode); - buffer.push_back(')'); - - int day = numericDate % 32; - numericDate /= 32; - int month = numericDate % 12 + 1; - numericDate /= 12; - int year = numericDate; - - if (year / 10 == 0) { - buffer.push_back('0'); - } - buffer.append(std::to_string(year)); - if (month / 10 == 0) { - buffer.push_back('0'); - } - buffer.append(std::to_string(month)); - if (day / 10 == 0) { - buffer.push_back('0'); - } - buffer.append(std::to_string(day)); - } - - return buffer; -} - -std::string -DecodeExpandedBits(const BitArray& bits) -{ - if (bits.get(1)) { - return DecodeAI01AndOtherAIs(bits); - } - if (!bits.get(2)) { - return DecodeAnyAI(bits); - } - - int fourBitEncodationMethod = ToInt(bits, 1, 4); - - switch (fourBitEncodationMethod) { - case 4: return DecodeAI013103(bits); - case 5: return DecodeAI01320x(bits); - } - - int fiveBitEncodationMethod = ToInt(bits, 1, 5); - switch (fiveBitEncodationMethod) { - case 12: return DecodeAI01392x(bits); - case 13: return DecodeAI01393x(bits); - } - - int sevenBitEncodationMethod = ToInt(bits, 1, 7); - switch (sevenBitEncodationMethod) { - case 56: return DecodeAI013x0x1x(bits, "310", "11"); - case 57: return DecodeAI013x0x1x(bits, "320", "11"); - case 58: return DecodeAI013x0x1x(bits, "310", "13"); - case 59: return DecodeAI013x0x1x(bits, "320", "13"); - case 60: return DecodeAI013x0x1x(bits, "310", "15"); - case 61: return DecodeAI013x0x1x(bits, "320", "15"); - case 62: return DecodeAI013x0x1x(bits, "310", "17"); - case 63: return DecodeAI013x0x1x(bits, "320", "17"); - } - - return std::string(); - //throw new IllegalStateException("unknown decoder: " + information); -} - -} // namespace ZXing::OneD::DataBar diff --git a/core/src/oned/rss/ODRSSExpandedBinaryDecoder.h b/core/src/oned/rss/ODRSSExpandedBinaryDecoder.h deleted file mode 100644 index 71900b66fe..0000000000 --- a/core/src/oned/rss/ODRSSExpandedBinaryDecoder.h +++ /dev/null @@ -1,30 +0,0 @@ -#pragma once -/* -* Copyright 2016 Nu-book Inc. -* Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#include - -namespace ZXing { - -class BitArray; - -namespace OneD::DataBar { - -std::string DecodeExpandedBits(const BitArray& bits); - -} // namespace OneD::DataBar -} // namespace ZXing diff --git a/core/src/oned/rss/ODRSSFieldParser.h b/core/src/oned/rss/ODRSSFieldParser.h deleted file mode 100644 index 16a37abd62..0000000000 --- a/core/src/oned/rss/ODRSSFieldParser.h +++ /dev/null @@ -1,30 +0,0 @@ -#pragma once -/* -* Copyright 2016 Nu-book Inc. -* Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#include - -namespace ZXing { - -enum class DecodeStatus; - -namespace OneD::DataBar { - -DecodeStatus ParseFieldsInGeneralPurpose(const std::string &rawInfo, std::string& result); - -} // namespace OneD::DataBar -} // namespace ZXing diff --git a/core/src/oned/rss/ODRSSGenericAppIdDecoder.cpp b/core/src/oned/rss/ODRSSGenericAppIdDecoder.cpp deleted file mode 100644 index 6f4881aa68..0000000000 --- a/core/src/oned/rss/ODRSSGenericAppIdDecoder.cpp +++ /dev/null @@ -1,508 +0,0 @@ -/* -* Copyright 2016 Nu-book Inc. -* Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#include "ODRSSGenericAppIdDecoder.h" - -#include "BitArray.h" -#include "DecodeStatus.h" -#include "ODRSSFieldParser.h" - -#include -#include -#include - -namespace ZXing::OneD::DataBar { - -struct DecodedValue -{ - int newPosition = std::numeric_limits::max(); - - DecodedValue() = default; - explicit DecodedValue(int np) : newPosition(np) {} - bool isValid() const { return newPosition != std::numeric_limits::max(); } -}; - -/** -* @author Pablo Orduña, University of Deusto (pablo.orduna@deusto.es) -* @author Eduardo Castillejo, University of Deusto (eduardo.castillejo@deusto.es) -*/ -struct DecodedChar : public DecodedValue -{ - static const char FNC1 = '$'; // It's not in Alphanumeric neither in ISO/IEC 646 charset - - char value = '\0'; - - DecodedChar() = default; - DecodedChar(int np, char c) : DecodedValue(np), value(c) {} - - bool isFNC1() const { return value == FNC1; } -}; - -/** -* @author Pablo Orduña, University of Deusto (pablo.orduna@deusto.es) -* @author Eduardo Castillejo, University of Deusto (eduardo.castillejo@deusto.es) -*/ -struct DecodedInformation : public DecodedValue -{ - std::string newString; - int remainingValue = -1; - - DecodedInformation() = default; - DecodedInformation(int np, std::string s) : DecodedValue(np), newString(std::move(s)) {} - DecodedInformation(int np, std::string s, int r) : DecodedValue(np), newString(std::move(s)), remainingValue(r) {} - - bool isRemaining() const { return remainingValue >= 0; } -}; - -/** -* @author Pablo Orduña, University of Deusto (pablo.orduna@deusto.es) -* @author Eduardo Castillejo, University of Deusto (eduardo.castillejo@deusto.es) -*/ -struct DecodedNumeric : public DecodedValue -{ - static const int FNC1 = 10; - - int firstDigit = 0; - int secondDigit = 0; - - DecodedNumeric() = default; - DecodedNumeric(int newPosition, int first, int second) : DecodedValue(newPosition), firstDigit(first), secondDigit(second) { - if (firstDigit < 0 || firstDigit > 10 || secondDigit < 0 || secondDigit > 10) { - *this = DecodedNumeric(); - } - } - - int value() const { - return firstDigit * 10 + secondDigit; - } - - bool isFirstDigitFNC1() const { - return firstDigit == FNC1; - } - - bool isSecondDigitFNC1() const { - return secondDigit == FNC1; - } - - bool isAnyFNC1() const { - return firstDigit == FNC1 || secondDigit == FNC1; - } - -private: -}; - -struct ParsingState -{ - enum State { - NUMERIC, - ALPHA, - ISO_IEC_646 - }; - - int position = 0; - State encoding = NUMERIC; -}; - -static bool -IsStillAlpha(const BitArray& bits, int pos) -{ - if (pos + 5 > bits.size()) { - return false; - } - - // We now check if it's a valid 5-bit value (0..9 and FNC1) - int fiveBitValue = ToInt(bits, pos, 5); - if (fiveBitValue >= 5 && fiveBitValue < 16) { - return true; - } - - if (pos + 6 > bits.size()) { - return false; - } - - int sixBitValue = ToInt(bits, pos, 6); - return sixBitValue >= 16 && sixBitValue < 63; // 63 not included -} - -static bool -IsStillIsoIec646(const BitArray& bits, int pos) -{ - if (pos + 5 > bits.size()) { - return false; - } - - int fiveBitValue = ToInt(bits, pos, 5); - if (fiveBitValue >= 5 && fiveBitValue < 16) { - return true; - } - - if (pos + 7 > bits.size()) { - return false; - } - - int sevenBitValue = ToInt(bits, pos, 7); - if (sevenBitValue >= 64 && sevenBitValue < 116) { - return true; - } - - if (pos + 8 > bits.size()) { - return false; - } - - int eightBitValue = ToInt(bits, pos, 8); - return eightBitValue >= 232 && eightBitValue < 253; -} - -static bool -IsStillNumeric(const BitArray& bits, int pos) -{ - // It's numeric if it still has 7 positions - // and one of the first 4 bits is "1". - if (pos + 7 > bits.size()) { - return pos + 4 <= bits.size(); - } - auto bitIter = bits.iterAt(pos); - for (int i = 0; i < 4; ++i, ++bitIter) { - if (*bitIter) { - return true; - } - } - return false; -} - -static DecodedChar -DecodeAlphanumeric(const BitArray& bits, int pos) -{ - int fiveBitValue = ToInt(bits, pos, 5); - if (fiveBitValue == 15) { - return DecodedChar(pos + 5, DecodedChar::FNC1); - } - - if (fiveBitValue >= 5 && fiveBitValue < 15) { - return DecodedChar(pos + 5, (char)('0' + fiveBitValue - 5)); - } - - int sixBitValue = ToInt(bits, pos, 6); - - if (sixBitValue >= 32 && sixBitValue < 58) { - return DecodedChar(pos + 6, (char)(sixBitValue + 33)); - } - - if (sixBitValue < 58 || sixBitValue > 62) - throw std::runtime_error("Decoding invalid alphanumeric value"); - - constexpr char const* lut58to62 = R"(*,-./)"; - char c = lut58to62[sixBitValue - 58]; - - return DecodedChar(pos + 6, c); -} - -static bool -IsAlphaTo646ToAlphaLatch(const BitArray& bits, int pos) -{ - if (pos + 1 > bits.size()) { - return false; - } - for (int i = 0; i < 5 && i + pos < bits.size(); ++i) { - if (i == 2) { - if (!bits.get(pos + 2)) { - return false; - } - } - else if (bits.get(pos + i)) { - return false; - } - } - return true; -} - -static bool -IsAlphaOr646ToNumericLatch(const BitArray& bits, int pos) -{ - // Next is alphanumeric if there are 3 positions and they are all zeros - if (pos + 3 > bits.size()) { - return false; - } - auto bitIter = bits.iterAt(pos); - for (int i = 0; i < 3; ++i, ++bitIter) { - if (*bitIter) { - return false; - } - } - return true; -} - -static bool -IsNumericToAlphaNumericLatch(const BitArray& bits, int pos) -{ - // Next is alphanumeric if there are 4 positions and they are all zeros, or - // if there is a subset of this just before the end of the symbol - if (pos + 1 > bits.size()) { - return false; - } - - auto bitIter = bits.iterAt(pos); - for (int i = 0; i < 4 && i + pos < bits.size(); ++i, ++bitIter) { - if (*bitIter) { - return false; - } - } - return true; -} - -static DecodedInformation -ParseAlphaBlock(const BitArray& bits, ParsingState& state, std::string& buffer) -{ - while (IsStillAlpha(bits, state.position)) { - DecodedChar alpha = DecodeAlphanumeric(bits, state.position); - state.position = alpha.newPosition; - - if (alpha.isFNC1()) { - // Allow for some generators incorrectly placing a numeric latch "000" after an FNC1 - if (state.position + 7 < bits.size() && ToInt(bits, state.position, 7) < 8) { - state.position += 3; - } - state.encoding = ParsingState::NUMERIC; // FNC1 latches to numeric encodation - return DecodedInformation(state.position, buffer); //end of the char block - } - buffer.push_back(alpha.value); - } - - if (IsAlphaOr646ToNumericLatch(bits, state.position)) { - state.position += 3; - state.encoding = ParsingState::NUMERIC; - } - else if (IsAlphaTo646ToAlphaLatch(bits, state.position)) { - if (state.position + 5 < bits.size()) { - state.position += 5; - } - else { - state.position = bits.size(); - } - state.encoding = ParsingState::ISO_IEC_646; - } - return DecodedInformation(); -} - -static DecodedChar -DecodeIsoIec646(const BitArray& bits, int pos) -{ - int fiveBitValue = ToInt(bits,pos, 5); - if (fiveBitValue == 15) { - return DecodedChar(pos + 5, DecodedChar::FNC1); - } - - if (fiveBitValue >= 5 && fiveBitValue < 15) { - return DecodedChar(pos + 5, (char)('0' + fiveBitValue - 5)); - } - - int sevenBitValue = ToInt(bits, pos, 7); - - if (sevenBitValue >= 64 && sevenBitValue < 90) { - return DecodedChar(pos + 7, (char)(sevenBitValue + 1)); - } - - if (sevenBitValue >= 90 && sevenBitValue < 116) { - return DecodedChar(pos + 7, (char)(sevenBitValue + 7)); - } - - int eightBitValue = ToInt(bits, pos, 8); - if (eightBitValue < 232 || eightBitValue > 252) - throw std::runtime_error("Decoding invalid ISO-IEC-646 value"); - - constexpr char const* lut232to252 = R"(!"%&'()*+,-./:;<=>?_ )"; - char c = lut232to252[eightBitValue - 232]; - - return DecodedChar(pos + 8, c); -} - -static DecodedInformation -ParseIsoIec646Block(const BitArray& bits, ParsingState& state, std::string& buffer) -{ - while (IsStillIsoIec646(bits, state.position)) { - DecodedChar iso = DecodeIsoIec646(bits, state.position); - state.position = iso.newPosition; - if (iso.isFNC1()) { - // Allow for some generators incorrectly placing a numeric latch "000" after an FNC1 - if (state.position + 7 < bits.size() && ToInt(bits, state.position, 7) < 8) { - state.position += 3; - } - state.encoding = ParsingState::NUMERIC; // FNC1 latches to numeric encodation - return DecodedInformation(state.position, buffer); - } - buffer.push_back(iso.value); - } - - if (IsAlphaOr646ToNumericLatch(bits, state.position)) { - state.position += 3;; - state.encoding = ParsingState::NUMERIC; - } - else if (IsAlphaTo646ToAlphaLatch(bits, state.position)) { - if (state.position + 5 < bits.size()) { - state.position += 5; - } - else { - state.position = bits.size(); - } - state.encoding = ParsingState::ALPHA; - } - return DecodedInformation(); -} - -static DecodedNumeric -DecodeNumeric(const BitArray& bits, int pos) -{ - if (pos + 7 > bits.size()) { - int numeric = ToInt(bits, pos, 4); - if (numeric == 0) { - return DecodedNumeric(bits.size(), DecodedNumeric::FNC1, DecodedNumeric::FNC1); - } - return DecodedNumeric(bits.size(), numeric - 1, DecodedNumeric::FNC1); - } - int numeric = ToInt(bits, pos, 7); - int digit1 = (numeric - 8) / 11; - int digit2 = (numeric - 8) % 11; - - return DecodedNumeric(pos + 7, digit1, digit2); -} - -static DecodedInformation -ParseNumericBlock(const BitArray& bits, ParsingState& state, std::string& buffer) -{ - while (IsStillNumeric(bits, state.position)) { - DecodedNumeric numeric = DecodeNumeric(bits, state.position); - if (!numeric.isValid()) - break; - state.position = numeric.newPosition; - - if (numeric.isFirstDigitFNC1()) { - DecodedInformation information; - if (numeric.isSecondDigitFNC1()) { - return DecodedInformation(state.position, buffer); - } - else { - return DecodedInformation(state.position, buffer, numeric.secondDigit); - } - } - - buffer.append(std::to_string(numeric.firstDigit)); - if (numeric.isSecondDigitFNC1()) { - return DecodedInformation(state.position, buffer); - } - buffer.append(std::to_string(numeric.secondDigit)); - } - - if (IsNumericToAlphaNumericLatch(bits, state.position)) { - state.encoding = ParsingState::ALPHA; - state.position += 4; - } - return DecodedInformation(); -} - - -static DecodedInformation -ParseBlocks(const BitArray& bits, ParsingState& state, std::string& buffer) -{ - while (true) { - int initialPosition = state.position; - auto result = - state.encoding == ParsingState::ALPHA ? - ParseAlphaBlock(bits, state, buffer) : - (state.encoding == ParsingState::ISO_IEC_646 ? - ParseIsoIec646Block(bits, state, buffer) : - // else - ParseNumericBlock(bits, state, buffer)); - if (result.isValid() || initialPosition == state.position) - { - return result; - } - } -} - -static DecodedInformation -DoDecodeGeneralPurposeField(ParsingState& state, const BitArray& bits, std::string prefix) -{ - DecodedInformation lastDecoded = ParseBlocks(bits, state, prefix); - if (lastDecoded.isValid() && lastDecoded.isRemaining()) { - return DecodedInformation(state.position, prefix, lastDecoded.remainingValue); - } - return DecodedInformation(state.position, prefix); -} - -DecodeStatus -DecodeAppIdGeneralPurposeField(const BitArray& bits, int& pos, int& remainingValue, std::string& result) -{ - try - { - ParsingState state; - state.position = pos; - DecodedInformation info = DoDecodeGeneralPurposeField(state, bits, std::string()); - result += info.newString; - pos = state.position; - remainingValue = info.remainingValue; - return DecodeStatus::NoError; - } - catch (const std::exception &) - { - } - return DecodeStatus::FormatError; -} - -DecodeStatus -DecodeAppIdAllCodes(const BitArray& bits, int pos, int remainingValue, std::string& result) -{ - try - { - ParsingState state; - std::string remaining; - if (remainingValue != -1) { - remaining = std::to_string(remainingValue); - } - while (true) { - state.position = pos; - DecodedInformation info = DoDecodeGeneralPurposeField(state, bits, remaining); - std::string parsedFields; - auto status = ParseFieldsInGeneralPurpose(info.newString, parsedFields); - if (StatusIsError(status)) { - if (result.empty() && remaining.empty()){ - result = info.newString; - return DecodeStatus::NoError; - } else - return status; - } - result += parsedFields; - if (info.isRemaining()) { - remaining = std::to_string(info.remainingValue); - } - else { - remaining.clear(); - } - - if (pos == info.newPosition) {// No step forward! - break; - } - pos = info.newPosition; - }; - return DecodeStatus::NoError; - } - catch (const std::exception &) - { - } - return DecodeStatus::FormatError; -} - -} // namespace ZXing::OneD::DataBar diff --git a/core/src/oned/rss/ODRSSGenericAppIdDecoder.h b/core/src/oned/rss/ODRSSGenericAppIdDecoder.h deleted file mode 100644 index e93ccd2d2b..0000000000 --- a/core/src/oned/rss/ODRSSGenericAppIdDecoder.h +++ /dev/null @@ -1,32 +0,0 @@ -#pragma once -/* -* Copyright 2016 Nu-book Inc. -* Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#include - -namespace ZXing { - -class BitArray; -enum class DecodeStatus; - -namespace OneD::DataBar { - -DecodeStatus DecodeAppIdGeneralPurposeField(const BitArray& bits, int& pos, int& remainingValue, std::string& result); -DecodeStatus DecodeAppIdAllCodes(const BitArray& bits, int pos, const int remainingValue, std::string& result); - -} // namespace OneD::DataBar -} // namespace ZXing diff --git a/core/src/pdf417/PDFBarcodeMetadata.h b/core/src/pdf417/PDFBarcodeMetadata.h index 33a3785722..335a7eb6f2 100644 --- a/core/src/pdf417/PDFBarcodeMetadata.h +++ b/core/src/pdf417/PDFBarcodeMetadata.h @@ -1,20 +1,10 @@ -#pragma once /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once namespace ZXing { namespace Pdf417 { diff --git a/core/src/pdf417/PDFBarcodeValue.cpp b/core/src/pdf417/PDFBarcodeValue.cpp index 2d02d0ff2f..da608efb7d 100644 --- a/core/src/pdf417/PDFBarcodeValue.cpp +++ b/core/src/pdf417/PDFBarcodeValue.cpp @@ -1,19 +1,8 @@ /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "PDFBarcodeValue.h" diff --git a/core/src/pdf417/PDFBarcodeValue.h b/core/src/pdf417/PDFBarcodeValue.h index d7d8ca7e92..c15c0f365c 100644 --- a/core/src/pdf417/PDFBarcodeValue.h +++ b/core/src/pdf417/PDFBarcodeValue.h @@ -1,20 +1,10 @@ -#pragma once /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include #include diff --git a/core/src/pdf417/PDFBoundingBox.cpp b/core/src/pdf417/PDFBoundingBox.cpp index fb07c74df2..bd9ea35cc8 100644 --- a/core/src/pdf417/PDFBoundingBox.cpp +++ b/core/src/pdf417/PDFBoundingBox.cpp @@ -1,19 +1,8 @@ /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "PDFBoundingBox.h" diff --git a/core/src/pdf417/PDFBoundingBox.h b/core/src/pdf417/PDFBoundingBox.h index a09eab4dd4..fe2f7344e5 100644 --- a/core/src/pdf417/PDFBoundingBox.h +++ b/core/src/pdf417/PDFBoundingBox.h @@ -1,20 +1,10 @@ -#pragma once /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include "ZXNullable.h" #include "ResultPoint.h" diff --git a/core/src/pdf417/PDFCodeword.h b/core/src/pdf417/PDFCodeword.h index 4a2d68de16..bc351e0c9c 100644 --- a/core/src/pdf417/PDFCodeword.h +++ b/core/src/pdf417/PDFCodeword.h @@ -1,20 +1,10 @@ -#pragma once /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once namespace ZXing { namespace Pdf417 { diff --git a/core/src/pdf417/PDFCodewordDecoder.cpp b/core/src/pdf417/PDFCodewordDecoder.cpp index ec84e962ac..4b9d8c1094 100644 --- a/core/src/pdf417/PDFCodewordDecoder.cpp +++ b/core/src/pdf417/PDFCodewordDecoder.cpp @@ -1,23 +1,12 @@ /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "PDFCodewordDecoder.h" #include "BitArray.h" -#include "ZXContainerAlgorithms.h" +#include "ZXAlgorithms.h" #include #include @@ -27,7 +16,7 @@ namespace ZXing { namespace Pdf417 { -static const int SYMBOL_COUNT = 2787; +static constexpr const int SYMBOL_COUNT = 2787; /** @@ -35,7 +24,7 @@ static const int SYMBOL_COUNT = 2787; * specification. The index of a symbol in this table corresponds to the * index into the codeword table. */ -const std::array SYMBOL_TABLE = { +static constexpr const std::array SYMBOL_TABLE = { 0x1025e, 0x1027a, 0x1029e, 0x102bc, 0x102f2, 0x102f4, 0x1032e, 0x1034e, 0x1035c, 0x10396, 0x103a6, 0x103ac, 0x10422, 0x10428, 0x10436, 0x10442, 0x10444, 0x10448, 0x10450, 0x1045e, 0x10466, 0x1046c, 0x1047a, 0x10482, 0x1049e, 0x104a0, 0x104bc, 0x104c6, 0x104d8, 0x104ee, 0x104f2, 0x104f4, 0x10504, 0x10508, 0x10510, 0x1051e, @@ -274,7 +263,7 @@ const std::array SYMBOL_TABLE = { /** * This table contains to codewords for all symbols. */ -static const std::array CODEWORD_TABLE = { +static constexpr const std::array CODEWORD_TABLE = { 2627, 1819, 2622, 2621, 1813, 1812, 2729, 2724, 2723, 2779, 2774, 2773, 902, 896, 908, 868, 865, 861, 859, 2511, 873, 871, 1780, 835, 2493, 825, 2491, 842, 837, 844, 1764, 1762, 811, 810, 809, 2483, 807, 2482, 806, 2480, 815, 814, 813, 812, 2484, 817, 816, 1745, 1744, 1742, 1746, 2655, 2637, 2635, 2626, 2625, 2623, 2628, 1820, 2752, @@ -423,7 +412,8 @@ using ModuleBitCountType = std::array; static const RatioTableType& GetRatioTable() { - auto initTable = [](RatioTableType& table) -> RatioTableType& { + static constexpr RatioTableType table = []() constexpr { + RatioTableType table{}; for (int i = 0; i < SYMBOL_COUNT; i++) { int currentSymbol = SYMBOL_TABLE[i]; int currentBit = currentSymbol & 0x1; @@ -438,11 +428,9 @@ static const RatioTableType& GetRatioTable() } } return table; - }; + }(); - static RatioTableType table; - static const auto& ref = initTable(table); - return ref; + return table; } static ModuleBitCountType SampleBitCounts(const ModuleBitCountType& moduleBitCount) diff --git a/core/src/pdf417/PDFCodewordDecoder.h b/core/src/pdf417/PDFCodewordDecoder.h index 12b63b5de8..cb661ff10b 100644 --- a/core/src/pdf417/PDFCodewordDecoder.h +++ b/core/src/pdf417/PDFCodewordDecoder.h @@ -1,20 +1,10 @@ -#pragma once /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include @@ -28,13 +18,13 @@ namespace Pdf417 { class CodewordDecoder { public: - static const int NUMBER_OF_CODEWORDS = 929; + static constexpr const int NUMBER_OF_CODEWORDS = 929; // Maximum Codewords (Data + Error). - static const int MAX_CODEWORDS_IN_BARCODE = NUMBER_OF_CODEWORDS - 1; + static constexpr const int MAX_CODEWORDS_IN_BARCODE = NUMBER_OF_CODEWORDS - 1; // One left row indication column + max 30 data columns + one right row indicator column //public static final int MAX_CODEWORDS_IN_ROW = 32; - static const int MODULES_IN_CODEWORD = 17; - static const int BARS_IN_MODULE = 8; + static constexpr const int MODULES_IN_CODEWORD = 17; + static constexpr const int BARS_IN_MODULE = 8; /** * @param symbol encoded symbol to translate to a codeword diff --git a/core/src/pdf417/PDFCompaction.h b/core/src/pdf417/PDFCompaction.h index ddaa0f3bee..b8ac5d7b02 100644 --- a/core/src/pdf417/PDFCompaction.h +++ b/core/src/pdf417/PDFCompaction.h @@ -1,20 +1,10 @@ -#pragma once /* * Copyright 2016 Huy Cuong Nguyen * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once namespace ZXing { namespace Pdf417 { diff --git a/core/src/pdf417/PDFDecodedBitStreamParser.cpp b/core/src/pdf417/PDFDecodedBitStreamParser.cpp index ab61c4c6c8..72f8989505 100644 --- a/core/src/pdf417/PDFDecodedBitStreamParser.cpp +++ b/core/src/pdf417/PDFDecodedBitStreamParser.cpp @@ -1,24 +1,13 @@ /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "PDFDecodedBitStreamParser.h" #include "ByteArray.h" -#include "CharacterSetECI.h" +#include "CharacterSet.h" #include "DecoderResult.h" #include "DecodeStatus.h" #include "PDFDecoderResultExtra.h" @@ -35,7 +24,8 @@ namespace ZXing::Pdf417 { -enum class Mode { +enum class Mode +{ ALPHA, LOWER, MIXED, @@ -77,6 +67,11 @@ static const char* MIXED_CHARS = "0123456789&\r\t,:#-.$/+%*=^"; static const int NUMBER_OF_SEQUENCE_CODEWORDS = 2; +inline bool IsECI(int code) +{ + return code >= ECI_USER_DEFINED && code <= ECI_CHARSET; +} + /** * Whether a codeword terminates a Compaction mode. * @@ -99,17 +94,13 @@ static bool TerminatesCompaction(int code) /** * Helper to process ECIs. **/ -static int ProcessECI(const std::vector& codewords, int codeIndex, const int length, const int code, - std::wstring& resultEncoded, std::string& result, CharacterSet& encoding) +static int ProcessECI(const std::vector& codewords, int codeIndex, const int length, const int code, Content& result) { - if (codeIndex < length && code >= ECI_USER_DEFINED && code <= ECI_CHARSET) { - if (code == ECI_CHARSET) { - encoding = CharacterSetECI::OnChangeAppendReset(codewords[codeIndex++], resultEncoded, result, encoding); - } - else { - // Don't currently handle non-character set ECIs so just ignore - codeIndex += code == ECI_GENERAL_PURPOSE ? 2 : 1; - } + if (codeIndex < length && IsECI(code)) { + if (code == ECI_CHARSET) + result.switchEncoding(ECI(codewords[codeIndex++])); + else + codeIndex += code == ECI_GENERAL_PURPOSE ? 2 : 1; // Don't currently handle non-character set ECIs so just ignore } return codeIndex; @@ -127,12 +118,9 @@ static int ProcessECI(const std::vector& codewords, int codeIndex, const in * * @param textCompactionData The text compaction data. * @param length The size of the text compaction data. -* @param resultEncoded The Unicode-encoded data. * @param result The data in the character set encoding. -* @param encoding Currently active character encoding. */ -static void DecodeTextCompaction(const std::vector& textCompactionData, int length, std::wstring& resultEncoded, - std::string& result, CharacterSet& encoding) +static void DecodeTextCompaction(const std::vector& textCompactionData, int length, Content& result) { // Beginning from an initial state of the Alpha sub-mode // The default compaction mode for PDF417 in effect at the start of each symbol shall always be Text @@ -145,20 +133,18 @@ static void DecodeTextCompaction(const std::vector& textCompactionData, int int subModeCh = textCompactionData[i]; // Note only have ECI and MODE_SHIFT_TO_BYTE_COMPACTION_MODE function codewords in text compaction array - if (subModeCh >= ECI_USER_DEFINED && subModeCh <= ECI_CHARSET) { - i = ProcessECI(textCompactionData, i + 1, length, subModeCh, resultEncoded, result, encoding); + if (IsECI(subModeCh)) { + i = ProcessECI(textCompactionData, i + 1, length, subModeCh, result); continue; } if (subModeCh == MODE_SHIFT_TO_BYTE_COMPACTION_MODE) { i++; - while (i < length && textCompactionData[i] >= ECI_USER_DEFINED && textCompactionData[i] <= ECI_CHARSET) { - i = ProcessECI(textCompactionData, i + 1, length, textCompactionData[i], resultEncoded, result, - encoding); - } - if (i < length) { - result.push_back((uint8_t)textCompactionData[i]); - i++; - } + while (i < length && IsECI(textCompactionData[i])) + i = ProcessECI(textCompactionData, i + 1, length, textCompactionData[i], result); + + if (i < length) + result.push_back((uint8_t)textCompactionData[i++]); + continue; } @@ -170,19 +156,15 @@ static void DecodeTextCompaction(const std::vector& textCompactionData, int if (subModeCh < 26) { // Upper/lowercase character ch = (char)((subMode == Mode::ALPHA ? 'A' : 'a') + subModeCh); - } - else if (subModeCh == 26) { // Space + } else if (subModeCh == 26) { // Space ch = ' '; - } - else if (subModeCh == 27 && subMode == Mode::ALPHA) { // LL + } else if (subModeCh == 27 && subMode == Mode::ALPHA) { // LL subMode = Mode::LOWER; - } - else if (subModeCh == 27 && subMode == Mode::LOWER) { // AS + } else if (subModeCh == 27 && subMode == Mode::LOWER) { // AS // Shift to alpha priorToShiftMode = subMode; subMode = Mode::ALPHA_SHIFT; - } - else if (subModeCh == 28) { // ML + } else if (subModeCh == 28) { // ML subMode = Mode::MIXED; } // 29 PS - ignore if last or followed by Shift to Byte, 5.4.2.4 (b) (1) @@ -197,17 +179,13 @@ static void DecodeTextCompaction(const std::vector& textCompactionData, int // Mixed (numeric and some punctuation) if (subModeCh < 25) { ch = MIXED_CHARS[subModeCh]; - } - else if (subModeCh == 25) { // PL + } else if (subModeCh == 25) { // PL subMode = Mode::PUNCT; - } - else if (subModeCh == 26) { // Space + } else if (subModeCh == 26) { // Space ch = ' '; - } - else if (subModeCh == 27) { // LL + } else if (subModeCh == 27) { // LL subMode = Mode::LOWER; - } - else if (subModeCh == 28) { // AL + } else if (subModeCh == 28) { // AL subMode = Mode::ALPHA; } // 29 PS - ignore if last or followed by Shift to Byte, 5.4.2.4 (b) (1) @@ -220,41 +198,33 @@ static void DecodeTextCompaction(const std::vector& textCompactionData, int case Mode::PUNCT: // Punctuation - if (subModeCh < 29) { + if (subModeCh < 29) ch = PUNCT_CHARS[subModeCh]; - } - else { // 29 AL - note not ignored if followed by Shift to Byte, 5.4.2.4 (b) (2) + else // 29 AL - note not ignored if followed by Shift to Byte, 5.4.2.4 (b) (2) subMode = Mode::ALPHA; - } break; case Mode::ALPHA_SHIFT: // Restore sub-mode subMode = priorToShiftMode; - if (subModeCh < 26) { + if (subModeCh < 26) ch = (char)('A' + subModeCh); - } - else if (subModeCh == 26) { // Space + else if (subModeCh == 26) // Space ch = ' '; - } // 27 LL, 28 ML, 29 PS used as padding break; case Mode::PUNCT_SHIFT: // Restore sub-mode subMode = priorToShiftMode; - if (subModeCh < 29) { + if (subModeCh < 29) ch = PUNCT_CHARS[subModeCh]; - } - else { // 29 AL + else // 29 AL subMode = Mode::ALPHA; - } break; } - if (ch != 0) { - // Append decoded character to result - result.push_back(ch); - } + if (ch != 0) + result.push_back(ch); // Append decoded character to result i++; } } @@ -262,8 +232,9 @@ static void DecodeTextCompaction(const std::vector& textCompactionData, int /* * Helper to put ECI codewords into Text Compaction array. */ -static int ProcessTextECI(std::vector& textCompactionData, int& index, - const std::vector& codewords, int codeIndex, const int code) { +static int ProcessTextECI(std::vector& textCompactionData, int& index, const std::vector& codewords, int codeIndex, + const int code) +{ textCompactionData[index++] = code; if (codeIndex < codewords[0]) { textCompactionData[index++] = codewords[codeIndex++]; @@ -282,13 +253,10 @@ static int ProcessTextECI(std::vector& textCompactionData, int& index, * * @param codewords The array of codewords (data + error) * @param codeIndex The current index into the codeword array. -* @param resultEncoded The Unicode-encoded data. * @param result The data in the character set encoding. -* @param encoding Currently active character encoding. * @return The next index into the codeword array. */ -static int TextCompaction(DecodeStatus& status, const std::vector& codewords, int codeIndex, - std::wstring& resultEncoded, std::string& result, CharacterSet& encoding) +static int TextCompaction(const std::vector& codewords, int codeIndex, Content& result) { // 2 characters per codeword std::vector textCompactionData((codewords[0] - codeIndex) * 2, 0); @@ -302,8 +270,7 @@ static int TextCompaction(DecodeStatus& status, const std::vector& codeword textCompactionData[index] = code / 30; textCompactionData[index + 1] = code % 30; index += 2; - } - else { + } else { switch (code) { case MODE_SHIFT_TO_BYTE_COMPACTION_MODE: // The Mode Shift codeword 913 shall cause a temporary @@ -314,14 +281,11 @@ static int TextCompaction(DecodeStatus& status, const std::vector& codeword // in Text Compaction mode; its use is described in 5.4.2.4. textCompactionData[index++] = MODE_SHIFT_TO_BYTE_COMPACTION_MODE; // 5.5.3.1 allows ECIs anywhere in Text Compaction, including after a Shift to Byte - while (codeIndex < codewords[0] && codewords[codeIndex] >= ECI_USER_DEFINED - && codewords[codeIndex] <= ECI_CHARSET) { - codeIndex = ProcessTextECI(textCompactionData, index, codewords, codeIndex + 1, - codewords[codeIndex]); + while (codeIndex < codewords[0] && IsECI(codewords[codeIndex])) { + codeIndex = ProcessTextECI(textCompactionData, index, codewords, codeIndex + 1, codewords[codeIndex]); } - if (codeIndex < codewords[0]) { + if (codeIndex < codewords[0]) textCompactionData[index++] = codewords[codeIndex++]; // Byte to shift - } break; case ECI_CHARSET: case ECI_GENERAL_PURPOSE: @@ -329,17 +293,16 @@ static int TextCompaction(DecodeStatus& status, const std::vector& codeword codeIndex = ProcessTextECI(textCompactionData, index, codewords, codeIndex, code); break; default: - if (!TerminatesCompaction(code)) { - status = DecodeStatus::FormatError; - return codeIndex; - } + if (!TerminatesCompaction(code)) + throw FormatError(); + codeIndex--; end = true; break; } } } - DecodeTextCompaction(textCompactionData, index, resultEncoded, result, encoding); + DecodeTextCompaction(textCompactionData, index, result); return codeIndex; } @@ -347,8 +310,7 @@ static int TextCompaction(DecodeStatus& status, const std::vector& codeword * Helper for Byte Compaction to look ahead and count 5-codeword batches and trailing bytes, with some checking of * format errors. */ -static int CountByteBatches(DecodeStatus& status, int mode, const std::vector& codewords, int codeIndex, - int& trailingCount) +static int CountByteBatches(int mode, const std::vector& codewords, int codeIndex, int& trailingCount) { int count = 0; trailingCount = 0; @@ -356,29 +318,24 @@ static int CountByteBatches(DecodeStatus& status, int mode, const std::vector= TEXT_COMPACTION_MODE_LATCH) { - if (mode == BYTE_COMPACTION_MODE_LATCH_6 && count && count % 5) { - status = DecodeStatus::FormatError; - return 0; - } - if (code >= ECI_USER_DEFINED && code <= ECI_CHARSET) { + if (mode == BYTE_COMPACTION_MODE_LATCH_6 && count && count % 5) + throw FormatError(); + + if (IsECI(code)) { codeIndex += code == ECI_GENERAL_PURPOSE ? 2 : 1; continue; } - if (!TerminatesCompaction(code)) { - status = DecodeStatus::FormatError; - return 0; - } + if (!TerminatesCompaction(code)) + throw FormatError(); break; } count++; } - if (codeIndex > codewords[0]) { - status = DecodeStatus::FormatError; - return 0; - } - if (count == 0) { + if (codeIndex > codewords[0]) + throw FormatError(); + + if (count == 0) return 0; - } if (mode == BYTE_COMPACTION_MODE_LATCH) { trailingCount = count % 5; @@ -386,12 +343,9 @@ static int CountByteBatches(DecodeStatus& status, int mode, const std::vector& codewords, int codeIndex, - std::wstring& resultEncoded, std::string& result, CharacterSet& encoding) +static int ProcessByteECIs(const std::vector& codewords, int codeIndex, Content& result) { while (codeIndex < codewords[0] && codewords[codeIndex] >= TEXT_COMPACTION_MODE_LATCH && !TerminatesCompaction(codewords[codeIndex])) { int code = codewords[codeIndex++]; - if (code >= ECI_USER_DEFINED && code <= ECI_CHARSET) { - codeIndex = ProcessECI(codewords, codeIndex, codewords[0], code, resultEncoded, result, encoding); - } + if (IsECI(code)) + codeIndex = ProcessECI(codewords, codeIndex, codewords[0], code, result); } return codeIndex; @@ -423,41 +375,34 @@ static int ProcessByteECIs(const std::vector& codewords, int codeIndex, * @param mode The byte compaction mode i.e. 901 or 924 * @param codewords The array of codewords (data + error) * @param codeIndex The current index into the codeword array. -* @param resultEncoded The Unicode-encoded data. * @param result The data in the character set encoding. -* @param encoding Currently active character encoding. * @return The next index into the codeword array. */ -static int ByteCompaction(DecodeStatus& status, int mode, const std::vector& codewords, int codeIndex, - std::wstring& resultEncoded, std::string& result, CharacterSet& encoding) +static int ByteCompaction(int mode, const std::vector& codewords, int codeIndex, Content& result) { // Count number of 5-codeword batches and trailing bytes int trailingCount; - int batches = CountByteBatches(status, mode, codewords, codeIndex, trailingCount); - - if (StatusIsError(status)) { - return codeIndex; - } + int batches = CountByteBatches(mode, codewords, codeIndex, trailingCount); // Deal with initial ECIs - codeIndex = ProcessByteECIs(codewords, codeIndex, resultEncoded, result, encoding); + codeIndex = ProcessByteECIs(codewords, codeIndex, result); for (int batch = 0; batch < batches; batch++) { int64_t value = 0; - for (int count = 0; count < 5; count++) { + for (int count = 0; count < 5; count++) value = 900 * value + codewords[codeIndex++]; - } - for (int j = 0; j < 6; ++j) { + + for (int j = 0; j < 6; ++j) result.push_back((uint8_t)(value >> (8 * (5 - j)))); - } + // Deal with inter-batch ECIs - codeIndex = ProcessByteECIs(codewords, codeIndex, resultEncoded, result, encoding); + codeIndex = ProcessByteECIs(codewords, codeIndex, result); } for (int i = 0; i < trailingCount; i++) { result.push_back((uint8_t)codewords[codeIndex++]); // Deal with inter-byte ECIs - codeIndex = ProcessByteECIs(codewords, codeIndex, resultEncoded, result, encoding); + codeIndex = ProcessByteECIs(codewords, codeIndex, result); } return codeIndex; @@ -507,29 +452,27 @@ Decode the above codewords involves Remove leading 1 => Result is 000213298174000 */ -static DecodeStatus DecodeBase900toBase10(const std::vector& codewords, int count, std::string& resultString) +static std::string DecodeBase900toBase10(const std::vector& codewords, int count) { // Table containing values for the exponent of 900. static const auto EXP900 = []() { std::array table = {1, 900}; - for (size_t i = 2; i < table.size(); ++i) { + for (size_t i = 2; i < table.size(); ++i) table[i] = table[i - 1] * 900; - } return table; }(); assert(count <= 16); BigInteger result; - for (int i = 0; i < count; i++) { + for (int i = 0; i < count; i++) result += EXP900[count - i - 1] * codewords[i]; - } - resultString = result.toString(); - if (!resultString.empty() && resultString.front() == '1') { - resultString = resultString.substr(1); - return DecodeStatus::NoError; - } - return DecodeStatus::FormatError; + + std::string resultString = result.toString(); + if (!resultString.empty() && resultString.front() == '1') + return resultString.substr(1); + + throw FormatError(); } @@ -543,8 +486,7 @@ static DecodeStatus DecodeBase900toBase10(const std::vector& codewords, int * @param encoding Currently active character encoding. * @return The next index into the codeword array. */ -static int NumericCompaction(DecodeStatus& status, const std::vector& codewords, int codeIndex, - std::wstring& resultEncoded, std::string& result, CharacterSet& encoding) +static int NumericCompaction(const std::vector& codewords, int codeIndex, Content& result) { int count = 0; bool end = false; @@ -554,25 +496,19 @@ static int NumericCompaction(DecodeStatus& status, const std::vector& codew while (codeIndex < codewords[0] && !end) { int code = codewords[codeIndex++]; if (code >= TEXT_COMPACTION_MODE_LATCH) { - if (code >= ECI_USER_DEFINED && code <= ECI_CHARSET) { + if (IsECI(code)) { // As operating in Basic Channel Mode (i.e. not embedding backslashed ECIs and doubling backslashes) // allow ECIs anywhere in Numeric Compaction (i.e. ISO/IEC 15438:2015 5.5.3.4 doesn't apply). if (count > 0) { - std::string tmp; - status = DecodeBase900toBase10(numericCodewords, count, tmp); - if (StatusIsError(status)) { - return codeIndex; - } - result += tmp; + result += DecodeBase900toBase10(numericCodewords, count); count = 0; } - codeIndex = ProcessECI(codewords, codeIndex, codewords[0], code, resultEncoded, result, encoding); + codeIndex = ProcessECI(codewords, codeIndex, codewords[0], code, result); continue; } - if (!TerminatesCompaction(code)) { - status = DecodeStatus::FormatError; - return codeIndex; - } + if (!TerminatesCompaction(code)) + throw FormatError(); + codeIndex--; end = true; } @@ -589,12 +525,7 @@ static int NumericCompaction(DecodeStatus& status, const std::vector& codew // current Numeric Compaction mode grouping as described in 5.4.4.2, // and then to start a new one grouping. if (count > 0) { - std::string tmp; - status = DecodeBase900toBase10(numericCodewords, count, tmp); - if (StatusIsError(status)) { - return codeIndex; - } - result += tmp; + result += DecodeBase900toBase10(numericCodewords, count); count = 0; } } @@ -605,20 +536,17 @@ static int NumericCompaction(DecodeStatus& status, const std::vector& codew /* * Helper to deal with optional text fields in Macros. */ -static int DecodeMacroOptionalTextField(DecodeStatus& status, const std::vector& codewords, int codeIndex, - std::string& field) +static int DecodeMacroOptionalTextField(const std::vector& codewords, int codeIndex, std::string& field) { - std::wstring resultEncoded; - std::string result; + Content result; // Each optional field begins with an implied reset to ECI 2 (Annex H.2.3). ECI 2 is ASCII for 0-127, and Cp437 // for non-ASCII (128-255). Text optional fields can contain ECIs. - CharacterSet encoding = CharacterSet::Cp437; + result.defaultCharset = "Cp437"; - codeIndex = TextCompaction(status, codewords, codeIndex, resultEncoded, result, encoding); - TextDecoder::Append(resultEncoded, reinterpret_cast(result.data()), result.size(), encoding); + codeIndex = TextCompaction(codewords, codeIndex, result); // Converting to UTF-8 (backward-incompatible change for non-ASCII chars) - TextUtfEncoding::ToUtf8(resultEncoded, field); + field = result.utf8(); return codeIndex; } @@ -626,41 +554,33 @@ static int DecodeMacroOptionalTextField(DecodeStatus& status, const std::vector< /* * Helper to deal with optional numeric fields in Macros. */ -static int DecodeMacroOptionalNumericField(DecodeStatus& status, const std::vector& codewords, int codeIndex, - uint64_t& field) +static int DecodeMacroOptionalNumericField(const std::vector& codewords, int codeIndex, uint64_t& field) { - std::wstring resultEncoded; - std::string result; - // Each optional field begins with an implied reset to ECI 2 (Annex H.2.3). - // Numeric optional fields should not contain ECIs, but processed anyway. - CharacterSet encoding = CharacterSet::Cp437; + Content result; + // Each optional field begins with an implied reset to ECI 2 (Annex H.2.3). ECI 2 is ASCII for 0-127, and Cp437 + // for non-ASCII (128-255). Text optional fields can contain ECIs. + result.defaultCharset = "Cp437"; - codeIndex = NumericCompaction(status, codewords, codeIndex, resultEncoded, result, encoding); - TextDecoder::Append(resultEncoded, reinterpret_cast(result.data()), result.size(), encoding); + codeIndex = NumericCompaction(codewords, codeIndex, result); - field = std::stoll(resultEncoded); + field = std::stoll(result.utf8()); return codeIndex; } ZXING_EXPORT_TEST_ONLY -DecodeStatus DecodeMacroBlock(const std::vector& codewords, int codeIndex, DecoderResultExtra& resultMetadata, - int& next) +int DecodeMacroBlock(const std::vector& codewords, int codeIndex, DecoderResultExtra& resultMetadata) { - if (codeIndex + NUMBER_OF_SEQUENCE_CODEWORDS > codewords[0]) { - // we must have at least two bytes left for the segment index - return DecodeStatus::FormatError; - } + // we must have at least two bytes left for the segment index + if (codeIndex + NUMBER_OF_SEQUENCE_CODEWORDS > codewords[0]) + throw FormatError(); + std::vector segmentIndexArray(NUMBER_OF_SEQUENCE_CODEWORDS); - for (int i = 0; i < NUMBER_OF_SEQUENCE_CODEWORDS; i++, codeIndex++) { + for (int i = 0; i < NUMBER_OF_SEQUENCE_CODEWORDS; i++, codeIndex++) segmentIndexArray[i] = codewords[codeIndex]; - } - std::string strBuf; - DecodeStatus status = DecodeBase900toBase10(segmentIndexArray, NUMBER_OF_SEQUENCE_CODEWORDS, strBuf); - if (StatusIsError(status)) { - return status; - } + std::string strBuf = DecodeBase900toBase10(segmentIndexArray, NUMBER_OF_SEQUENCE_CODEWORDS); + resultMetadata.setSegmentIndex(std::stoi(strBuf)); // Decoding the fileId codewords as 0-899 numbers, each 0-filled to width 3. This follows the spec @@ -668,69 +588,67 @@ DecodeStatus DecodeMacroBlock(const std::vector& codewords, int codeIndex, // the fileId using text compaction, so in those cases the fileId will appear mangled. std::ostringstream fileId; fileId.fill('0'); - for (; codeIndex < codewords[0] && codewords[codeIndex] != MACRO_PDF417_TERMINATOR && - codewords[codeIndex] != BEGIN_MACRO_PDF417_OPTIONAL_FIELD; + for (; codeIndex < codewords[0] && codewords[codeIndex] != MACRO_PDF417_TERMINATOR + && codewords[codeIndex] != BEGIN_MACRO_PDF417_OPTIONAL_FIELD; codeIndex++) { fileId << std::setw(3) << codewords[codeIndex]; } resultMetadata.setFileId(fileId.str()); int optionalFieldsStart = -1; - if (codeIndex < codewords[0] && codewords[codeIndex] == BEGIN_MACRO_PDF417_OPTIONAL_FIELD) { + if (codeIndex < codewords[0] && codewords[codeIndex] == BEGIN_MACRO_PDF417_OPTIONAL_FIELD) optionalFieldsStart = codeIndex + 1; - } while (codeIndex < codewords[0]) { switch (codewords[codeIndex]) { case BEGIN_MACRO_PDF417_OPTIONAL_FIELD: { codeIndex++; - if (codeIndex >= codewords[0]) { + if (codeIndex >= codewords[0]) break; - } switch (codewords[codeIndex]) { case MACRO_PDF417_OPTIONAL_FIELD_FILE_NAME: { std::string fileName; - codeIndex = DecodeMacroOptionalTextField(status, codewords, codeIndex + 1, fileName); + codeIndex = DecodeMacroOptionalTextField(codewords, codeIndex + 1, fileName); resultMetadata.setFileName(fileName); break; } case MACRO_PDF417_OPTIONAL_FIELD_SENDER: { std::string sender; - codeIndex = DecodeMacroOptionalTextField(status, codewords, codeIndex + 1, sender); + codeIndex = DecodeMacroOptionalTextField(codewords, codeIndex + 1, sender); resultMetadata.setSender(sender); break; } case MACRO_PDF417_OPTIONAL_FIELD_ADDRESSEE: { std::string addressee; - codeIndex = DecodeMacroOptionalTextField(status, codewords, codeIndex + 1, addressee); + codeIndex = DecodeMacroOptionalTextField(codewords, codeIndex + 1, addressee); resultMetadata.setAddressee(addressee); break; } case MACRO_PDF417_OPTIONAL_FIELD_SEGMENT_COUNT: { uint64_t segmentCount; - codeIndex = DecodeMacroOptionalNumericField(status, codewords, codeIndex + 1, segmentCount); - resultMetadata.setSegmentCount(static_cast(segmentCount)); + codeIndex = DecodeMacroOptionalNumericField(codewords, codeIndex + 1, segmentCount); + resultMetadata.setSegmentCount(narrow_cast(segmentCount)); break; } case MACRO_PDF417_OPTIONAL_FIELD_TIME_STAMP: { uint64_t timestamp; - codeIndex = DecodeMacroOptionalNumericField(status, codewords, codeIndex + 1, timestamp); + codeIndex = DecodeMacroOptionalNumericField(codewords, codeIndex + 1, timestamp); resultMetadata.setTimestamp(timestamp); break; } case MACRO_PDF417_OPTIONAL_FIELD_CHECKSUM: { uint64_t checksum; - codeIndex = DecodeMacroOptionalNumericField(status, codewords, codeIndex + 1, checksum); - resultMetadata.setChecksum(static_cast(checksum)); + codeIndex = DecodeMacroOptionalNumericField(codewords, codeIndex + 1, checksum); + resultMetadata.setChecksum(narrow_cast(checksum)); break; } case MACRO_PDF417_OPTIONAL_FIELD_FILE_SIZE: { uint64_t fileSize; - codeIndex = DecodeMacroOptionalNumericField(status, codewords, codeIndex + 1, fileSize); + codeIndex = DecodeMacroOptionalNumericField(codewords, codeIndex + 1, fileSize); resultMetadata.setFileSize(fileSize); break; } - default: status = DecodeStatus::FormatError; break; + default: throw FormatError(); } break; } @@ -739,109 +657,93 @@ DecodeStatus DecodeMacroBlock(const std::vector& codewords, int codeIndex, resultMetadata.setLastSegment(true); break; } - default: status = DecodeStatus::FormatError; break; - } - if (StatusIsError(status)) { - return status; + default: throw FormatError(); } } // copy optional fields to additional options if (optionalFieldsStart != -1) { int optionalFieldsLength = codeIndex - optionalFieldsStart; - if (resultMetadata.isLastSegment()) { - // do not include terminator - optionalFieldsLength--; - } + if (resultMetadata.isLastSegment()) + optionalFieldsLength--; // do not include terminator + resultMetadata.setOptionalData(std::vector(codewords.begin() + optionalFieldsStart, codewords.begin() + optionalFieldsStart + optionalFieldsLength)); } - next = codeIndex; - return DecodeStatus::NoError; + return codeIndex; } DecoderResult -DecodedBitStreamParser::Decode(const std::vector& codewords, int ecLevel, const std::string& characterSet) +DecodedBitStreamParser::Decode(const std::vector& codewords, int ecLevel) { - std::wstring resultEncoded; - std::string result; - auto encoding = CharacterSetECI::InitEncoding(characterSet); + Content result; + result.symbology = { 'L', '2', -1 }; + bool readerInit = false; auto resultMetadata = std::make_shared(); int codeIndex = 1; - DecodeStatus status = DecodeStatus::NoError; - while (codeIndex < codewords[0] && status == DecodeStatus::NoError) { + while (codeIndex < codewords[0]) { int code = codewords[codeIndex++]; switch (code) { case TEXT_COMPACTION_MODE_LATCH: - codeIndex = TextCompaction(status, codewords, codeIndex, resultEncoded, result, encoding); + codeIndex = TextCompaction(codewords, codeIndex, result); break; case MODE_SHIFT_TO_BYTE_COMPACTION_MODE: // This should only be encountered once in this loop, when default Text Compaction mode applies // (see default case below) - codeIndex = TextCompaction(status, codewords, codeIndex - 1, resultEncoded, result, encoding); + codeIndex = TextCompaction(codewords, codeIndex - 1, result); break; case BYTE_COMPACTION_MODE_LATCH: case BYTE_COMPACTION_MODE_LATCH_6: - codeIndex = ByteCompaction(status, code, codewords, codeIndex, resultEncoded, result, encoding); + codeIndex = ByteCompaction(code, codewords, codeIndex, result); break; case NUMERIC_COMPACTION_MODE_LATCH: - codeIndex = NumericCompaction(status, codewords, codeIndex, resultEncoded, result, encoding); + codeIndex = NumericCompaction(codewords, codeIndex, result); break; case ECI_CHARSET: case ECI_GENERAL_PURPOSE: case ECI_USER_DEFINED: - codeIndex = ProcessECI(codewords, codeIndex, codewords[0], code, resultEncoded, result, encoding); + codeIndex = ProcessECI(codewords, codeIndex, codewords[0], code, result); break; case BEGIN_MACRO_PDF417_CONTROL_BLOCK: - status = DecodeMacroBlock(codewords, codeIndex, *resultMetadata, codeIndex); + codeIndex = DecodeMacroBlock(codewords, codeIndex, *resultMetadata); break; case BEGIN_MACRO_PDF417_OPTIONAL_FIELD: case MACRO_PDF417_TERMINATOR: // Should not see these outside a macro block - status = DecodeStatus::FormatError; + throw FormatError(); break; case READER_INIT: - if (codeIndex != 2) { // Must be first codeword after symbol length (ISO/IEC 15438:2015 5.4.1.4) - status = DecodeStatus::FormatError; - } - else { + if (codeIndex != 2) // Must be first codeword after symbol length (ISO/IEC 15438:2015 5.4.1.4) + throw FormatError(); + else readerInit = true; - } break; case LINKAGE_EANUCC: - if (codeIndex != 2) { // Must be first codeword after symbol length (GS1 Composite ISO/IEC 24723:2010 4.3) - status = DecodeStatus::FormatError; - } - else { - // TODO: handle - } + if (codeIndex != 2) // Must be first codeword after symbol length (GS1 Composite ISO/IEC 24723:2010 4.3) + throw FormatError(); + // TODO: handle else case break; case LINKAGE_OTHER: // Allowed to treat as invalid by ISO/IEC 24723:2010 5.4.1.5 and 5.4.6.1 when in Basic Channel Mode - status = DecodeStatus::FormatError; // TODO: add NotSupported error + throw UnsupportedError("LINKAGE_OTHER, see ISO/IEC 24723:2010 5.4.1.5"); break; default: if (code >= TEXT_COMPACTION_MODE_LATCH) { // Reserved codewords (all others in switch) // Allowed to treat as invalid by ISO/IEC 24723:2010 5.4.6.1 when in Basic Channel Mode - status = DecodeStatus::FormatError; // TODO: add NotSupported error - } - else { + throw UnsupportedError("TEXT_COMPACTION_MODE_LATCH, see ISO/IEC 24723:2010 5.4.6.1"); + } else { // Default mode is Text Compaction mode Alpha sub-mode (ISO/IEC 15438:2015 5.4.2.1) - codeIndex = TextCompaction(status, codewords, codeIndex - 1, resultEncoded, result, encoding); + codeIndex = TextCompaction(codewords, codeIndex - 1, result); } break; } } - TextDecoder::Append(resultEncoded, reinterpret_cast(result.data()), result.size(), encoding); - - if (resultEncoded.empty() && resultMetadata->segmentIndex() == -1) - return DecodeStatus::FormatError; - if (StatusIsError(status)) - return status; + if (result.empty() && resultMetadata->segmentIndex() == -1) + return FormatError(); StructuredAppendInfo sai; if (resultMetadata->segmentIndex() > -1) { @@ -852,11 +754,8 @@ DecodedBitStreamParser::Decode(const std::vector& codewords, int ecLevel, c sai.id = resultMetadata->fileId(); } - return DecoderResult(ByteArray(), std::move(resultEncoded)) - .setEcLevel(std::to_wstring(ecLevel)) - // As converting character set ECIs ourselves and ignoring/skipping non-character ECIs, not using modifier - // that indicates ECI protocol (ISO/IEC 15438:2015 Annex L Table L.1) - .setSymbologyIdentifier("]L2") + return DecoderResult({}, std::move(result)) + .setEcLevel(std::to_string(ecLevel)) .setStructuredAppend(sai) .setReaderInit(readerInit) .setExtra(resultMetadata); diff --git a/core/src/pdf417/PDFDecodedBitStreamParser.h b/core/src/pdf417/PDFDecodedBitStreamParser.h index 696d118e13..103db7c5b0 100644 --- a/core/src/pdf417/PDFDecodedBitStreamParser.h +++ b/core/src/pdf417/PDFDecodedBitStreamParser.h @@ -1,20 +1,10 @@ -#pragma once /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include #include @@ -34,7 +24,7 @@ namespace Pdf417 { class DecodedBitStreamParser { public: - static DecoderResult Decode(const std::vector& codewords, int ecLevel, const std::string& characterSet); + static DecoderResult Decode(const std::vector& codewords, int ecLevel); }; } // Pdf417 diff --git a/core/src/pdf417/PDFDecoderResultExtra.h b/core/src/pdf417/PDFDecoderResultExtra.h index 01284bd2c4..8aaf60a253 100644 --- a/core/src/pdf417/PDFDecoderResultExtra.h +++ b/core/src/pdf417/PDFDecoderResultExtra.h @@ -1,20 +1,10 @@ -#pragma once /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include "CustomData.h" diff --git a/core/src/pdf417/PDFDetectionResult.cpp b/core/src/pdf417/PDFDetectionResult.cpp index 07d31aa14f..b9f97b305a 100644 --- a/core/src/pdf417/PDFDetectionResult.cpp +++ b/core/src/pdf417/PDFDetectionResult.cpp @@ -1,23 +1,12 @@ /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "PDFDetectionResult.h" #include "PDFCodewordDecoder.h" -#include "ZXContainerAlgorithms.h" +#include "ZXAlgorithms.h" #include #include diff --git a/core/src/pdf417/PDFDetectionResult.h b/core/src/pdf417/PDFDetectionResult.h index 97fb116aa6..b5dedc64d9 100644 --- a/core/src/pdf417/PDFDetectionResult.h +++ b/core/src/pdf417/PDFDetectionResult.h @@ -1,20 +1,10 @@ -#pragma once /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include "PDFBarcodeMetadata.h" #include "PDFBoundingBox.h" diff --git a/core/src/pdf417/PDFDetectionResultColumn.cpp b/core/src/pdf417/PDFDetectionResultColumn.cpp index 18131bcda7..4386746fda 100644 --- a/core/src/pdf417/PDFDetectionResultColumn.cpp +++ b/core/src/pdf417/PDFDetectionResultColumn.cpp @@ -1,24 +1,13 @@ /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "PDFDetectionResultColumn.h" #include "PDFBarcodeMetadata.h" #include "PDFBarcodeValue.h" -#include "ZXContainerAlgorithms.h" +#include "ZXAlgorithms.h" #include #include diff --git a/core/src/pdf417/PDFDetectionResultColumn.h b/core/src/pdf417/PDFDetectionResultColumn.h index 732d8724c4..0df6d7fc73 100644 --- a/core/src/pdf417/PDFDetectionResultColumn.h +++ b/core/src/pdf417/PDFDetectionResultColumn.h @@ -1,20 +1,10 @@ -#pragma once /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include "PDFBoundingBox.h" #include "PDFCodeword.h" diff --git a/core/src/pdf417/PDFDetector.cpp b/core/src/pdf417/PDFDetector.cpp index 5ddf915927..97835f13c5 100644 --- a/core/src/pdf417/PDFDetector.cpp +++ b/core/src/pdf417/PDFDetector.cpp @@ -1,19 +1,8 @@ /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "PDFDetector.h" #include "BinaryBitmap.h" @@ -315,15 +304,16 @@ static std::list, 8>> DetectBarcode(const BitMa } #ifdef ZX_FAST_BIT_STORAGE -bool HasStartPattern(const BitMatrix& m) +bool HasStartPattern(const BitMatrix& m, bool rotate90) { constexpr FixedPattern<8, 17> START_PATTERN = { 8, 1, 1, 1, 1, 1, 1, 3 }; constexpr int minSymbolWidth = 3*8+1; // compact symbol PatternRow row; + int end = rotate90 ? m.width() : m.height(); - for (int r = ROW_STEP; r < m.height(); r += ROW_STEP) { - m.getPatternRow(r, row); + for (int r = ROW_STEP; r < end; r += ROW_STEP) { + m.getPatternRow(r, row, rotate90); if (FindLeftGuard(row, minSymbolWidth, START_PATTERN, 2).isValid()) return true; @@ -340,40 +330,46 @@ bool HasStartPattern(const BitMatrix& m) *

Detects a PDF417 Code in an image. Only checks 0 and 180 degree rotations.

* * @param image barcode image to decode -* @param hints optional hints to detector * @param multiple if true, then the image is searched for multiple codes. If false, then at most one code will * be found and returned -* @return {@link PDF417DetectorResult} encapsulating results of detecting a PDF417 code -* @throws NotFoundException if no PDF417 Code can be found */ -DecodeStatus -Detector::Detect(const BinaryBitmap& image, bool multiple, Result& result) +Detector::Result Detector::Detect(const BinaryBitmap& image, bool multiple, bool tryRotate) { // construct a 'dummy' shared pointer, just be able to pass it up the call chain in DecodeStatus // TODO: reimplement PDF Detector auto binImg = std::shared_ptr(image.getBitMatrix(), [](const BitMatrix*){}); - if (!binImg) { - return DecodeStatus::NotFound; - } + if (!binImg) + return {}; + + Result result; + for (int rotate90 = false; rotate90 <= tryRotate && result.points.empty(); ++rotate90) { #if defined(ZX_FAST_BIT_STORAGE) - if (!HasStartPattern(*binImg)) - return DecodeStatus::NotFound; + if (!HasStartPattern(*binImg, rotate90)) + continue; #endif + result.rotation = 90 * rotate90; + if (rotate90) { + auto newBits = std::make_shared(binImg->copy()); + newBits->rotate90(); + binImg = newBits; + } - auto barcodeCoordinates = DetectBarcode(*binImg, multiple); - if (barcodeCoordinates.empty()) { - auto newBits = std::make_shared(binImg->copy()); - newBits->rotate180(); - binImg = newBits; - barcodeCoordinates = DetectBarcode(*binImg, multiple); - } - if (barcodeCoordinates.empty()) { - return DecodeStatus::NotFound; + result.points = DetectBarcode(*binImg, multiple); + if (result.points.empty()) { + auto newBits = std::make_shared(binImg->copy()); + newBits->rotate180(); + binImg = newBits; + result.points = DetectBarcode(*binImg, multiple); + result.rotation += 180; + } } - result.points = barcodeCoordinates; + + if (result.points.empty()) + return {}; + result.bits = binImg; - return DecodeStatus::NoError; + return result; } } // Pdf417 diff --git a/core/src/pdf417/PDFDetector.h b/core/src/pdf417/PDFDetector.h index ce8fbff464..1316c0a52c 100644 --- a/core/src/pdf417/PDFDetector.h +++ b/core/src/pdf417/PDFDetector.h @@ -1,20 +1,10 @@ -#pragma once /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include "ResultPoint.h" #include "ZXNullable.h" @@ -27,7 +17,6 @@ namespace ZXing { class BitMatrix; class BinaryBitmap; -enum class DecodeStatus; namespace Pdf417 { @@ -46,9 +35,10 @@ class Detector { std::shared_ptr bits; std::list, 8>> points; + int rotation; }; - static DecodeStatus Detect(const BinaryBitmap& image, bool multiple, Result& result); + static Result Detect(const BinaryBitmap& image, bool multiple, bool tryRotate); }; } // Pdf417 diff --git a/core/src/pdf417/PDFEncoder.cpp b/core/src/pdf417/PDFEncoder.cpp index c38a35ce2f..e53daeea7c 100644 --- a/core/src/pdf417/PDFEncoder.cpp +++ b/core/src/pdf417/PDFEncoder.cpp @@ -2,19 +2,8 @@ * Copyright 2016 Huy Cuong Nguyen * Copyright 2016 ZXing authors * Copyright 2006 Jeremias Maerki -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "PDFEncoder.h" #include "PDFHighLevelEncoder.h" diff --git a/core/src/pdf417/PDFEncoder.h b/core/src/pdf417/PDFEncoder.h index 459a8634c0..3f086dfd0d 100644 --- a/core/src/pdf417/PDFEncoder.h +++ b/core/src/pdf417/PDFEncoder.h @@ -1,23 +1,13 @@ -#pragma once /* * Copyright 2016 Huy Cuong Nguyen * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include "CharacterSet.h" #include "PDFCompaction.h" -#include "ZXContainerAlgorithms.h" +#include "ZXAlgorithms.h" #include #include diff --git a/core/src/pdf417/PDFHighLevelEncoder.cpp b/core/src/pdf417/PDFHighLevelEncoder.cpp index c37b41c11b..07f08b4421 100644 --- a/core/src/pdf417/PDFHighLevelEncoder.cpp +++ b/core/src/pdf417/PDFHighLevelEncoder.cpp @@ -2,27 +2,16 @@ * Copyright 2016 Huy Cuong Nguyen * Copyright 2016 ZXing authors * Copyright 2006 Jeremias Maerki in part, and ZXing Authors in part -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "PDFHighLevelEncoder.h" #include "PDFCompaction.h" #include "CharacterSet.h" -#include "CharacterSetECI.h" +#include "ECI.h" #include "TextEncoder.h" #include "ZXBigInteger.h" -#include "ZXContainerAlgorithms.h" +#include "ZXAlgorithms.h" #include #include @@ -513,8 +502,8 @@ HighLevelEncoder::EncodeHighLevel(const std::wstring& msg, Compaction compaction highLevel.reserve(highLevel.size() + msg.length()); //the codewords 0..928 are encoded as Unicode characters - if (encoding != CharacterSet::ISO8859_1) { - EncodingECI(CharacterSetECI::ValueForCharset(encoding), highLevel); + if (encoding != CharacterSet::ISO8859_1) { + EncodingECI(ToInt(ToECI(encoding)), highLevel); } int len = Size(msg); diff --git a/core/src/pdf417/PDFHighLevelEncoder.h b/core/src/pdf417/PDFHighLevelEncoder.h index 0df789e0be..e0bbe89d28 100644 --- a/core/src/pdf417/PDFHighLevelEncoder.h +++ b/core/src/pdf417/PDFHighLevelEncoder.h @@ -1,21 +1,11 @@ -#pragma once /* * Copyright 2016 Huy Cuong Nguyen * Copyright 2016 ZXing authors * Copyright 2006 Jeremias Maerki -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include #include diff --git a/core/src/pdf417/PDFModulusGF.cpp b/core/src/pdf417/PDFModulusGF.cpp index eebc090947..3859c1c7e4 100644 --- a/core/src/pdf417/PDFModulusGF.cpp +++ b/core/src/pdf417/PDFModulusGF.cpp @@ -1,19 +1,8 @@ /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "PDFModulusGF.h" #include diff --git a/core/src/pdf417/PDFModulusGF.h b/core/src/pdf417/PDFModulusGF.h index 12095c9491..3ee80bc050 100644 --- a/core/src/pdf417/PDFModulusGF.h +++ b/core/src/pdf417/PDFModulusGF.h @@ -1,20 +1,10 @@ -#pragma once /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include "PDFModulusPoly.h" #include "ZXConfig.h" diff --git a/core/src/pdf417/PDFModulusPoly.cpp b/core/src/pdf417/PDFModulusPoly.cpp index bfd414cb36..9883775f77 100644 --- a/core/src/pdf417/PDFModulusPoly.cpp +++ b/core/src/pdf417/PDFModulusPoly.cpp @@ -1,19 +1,8 @@ /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "PDFModulusPoly.h" #include "PDFModulusGF.h" diff --git a/core/src/pdf417/PDFModulusPoly.h b/core/src/pdf417/PDFModulusPoly.h index ba33405f74..0de1c9132a 100644 --- a/core/src/pdf417/PDFModulusPoly.h +++ b/core/src/pdf417/PDFModulusPoly.h @@ -1,22 +1,12 @@ -#pragma once /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once -#include "ZXContainerAlgorithms.h" +#include "ZXAlgorithms.h" #include #include diff --git a/core/src/pdf417/PDFReader.cpp b/core/src/pdf417/PDFReader.cpp index dadc456117..947b21e95c 100644 --- a/core/src/pdf417/PDFReader.cpp +++ b/core/src/pdf417/PDFReader.cpp @@ -2,19 +2,8 @@ * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors * Copyright 2020 Axel Waggershauser -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "PDFReader.h" #include "PDFDetector.h" @@ -77,32 +66,35 @@ static int GetMaxCodewordWidth(const std::array, 8>& p) std::max(GetMaxWidth(p[1], p[5]), GetMaxWidth(p[7], p[3]) * CodewordDecoder::MODULES_IN_CODEWORD / MODULES_IN_STOP_PATTERN)); } -DecodeStatus DoDecode(const BinaryBitmap& image, bool multiple, std::list& results, - const std::string& characterSet) +static Results DoDecode(const BinaryBitmap& image, bool multiple, bool tryRotate, bool returnErrors) { - Detector::Result detectorResult; - DecodeStatus status = Detector::Detect(image, multiple, detectorResult); - if (StatusIsError(status)) { - return status; - } + Detector::Result detectorResult = Detector::Detect(image, multiple, tryRotate); + if (detectorResult.points.empty()) + return {}; + auto rotate = [res = detectorResult](PointI p) { + switch(res.rotation) { + case 90: return PointI(res.bits->height() - p.y - 1, p.x); + case 180: return PointI(res.bits->width() - p.x - 1, res.bits->height() - p.y - 1); + case 270: return PointI(p.y, res.bits->width() - p.x - 1); + } + return p; + }; + + Results results; for (const auto& points : detectorResult.points) { DecoderResult decoderResult = ScanningDecoder::Decode(*detectorResult.bits, points[4], points[5], points[6], points[7], - GetMinCodewordWidth(points), GetMaxCodewordWidth(points), characterSet); - if (decoderResult.isValid()) { - auto point = [&](int i) { return points[i].value(); }; + GetMinCodewordWidth(points), GetMaxCodewordWidth(points)); + if (decoderResult.isValid(returnErrors)) { + auto point = [&](int i) { return rotate(PointI(points[i].value())); }; Result result(std::move(decoderResult), {point(0), point(2), point(3), point(1)}, BarcodeFormat::PDF417); results.push_back(result); - if (!multiple) { - return DecodeStatus::NoError; - } - } - else if (!multiple) { - return decoderResult.errorCode(); + if (!multiple) + return results; } } - return results.empty() ? DecodeStatus::NotFound : DecodeStatus::NoError; + return results; } // new implementation (only for isPure use case atm.) @@ -266,14 +258,13 @@ std::vector ReadCodeWords(BitMatrixCursor topCur, SymbolInfo info) } // forward declaration from PDFScanningDecoder.cpp -DecoderResult DecodeCodewords(std::vector& codewords, int ecLevel, const std::vector& erasures, - const std::string& characterSet); +DecoderResult DecodeCodewords(std::vector& codewords, int ecLevel, const std::vector& erasures); -static Result DecodePure(const BinaryBitmap& image_, const std::string& characterSet) +static Result DecodePure(const BinaryBitmap& image_) { auto pimage = image_.getBitMatrix(); if (!pimage) - return Result(DecodeStatus::NotFound); + return {}; auto& image = *pimage; #ifdef PRINT_DEBUG @@ -282,7 +273,7 @@ static Result DecodePure(const BinaryBitmap& image_, const std::string& characte int left, top, width, height; if (!image.findBoundingBox(left, top, width, height, 9) || (width < 3 * 17 && height < 3 * 17)) - return Result(DecodeStatus::NotFound); + return {}; int right = left + width - 1; int bottom = top + height - 1; @@ -301,7 +292,7 @@ static Result DecodePure(const BinaryBitmap& image_, const std::string& characte } if (!info) - return Result(DecodeStatus::NotFound); + return {}; auto codeWords = ReadCodeWords(cur, info); @@ -312,45 +303,35 @@ static Result DecodePure(const BinaryBitmap& image_, const std::string& characte erasures.push_back(i); } - auto res = DecodeCodewords(codeWords, info.ecLevel, erasures, characterSet); + auto res = DecodeCodewords(codeWords, info.ecLevel, erasures); return Result(std::move(res), {{left, top}, {right, top}, {right, bottom}, {left, bottom}}, BarcodeFormat::PDF417); } -Reader::Reader(const DecodeHints& hints) : _isPure(hints.isPure()), _characterSet(hints.characterSet()) {} - Result Reader::decode(const BinaryBitmap& image) const { - if (_isPure) { - auto res = DecodePure(image, _characterSet); - if (res.status() != DecodeStatus::ChecksumError) + if (_hints.isPure()) { + auto res = DecodePure(image); + if (res.error() != Error::Checksum) return res; // This falls through and tries the non-pure code path if we have a checksum error. This approach is // currently the best option to deal with 'aliased' input like e.g. 03-aliased.png } - std::list results; - DecodeStatus status = DoDecode(image, false, results, _characterSet); - if (StatusIsOK(status)) { - return results.front(); - } - return Result(status); + return FirstOrDefault(DoDecode(image, false, _hints.tryRotate(), _hints.returnErrors())); } Results Reader::decode(const BinaryBitmap& image, [[maybe_unused]] int maxSymbols) const { - std::list results; - DoDecode(image, true, results, _characterSet); - return Results(results.begin(), results.end()); + return DoDecode(image, true, _hints.tryRotate(), _hints.returnErrors()); } std::list Reader::decodeMultiple(const BinaryBitmap& image) const { - std::list results; - DoDecode(image, true, results, _characterSet); - return results; + Results results = DoDecode(image, true, _hints.tryRotate(), _hints.returnErrors()); + return std::list(results.begin(), results.end()); } } // Pdf417 diff --git a/core/src/pdf417/PDFReader.h b/core/src/pdf417/PDFReader.h index 138d31ef1e..c4d3272ee6 100644 --- a/core/src/pdf417/PDFReader.h +++ b/core/src/pdf417/PDFReader.h @@ -1,31 +1,16 @@ -#pragma once /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include "Reader.h" #include -#include - -namespace ZXing { -class DecodeHints; - -namespace Pdf417 { +namespace ZXing::Pdf417 { /** * This implementation can detect and decode PDF417 codes in an image. @@ -34,11 +19,8 @@ namespace Pdf417 { */ class Reader : public ZXing::Reader { - bool _isPure; - std::string _characterSet; - public: - explicit Reader(const DecodeHints& hints); + using ZXing::Reader::Reader; Result decode(const BinaryBitmap& image) const override; Results decode(const BinaryBitmap& image, int maxSymbols) const override; @@ -46,5 +28,4 @@ class Reader : public ZXing::Reader [[deprecated]] std::list decodeMultiple(const BinaryBitmap& image) const; }; -} // Pdf417 -} // ZXing +} // namespace ZXing::Pdf417 diff --git a/core/src/pdf417/PDFScanningDecoder.cpp b/core/src/pdf417/PDFScanningDecoder.cpp index c95f80a1dc..895404ca1b 100644 --- a/core/src/pdf417/PDFScanningDecoder.cpp +++ b/core/src/pdf417/PDFScanningDecoder.cpp @@ -1,19 +1,8 @@ /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "PDFScanningDecoder.h" #include "PDFBoundingBox.h" @@ -469,8 +458,7 @@ static std::vector FindErrorMagnitudes(const ModulusPoly& errorEvaluator, c * @param received received codewords * @param numECCodewords number of those codewords used for EC * @param erasures location of erasures -* @return number of errors -* @throws ChecksumException if errors cannot be corrected, maybe because of too many errors +* @return false if errors cannot be corrected, maybe because of too many errors */ ZXING_EXPORT_TEST_ONLY bool DecodeErrorCorrection(std::vector& received, int numECCodewords, const std::vector& erasures, int& nbErrors) @@ -538,7 +526,7 @@ bool DecodeErrorCorrection(std::vector& received, int numECCodewords, const * @param codewords data and error correction codewords * @param erasures positions of any known erasures * @param numECCodewords number of error correction codewords that are available in codewords -* @throws ChecksumException if error correction fails +* @return false if error correction fails */ static bool CorrectErrors(std::vector& codewords, const std::vector& erasures, int numECCodewords, int& errorCount) { @@ -580,28 +568,25 @@ static bool VerifyCodewordCount(std::vector& codewords, int numECCodewords) return true; } -DecoderResult DecodeCodewords(std::vector& codewords, int ecLevel, const std::vector& erasures, - const std::string& characterSet) +DecoderResult DecodeCodewords(std::vector& codewords, int ecLevel, const std::vector& erasures) { - if (codewords.empty()) { - return DecodeStatus::FormatError; - } + if (codewords.empty()) + return FormatError(); int numECCodewords = 1 << (ecLevel + 1); int correctedErrorsCount = 0; if (!CorrectErrors(codewords, erasures, numECCodewords, correctedErrorsCount)) - return DecodeStatus::ChecksumError; + return ChecksumError(); if (!VerifyCodewordCount(codewords, numECCodewords)) - return DecodeStatus::FormatError; + return FormatError(); // Decode the codewords - auto result = DecodedBitStreamParser::Decode(codewords, ecLevel, characterSet); - if (result.isValid()) { - result.setErrorsCorrected(correctedErrorsCount); - result.setErasures(Size(erasures)); + try { + return DecodedBitStreamParser::Decode(codewords, ecLevel); + } catch (Error e) { + return e; } - return result; } @@ -620,7 +605,7 @@ DecoderResult DecodeCodewords(std::vector& codewords, int ecLevel, const st */ static DecoderResult CreateDecoderResultFromAmbiguousValues(int ecLevel, std::vector& codewords, const std::vector& erasureArray, const std::vector& ambiguousIndexes, - const std::vector>& ambiguousIndexValues, const std::string& characterSet) + const std::vector>& ambiguousIndexValues) { std::vector ambiguousIndexCount(ambiguousIndexes.size(), 0); @@ -629,13 +614,13 @@ static DecoderResult CreateDecoderResultFromAmbiguousValues(int ecLevel, std::ve for (size_t i = 0; i < ambiguousIndexCount.size(); i++) { codewords[ambiguousIndexes[i]] = ambiguousIndexValues[i][ambiguousIndexCount[i]]; } - auto result = DecodeCodewords(codewords, ecLevel, erasureArray, characterSet); - if (result.errorCode() != DecodeStatus::ChecksumError) { + auto result = DecodeCodewords(codewords, ecLevel, erasureArray); + if (result.error() != Error::Checksum) { return result; } if (ambiguousIndexCount.empty()) { - return DecodeStatus::ChecksumError; + return ChecksumError(); } for (size_t i = 0; i < ambiguousIndexCount.size(); i++) { if (ambiguousIndexCount[i] < Size(ambiguousIndexValues[i]) - 1) { @@ -645,20 +630,20 @@ static DecoderResult CreateDecoderResultFromAmbiguousValues(int ecLevel, std::ve else { ambiguousIndexCount[i] = 0; if (i == ambiguousIndexCount.size() - 1) { - return DecodeStatus::ChecksumError; + return ChecksumError(); } } } } - return DecodeStatus::ChecksumError; + return ChecksumError(); } -static DecoderResult CreateDecoderResult(DetectionResult& detectionResult, const std::string& characterSet) +static DecoderResult CreateDecoderResult(DetectionResult& detectionResult) { auto barcodeMatrix = CreateBarcodeMatrix(detectionResult); if (!AdjustCodewordCount(detectionResult, barcodeMatrix)) { - return DecodeStatus::NotFound; + return {}; } std::vector erasures; std::vector codewords(detectionResult.barcodeRowCount() * detectionResult.barcodeColumnCount(), 0); @@ -681,7 +666,7 @@ static DecoderResult CreateDecoderResult(DetectionResult& detectionResult, const } } return CreateDecoderResultFromAmbiguousValues(detectionResult.barcodeECLevel(), codewords, erasures, - ambiguousIndexesList, ambiguousIndexValues, characterSet); + ambiguousIndexesList, ambiguousIndexValues); } @@ -692,11 +677,11 @@ static DecoderResult CreateDecoderResult(DetectionResult& detectionResult, const DecoderResult ScanningDecoder::Decode(const BitMatrix& image, const Nullable& imageTopLeft, const Nullable& imageBottomLeft, const Nullable& imageTopRight, const Nullable& imageBottomRight, - int minCodewordWidth, int maxCodewordWidth, const std::string& characterSet) + int minCodewordWidth, int maxCodewordWidth) { BoundingBox boundingBox; if (!BoundingBox::Create(image.width(), image.height(), imageTopLeft, imageBottomLeft, imageTopRight, imageBottomRight, boundingBox)) { - return DecodeStatus::NotFound; + return {}; } Nullable leftRowIndicatorColumn, rightRowIndicatorColumn; @@ -709,7 +694,7 @@ ScanningDecoder::Decode(const BitMatrix& image, const Nullable& ima rightRowIndicatorColumn = GetRowIndicatorColumn(image, boundingBox, imageTopRight, false, minCodewordWidth, maxCodewordWidth); } if (!Merge(leftRowIndicatorColumn, rightRowIndicatorColumn, detectionResult)) { - return DecodeStatus::NotFound; + return {}; } if (i == 0 && detectionResult.getBoundingBox() != nullptr && (detectionResult.getBoundingBox().value().minY() < boundingBox.minY() || detectionResult.getBoundingBox().value().maxY() > boundingBox.maxY())) { boundingBox = detectionResult.getBoundingBox(); @@ -753,7 +738,7 @@ ScanningDecoder::Decode(const BitMatrix& image, const Nullable& ima } } } - return CreateDecoderResult(detectionResult, characterSet); + return CreateDecoderResult(detectionResult); } } // Pdf417 diff --git a/core/src/pdf417/PDFScanningDecoder.h b/core/src/pdf417/PDFScanningDecoder.h index 7ff7248121..2c34aea07c 100644 --- a/core/src/pdf417/PDFScanningDecoder.h +++ b/core/src/pdf417/PDFScanningDecoder.h @@ -1,20 +1,10 @@ -#pragma once /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include @@ -36,7 +26,7 @@ class ScanningDecoder static DecoderResult Decode(const BitMatrix& image, const Nullable& imageTopLeft, const Nullable& imageBottomLeft, const Nullable& imageTopRight, const Nullable& imageBottomRight, - int minCodewordWidth, int maxCodewordWidth, const std::string& characterSet); + int minCodewordWidth, int maxCodewordWidth); }; } // Pdf417 diff --git a/core/src/pdf417/PDFWriter.cpp b/core/src/pdf417/PDFWriter.cpp index 60d8206bea..400208eb50 100644 --- a/core/src/pdf417/PDFWriter.cpp +++ b/core/src/pdf417/PDFWriter.cpp @@ -1,23 +1,13 @@ /* * Copyright 2016 Huy Cuong Nguyen * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "PDFWriter.h" #include "PDFEncoder.h" #include "BitMatrix.h" +#include "TextUtfEncoding.h" #include @@ -122,6 +112,11 @@ Writer::encode(const std::wstring& contents, int width, int height) const } } +BitMatrix Writer::encode(const std::string& contents, int width, int height) const +{ + return encode(TextUtfEncoding::FromUtf8(contents), width, height); +} + Writer::Writer() { _encoder.reset(new Encoder); diff --git a/core/src/pdf417/PDFWriter.h b/core/src/pdf417/PDFWriter.h index dad8e360aa..b9bf3c3606 100644 --- a/core/src/pdf417/PDFWriter.h +++ b/core/src/pdf417/PDFWriter.h @@ -1,20 +1,10 @@ -#pragma once /* * Copyright 2016 Huy Cuong Nguyen * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include #include @@ -70,6 +60,7 @@ class Writer BitMatrix encode(const std::wstring& contents, int width, int height) const; + BitMatrix encode(const std::string& contents, int width, int height) const; private: int _margin = -1; diff --git a/core/src/qrcode/QRBitMatrixParser.cpp b/core/src/qrcode/QRBitMatrixParser.cpp index ab599a7b67..7cdb3e7529 100644 --- a/core/src/qrcode/QRBitMatrixParser.cpp +++ b/core/src/qrcode/QRBitMatrixParser.cpp @@ -1,19 +1,8 @@ /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "QRBitMatrixParser.h" @@ -28,27 +17,32 @@ namespace ZXing::QRCode { -static bool getBit(const BitMatrix& bitMatrix, int x, int y, bool mirrored) +static bool getBit(const BitMatrix& bitMatrix, int x, int y, bool mirrored = false) { return mirrored ? bitMatrix.get(y, x) : bitMatrix.get(x, y); } -static bool hasValidDimension(const BitMatrix& bitMatrix) +static bool hasValidDimension(const BitMatrix& bitMatrix, bool isMicro) { int dimension = bitMatrix.height(); - return dimension >= 21 && dimension <= 177 && (dimension % 4) == 1; + if (isMicro) + return dimension >= 11 && dimension <= 17 && (dimension % 2) == 1; + else + return dimension >= 21 && dimension <= 177 && (dimension % 4) == 1; } const Version* ReadVersion(const BitMatrix& bitMatrix) { - if (!hasValidDimension(bitMatrix)) + int dimension = bitMatrix.height(); + bool isMicro = dimension < 21; + + if (!hasValidDimension(bitMatrix, isMicro)) return nullptr; - int dimension = bitMatrix.height(); + int provisionalVersion = (dimension - Version::DimensionOffset(isMicro)) / Version::DimensionStep(isMicro); - int provisionalVersion = (dimension - 17) / 4; if (provisionalVersion <= 6) - return Version::VersionForNumber(provisionalVersion); + return Version::VersionForNumber(provisionalVersion, isMicro); for (bool mirror : {false, true}) { // Read top-right/bottom-left version info: 3 wide by 6 tall (depending on mirrored) @@ -66,39 +60,47 @@ const Version* ReadVersion(const BitMatrix& bitMatrix) return nullptr; } -FormatInformation ReadFormatInformation(const BitMatrix& bitMatrix, bool mirrored) +FormatInformation ReadFormatInformation(const BitMatrix& bitMatrix, bool isMicro) { - if (!hasValidDimension(bitMatrix)) + if (!hasValidDimension(bitMatrix, isMicro)) return {}; + if (isMicro) { + // Read top-left format info bits + int formatInfoBits = 0; + for (int x = 1; x < 9; x++) + AppendBit(formatInfoBits, getBit(bitMatrix, x, 8)); + for (int y = 7; y >= 1; y--) + AppendBit(formatInfoBits, getBit(bitMatrix, 8, y)); + + return FormatInformation::DecodeMQR(formatInfoBits); + } + // Read top-left format info bits int formatInfoBits1 = 0; for (int x = 0; x < 6; x++) - AppendBit(formatInfoBits1, getBit(bitMatrix, x, 8, mirrored)); + AppendBit(formatInfoBits1, getBit(bitMatrix, x, 8)); // .. and skip a bit in the timing pattern ... - AppendBit(formatInfoBits1, getBit(bitMatrix, 7, 8, mirrored)); - AppendBit(formatInfoBits1, getBit(bitMatrix, 8, 8, mirrored)); - AppendBit(formatInfoBits1, getBit(bitMatrix, 8, 7, mirrored)); + AppendBit(formatInfoBits1, getBit(bitMatrix, 7, 8)); + AppendBit(formatInfoBits1, getBit(bitMatrix, 8, 8)); + AppendBit(formatInfoBits1, getBit(bitMatrix, 8, 7)); // .. and skip a bit in the timing pattern ... for (int y = 5; y >= 0; y--) - AppendBit(formatInfoBits1, getBit(bitMatrix, 8, y, mirrored)); + AppendBit(formatInfoBits1, getBit(bitMatrix, 8, y)); // Read the top-right/bottom-left pattern too int dimension = bitMatrix.height(); int formatInfoBits2 = 0; for (int y = dimension - 1; y >= dimension - 7; y--) - AppendBit(formatInfoBits2, getBit(bitMatrix, 8, y, mirrored)); + AppendBit(formatInfoBits2, getBit(bitMatrix, 8, y)); for (int x = dimension - 8; x < dimension; x++) - AppendBit(formatInfoBits2, getBit(bitMatrix, x, 8, mirrored)); + AppendBit(formatInfoBits2, getBit(bitMatrix, x, 8)); - return FormatInformation::DecodeFormatInformation(formatInfoBits1, formatInfoBits2); + return FormatInformation::DecodeQR(formatInfoBits1, formatInfoBits2); } -ByteArray ReadCodewords(const BitMatrix& bitMatrix, const Version& version, int maskIndex, bool mirrored) +static ByteArray ReadQRCodewords(const BitMatrix& bitMatrix, const Version& version, const FormatInformation& formatInfo) { - if (!hasValidDimension(bitMatrix)) - return {}; - BitMatrix functionPattern = version.buildFunctionPattern(); ByteArray result; @@ -120,7 +122,8 @@ ByteArray ReadCodewords(const BitMatrix& bitMatrix, const Version& version, int // Ignore bits covered by the function pattern if (!functionPattern.get(xx, y)) { // Read a bit - AppendBit(currentByte, GetDataMaskBit(maskIndex, xx, y) != getBit(bitMatrix, xx, y, mirrored)); + AppendBit(currentByte, + GetDataMaskBit(formatInfo.dataMask, xx, y) != getBit(bitMatrix, xx, y, formatInfo.isMirrored)); // If we've made a whole byte, save it off if (++bitsRead % 8 == 0) result.push_back(std::exchange(currentByte, 0)); @@ -135,4 +138,59 @@ ByteArray ReadCodewords(const BitMatrix& bitMatrix, const Version& version, int return result; } +static ByteArray ReadMQRCodewords(const BitMatrix& bitMatrix, const QRCode::Version& version, const FormatInformation& formatInfo) +{ + BitMatrix functionPattern = version.buildFunctionPattern(); + + // D3 in a Version M1 symbol, D11 in a Version M3-L symbol and D9 + // in a Version M3-M symbol is a 2x2 square 4-module block. + // See ISO 18004:2006 6.7.3. + bool hasD4mBlock = version.versionNumber() % 2 == 1; + int d4mBlockIndex = + version.versionNumber() == 1 ? 3 : (formatInfo.ecLevel == QRCode::ErrorCorrectionLevel::Low ? 11 : 9); + + ByteArray result; + result.reserve(version.totalCodewords()); + uint8_t currentByte = 0; + bool readingUp = true; + int bitsRead = 0; + int dimension = bitMatrix.height(); + // Read columns in pairs, from right to left + for (int x = dimension - 1; x > 0; x -= 2) { + // Read alternatingly from bottom to top then top to bottom + for (int row = 0; row < dimension; row++) { + int y = readingUp ? dimension - 1 - row : row; + for (int col = 0; col < 2; col++) { + int xx = x - col; + // Ignore bits covered by the function pattern + if (!functionPattern.get(xx, y)) { + // Read a bit + AppendBit(currentByte, + GetDataMaskBit(formatInfo.dataMask, xx, y, true) != getBit(bitMatrix, xx, y, formatInfo.isMirrored)); + ++bitsRead; + // If we've made a whole byte, save it off; save early if 2x2 data block. + if (bitsRead == 8 || (bitsRead == 4 && hasD4mBlock && Size(result) == d4mBlockIndex - 1)) { + result.push_back(std::exchange(currentByte, 0)); + bitsRead = 0; + } + } + } + } + readingUp = !readingUp; // switch directions + } + if (Size(result) != version.totalCodewords()) + return {}; + + return result; +} + +ByteArray ReadCodewords(const BitMatrix& bitMatrix, const Version& version, const FormatInformation& formatInfo) +{ + if (!hasValidDimension(bitMatrix, version.isMicroQRCode())) + return {}; + + return version.isMicroQRCode() ? ReadMQRCodewords(bitMatrix, version, formatInfo) + : ReadQRCodewords(bitMatrix, version, formatInfo); +} + } // namespace ZXing::QRCode diff --git a/core/src/qrcode/QRBitMatrixParser.h b/core/src/qrcode/QRBitMatrixParser.h index 3f0a9d9900..0f070c8403 100644 --- a/core/src/qrcode/QRBitMatrixParser.h +++ b/core/src/qrcode/QRBitMatrixParser.h @@ -1,20 +1,10 @@ -#pragma once /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once namespace ZXing { @@ -37,13 +27,13 @@ const Version* ReadVersion(const BitMatrix& bitMatrix); * @return {@link FormatInformation} encapsulating the QR Code's format info, result is invalid if both format * information locations cannot be parsed as the valid encoding of format information */ -FormatInformation ReadFormatInformation(const BitMatrix& bitMatrix, bool mirrored); +FormatInformation ReadFormatInformation(const BitMatrix& bitMatrix, bool isMicro); /** * @brief Reads the codewords from the BitMatrix. * @return bytes encoded within the QR Code or empty array if the exact number of bytes expected is not read */ -ByteArray ReadCodewords(const BitMatrix& bitMatrix, const Version& version, int maskIndex, bool mirrored); +ByteArray ReadCodewords(const BitMatrix& bitMatrix, const Version& version, const FormatInformation& formatInfo); } // QRCode } // ZXing diff --git a/core/src/qrcode/QRCodecMode.cpp b/core/src/qrcode/QRCodecMode.cpp index a64e6bd9c6..9d018d64bd 100644 --- a/core/src/qrcode/QRCodecMode.cpp +++ b/core/src/qrcode/QRCodecMode.cpp @@ -1,33 +1,29 @@ /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "QRCodecMode.h" #include "QRVersion.h" +#include "ZXAlgorithms.h" #include #include namespace ZXing::QRCode { -CodecMode CodecModeForBits(int bits) +CodecMode CodecModeForBits(int bits, bool isMirco) { - if ((bits >= 0x00 && bits <= 0x05) || (bits >= 0x07 && bits <= 0x09) || bits == 0x0d) - return static_cast(bits); + if (!isMirco) { + if ((bits >= 0x00 && bits <= 0x05) || (bits >= 0x07 && bits <= 0x09) || bits == 0x0d) + return static_cast(bits); + } else { + constexpr CodecMode Bits2Mode[4] = {CodecMode::NUMERIC, CodecMode::ALPHANUMERIC, CodecMode::BYTE, CodecMode::KANJI}; + if (bits < Size(Bits2Mode)) + return Bits2Mode[bits]; + } throw std::invalid_argument("Invalid mode"); } @@ -35,6 +31,17 @@ CodecMode CodecModeForBits(int bits) int CharacterCountBits(CodecMode mode, const Version& version) { int number = version.versionNumber(); + if (version.isMicroQRCode()) { + switch (mode) { + case CodecMode::NUMERIC: return std::array{3, 4, 5, 6}[number - 1]; + case CodecMode::ALPHANUMERIC: return std::array{3, 4, 5}[number - 2]; + case CodecMode::BYTE: return std::array{4, 5}[number - 3]; + case CodecMode::KANJI: [[fallthrough]]; + case CodecMode::HANZI: return std::array{3, 4}[number - 3]; + default: return 0; + } + } + int i; if (number <= 9) i = 0; @@ -53,4 +60,14 @@ int CharacterCountBits(CodecMode mode, const Version& version) } } +int CodecModeBitsLength(const Version& version) +{ + return version.isMicroQRCode() ? version.versionNumber() - 1 : 4; +} + +int TerminatorBitsLength(const Version& version) +{ + return version.isMicroQRCode() ? version.versionNumber() * 2 + 1 : 4; +} + } // namespace ZXing::QRCode diff --git a/core/src/qrcode/QRCodecMode.h b/core/src/qrcode/QRCodecMode.h index 066c143fd4..830b2f897a 100644 --- a/core/src/qrcode/QRCodecMode.h +++ b/core/src/qrcode/QRCodecMode.h @@ -1,20 +1,10 @@ -#pragma once /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once namespace ZXing { namespace QRCode { @@ -40,11 +30,12 @@ enum class CodecMode }; /** - * @param bits four bits encoding a QR Code data mode + * @param bits variable number of bits encoding a QR Code data mode + * @param isMicro is this a MicroQRCode * @return Mode encoded by these bits - * @throws IllegalArgumentException if bits do not correspond to a known mode + * @throws std::invalid_argument if bits do not correspond to a known mode */ -CodecMode CodecModeForBits(int bits); +CodecMode CodecModeForBits(int bits, bool isMirco = false); /** * @param version version in question @@ -53,5 +44,17 @@ CodecMode CodecModeForBits(int bits); */ int CharacterCountBits(CodecMode mode, const Version& version); +/** + * @param version version in question + * @return number of bits used to encode a codec mode. + */ +int CodecModeBitsLength(const Version& version); + +/** + * @param version version in question + * @return number of bits in the Terminator code. + */ +int TerminatorBitsLength(const Version& version); + } // QRCode } // ZXing diff --git a/core/src/qrcode/QRDataBlock.cpp b/core/src/qrcode/QRDataBlock.cpp index 7c04f5e760..cedd8a303a 100644 --- a/core/src/qrcode/QRDataBlock.cpp +++ b/core/src/qrcode/QRDataBlock.cpp @@ -1,25 +1,14 @@ /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "QRDataBlock.h" #include "QRErrorCorrectionLevel.h" #include "QRVersion.h" -#include "ZXContainerAlgorithms.h" +#include "ZXAlgorithms.h" namespace ZXing::QRCode { @@ -34,6 +23,8 @@ std::vector DataBlock::GetDataBlocks(const ByteArray& rawCodewords, c // First count the total number of data blocks int totalBlocks = ecBlocks.numBlocks(); + if (totalBlocks == 0) + return {}; std::vector result(totalBlocks); // Now establish DataBlocks of the appropriate size and number of data codewords diff --git a/core/src/qrcode/QRDataBlock.h b/core/src/qrcode/QRDataBlock.h index 73df72b5b5..d5f9858785 100644 --- a/core/src/qrcode/QRDataBlock.h +++ b/core/src/qrcode/QRDataBlock.h @@ -1,20 +1,10 @@ -#pragma once /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include "ByteArray.h" @@ -36,17 +26,11 @@ enum class ErrorCorrectionLevel; class DataBlock { public: - int numDataCodewords() const { - return _numDataCodewords; - } + int numDataCodewords() const { return _numDataCodewords; } - const ByteArray& codewords() const { - return _codewords; - } + const ByteArray& codewords() const { return _codewords; } - ByteArray& codewords() { - return _codewords; - } + ByteArray& codewords() { return _codewords; } /** *

When QR Codes use multiple data blocks, they are actually interleaved. diff --git a/core/src/qrcode/QRDataMask.h b/core/src/qrcode/QRDataMask.h index 50045cda3a..b735baf9ec 100644 --- a/core/src/qrcode/QRDataMask.h +++ b/core/src/qrcode/QRDataMask.h @@ -1,37 +1,34 @@ -#pragma once /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include "BitMatrix.h" +#include #include namespace ZXing { namespace QRCode { /** -*

Encapsulates data masks for the data bits in a QR code, per ISO 18004:2006 6.8.

+*

Encapsulates data masks for the data bits in a QR and micro QR code, per ISO 18004:2006 6.8.

* *

Note that the diagram in section 6.8.1 is misleading since it indicates that i is column position * and j is row position. In fact, as the text says, i is row position and j is column position.

*/ -inline bool GetDataMaskBit(int maskIndex, int x, int y) +inline bool GetDataMaskBit(int maskIndex, int x, int y, bool isMicro = false) { + if (isMicro) { + if (maskIndex < 0 || maskIndex >= 4) + throw std::invalid_argument("QRCode maskIndex out of range"); + maskIndex = std::array{1, 4, 6, 7}[maskIndex]; // map from MQR to QR indices + } + switch (maskIndex) { case 0: return (y + x) % 2 == 0; case 1: return y % 2 == 0; @@ -42,12 +39,13 @@ inline bool GetDataMaskBit(int maskIndex, int x, int y) case 6: return ((y * x) % 6) < 3; case 7: return (y + x + ((y * x) % 3)) % 2 == 0; } + throw std::invalid_argument("QRCode maskIndex out of range"); } -inline bool GetMaskedBit(const BitMatrix& bits, int x, int y, int maskIndex) +inline bool GetMaskedBit(const BitMatrix& bits, int x, int y, int maskIndex, bool isMicro = false) { - return GetDataMaskBit(maskIndex, x, y) != bits.get(x, y); + return GetDataMaskBit(maskIndex, x, y, isMicro) != bits.get(x, y); } } // QRCode diff --git a/core/src/qrcode/QRDecoder.cpp b/core/src/qrcode/QRDecoder.cpp index cc0899d7c7..abe44ba8c5 100644 --- a/core/src/qrcode/QRDecoder.cpp +++ b/core/src/qrcode/QRDecoder.cpp @@ -1,26 +1,14 @@ /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "QRDecoder.h" #include "BitMatrix.h" #include "BitSource.h" #include "CharacterSet.h" -#include "CharacterSetECI.h" #include "DecodeStatus.h" #include "DecoderResult.h" #include "GenericGF.h" @@ -28,10 +16,11 @@ #include "QRCodecMode.h" #include "QRDataBlock.h" #include "QRFormatInformation.h" +#include "QRVersion.h" #include "ReedSolomonDecoder.h" #include "StructuredAppend.h" #include "TextDecoder.h" -#include "ZXContainerAlgorithms.h" +#include "ZXAlgorithms.h" #include "ZXTestSupport.h" #include @@ -47,10 +36,9 @@ namespace ZXing::QRCode { * * @param codewordBytes data and error correction codewords * @param numDataCodewords number of codewords that are data bytes -* @throws ChecksumException if error correction fails +* @return false if error correction fails */ -static bool -CorrectErrors(ByteArray& codewordBytes, int numDataCodewords) +static bool CorrectErrors(ByteArray& codewordBytes, int numDataCodewords) { // First read into an array of ints std::vector codewordsInts(codewordBytes.begin(), codewordBytes.end()); @@ -69,18 +57,13 @@ CorrectErrors(ByteArray& codewordBytes, int numDataCodewords) /** * See specification GBT 18284-2000 */ -static DecodeStatus -DecodeHanziSegment(BitSource& bits, int count, std::wstring& result) +static void DecodeHanziSegment(BitSource& bits, int count, Content& result) { - // Don't crash trying to read more bits than we have available. - if (count * 13 > bits.available()) { - return DecodeStatus::FormatError; - } + // Each character will require 2 bytes, decode as GB2312 + // There is no ECI value for GB2312, use GB18030 which is a superset + result.switchEncoding(CharacterSet::GB18030); + result.reserve(2 * count); - // Each character will require 2 bytes. Read the characters as 2-byte pairs - // and decode as GB2312 afterwards - ByteArray buffer; - buffer.reserve(2 * count); while (count > 0) { // Each 13 bits encodes a 2-byte character int twoBytes = bits.readBits(13); @@ -88,32 +71,23 @@ DecodeHanziSegment(BitSource& bits, int count, std::wstring& result) if (assembledTwoBytes < 0x00A00) { // In the 0xA1A1 to 0xAAFE range assembledTwoBytes += 0x0A1A1; - } - else { + } else { // In the 0xB0A1 to 0xFAFE range assembledTwoBytes += 0x0A6A1; } - buffer.push_back(static_cast((assembledTwoBytes >> 8) & 0xFF)); - buffer.push_back(static_cast(assembledTwoBytes & 0xFF)); + result += narrow_cast((assembledTwoBytes >> 8) & 0xFF); + result += narrow_cast(assembledTwoBytes & 0xFF); count--; } - - TextDecoder::Append(result, buffer.data(), Size(buffer), CharacterSet::GB2312); - return DecodeStatus::NoError; } -static DecodeStatus -DecodeKanjiSegment(BitSource& bits, int count, std::wstring& result) +static void DecodeKanjiSegment(BitSource& bits, int count, Content& result) { - // Don't crash trying to read more bits than we have available. - if (count * 13 > bits.available()) { - return DecodeStatus::FormatError; - } - // Each character will require 2 bytes. Read the characters as 2-byte pairs // and decode as Shift_JIS afterwards - ByteArray buffer; - buffer.reserve(2 * count); + result.switchEncoding(CharacterSet::Shift_JIS); + result.reserve(2 * count); + while (count > 0) { // Each 13 bits encodes a 2-byte character int twoBytes = bits.readBits(13); @@ -121,53 +95,26 @@ DecodeKanjiSegment(BitSource& bits, int count, std::wstring& result) if (assembledTwoBytes < 0x01F00) { // In the 0x8140 to 0x9FFC range assembledTwoBytes += 0x08140; - } - else { + } else { // In the 0xE040 to 0xEBBF range assembledTwoBytes += 0x0C140; } - buffer.push_back(static_cast(assembledTwoBytes >> 8)); - buffer.push_back(static_cast(assembledTwoBytes)); + result += narrow_cast(assembledTwoBytes >> 8); + result += narrow_cast(assembledTwoBytes); count--; } - - TextDecoder::Append(result, buffer.data(), Size(buffer), CharacterSet::Shift_JIS); - return DecodeStatus::NoError; } -static DecodeStatus -DecodeByteSegment(BitSource& bits, int count, CharacterSet currentCharset, const std::string& hintedCharset, std::wstring& result) +static void DecodeByteSegment(BitSource& bits, int count, Content& result) { - // Don't crash trying to read more bits than we have available. - if (8 * count > bits.available()) { - return DecodeStatus::FormatError; - } + result.switchEncoding(CharacterSet::Unknown); + result.reserve(count); - ByteArray readBytes(count); - for (int i = 0; i < count; i++) { - readBytes[i] = static_cast(bits.readBits(8)); - } - if (currentCharset == CharacterSet::Unknown) { - // The spec isn't clear on this mode; see - // section 6.4.5: t does not say which encoding to assuming - // upon decoding. I have seen ISO-8859-1 used as well as - // Shift_JIS -- without anything like an ECI designator to - // give a hint. - if (!hintedCharset.empty()) - { - currentCharset = CharacterSetECI::CharsetFromName(hintedCharset.c_str()); - } - if (currentCharset == CharacterSet::Unknown) - { - currentCharset = TextDecoder::GuessEncoding(readBytes.data(), Size(readBytes)); - } - } - TextDecoder::Append(result, readBytes.data(), Size(readBytes), currentCharset); - return DecodeStatus::NoError; + for (int i = 0; i < count; i++) + result += narrow_cast(bits.readBits(8)); } -static char -ToAlphaNumericChar(int value) +static char ToAlphaNumericChar(int value) { /** * See ISO 18004:2006, 6.4.4 Table 5 @@ -179,21 +126,17 @@ ToAlphaNumericChar(int value) ' ', '$', '%', '*', '+', '-', '.', '/', ':' }; - if (value < 0 || value >= Size(ALPHANUMERIC_CHARS)) { + if (value < 0 || value >= Size(ALPHANUMERIC_CHARS)) throw std::out_of_range("ToAlphaNumericChar: out of range"); - } + return ALPHANUMERIC_CHARS[value]; } -static DecodeStatus -DecodeAlphanumericSegment(BitSource& bits, int count, bool fc1InEffect, std::wstring& result) +static void DecodeAlphanumericSegment(BitSource& bits, int count, Content& result) { // Read two characters at a time std::string buffer; while (count > 1) { - if (bits.available() < 11) { - return DecodeStatus::FormatError; - } int nextTwoCharsBits = bits.readBits(11); buffer += ToAlphaNumericChar(nextTwoCharsBits / 45); buffer += ToAlphaNumericChar(nextTwoCharsBits % 45); @@ -201,100 +144,106 @@ DecodeAlphanumericSegment(BitSource& bits, int count, bool fc1InEffect, std::wst } if (count == 1) { // special case: one character left - if (bits.available() < 6) { - return DecodeStatus::FormatError; - } buffer += ToAlphaNumericChar(bits.readBits(6)); } // See section 6.4.8.1, 6.4.8.2 - if (fc1InEffect) { + if (!result.applicationIndicator.empty()) { // We need to massage the result a bit if in an FNC1 mode: for (size_t i = 0; i < buffer.length(); i++) { if (buffer[i] == '%') { if (i < buffer.length() - 1 && buffer[i + 1] == '%') { // %% is rendered as % buffer.erase(i + 1); - } - else { + } else { // In alpha mode, % should be converted to FNC1 separator 0x1D buffer[i] = static_cast(0x1D); } } } } - TextDecoder::AppendLatin1(result, buffer); - return DecodeStatus::NoError; + + result.switchEncoding(CharacterSet::ISO8859_1); + result += buffer; } -static DecodeStatus -DecodeNumericSegment(BitSource& bits, int count, std::wstring& result) +static void DecodeNumericSegment(BitSource& bits, int count, Content& result) { + result.switchEncoding(CharacterSet::ISO8859_1); + result.reserve(count); + // Read three digits at a time - std::string buffer; while (count >= 3) { // Each 10 bits encodes three digits - if (bits.available() < 10) { - return DecodeStatus::FormatError; - } int threeDigitsBits = bits.readBits(10); - if (threeDigitsBits >= 1000) { - return DecodeStatus::FormatError; - } - buffer += ToAlphaNumericChar(threeDigitsBits / 100); - buffer += ToAlphaNumericChar((threeDigitsBits / 10) % 10); - buffer += ToAlphaNumericChar(threeDigitsBits % 10); + if (threeDigitsBits >= 1000) + throw FormatError("Invalid value in numeric segment"); + + result += ToAlphaNumericChar(threeDigitsBits / 100); + result += ToAlphaNumericChar((threeDigitsBits / 10) % 10); + result += ToAlphaNumericChar(threeDigitsBits % 10); count -= 3; } + if (count == 2) { // Two digits left over to read, encoded in 7 bits - if (bits.available() < 7) { - return DecodeStatus::FormatError; - } int twoDigitsBits = bits.readBits(7); - if (twoDigitsBits >= 100) { - return DecodeStatus::FormatError; - } - buffer += ToAlphaNumericChar(twoDigitsBits / 10); - buffer += ToAlphaNumericChar(twoDigitsBits % 10); - } - else if (count == 1) { + if (twoDigitsBits >= 100) + throw FormatError("Invalid value in numeric segment"); + + result += ToAlphaNumericChar(twoDigitsBits / 10); + result += ToAlphaNumericChar(twoDigitsBits % 10); + } else if (count == 1) { // One digit left over to read - if (bits.available() < 4) { - return DecodeStatus::FormatError; - } int digitBits = bits.readBits(4); - if (digitBits >= 10) { - return DecodeStatus::FormatError; - } - buffer += ToAlphaNumericChar(digitBits); - } + if (digitBits >= 10) + throw FormatError("Invalid value in numeric segment"); - TextDecoder::AppendLatin1(result, buffer); - return DecodeStatus::NoError; + result += ToAlphaNumericChar(digitBits); + } } -static DecodeStatus -ParseECIValue(BitSource& bits, int &outValue) +static ECI ParseECIValue(BitSource& bits) { int firstByte = bits.readBits(8); if ((firstByte & 0x80) == 0) { // just one byte - outValue = firstByte & 0x7F; - return DecodeStatus::NoError; + return ECI(firstByte & 0x7F); } if ((firstByte & 0xC0) == 0x80) { // two bytes int secondByte = bits.readBits(8); - outValue = ((firstByte & 0x3F) << 8) | secondByte; - return DecodeStatus::NoError; + return ECI(((firstByte & 0x3F) << 8) | secondByte); } if ((firstByte & 0xE0) == 0xC0) { // three bytes int secondThirdBytes = bits.readBits(16); - outValue = ((firstByte & 0x1F) << 16) | secondThirdBytes; - return DecodeStatus::NoError; + return ECI(((firstByte & 0x1F) << 16) | secondThirdBytes); } - return DecodeStatus::FormatError; + throw FormatError("ParseECIValue: invalid value"); +} + +/** + * QR codes encode mode indicators and terminator codes into a constant bit length of 4. + * Micro QR codes have terminator codes that vary in bit length but are always longer than + * the mode indicators. + * M1 - 0 length mode code, 3 bits terminator code + * M2 - 1 bit mode code, 5 bits terminator code + * M3 - 2 bit mode code, 7 bits terminator code + * M4 - 3 bit mode code, 9 bits terminator code + * IsTerminator peaks into the bit stream to see if the current position is at the start of + * a terminator code. If true, then the decoding can finish. If false, then the decoding + * can read off the next mode code. + * + * See ISO 18004:2006, 6.4.1 Table 2 + * + * @param bits the stream of bits that might have a terminator code + * @param version the QR or micro QR code version + */ +bool IsEndOfStream(const BitSource& bits, const Version& version) +{ + const int bitsRequired = TerminatorBitsLength(version); + const int bitsAvailable = std::min(bits.available(), bitsRequired); + return bitsAvailable == 0 || bits.peakBits(bitsAvailable) == 0; } /** @@ -303,155 +252,112 @@ ParseECIValue(BitSource& bits, int &outValue) * *

See ISO 18004:2006, 6.4.3 - 6.4.7

*/ -ZXING_EXPORT_TEST_ONLY DecoderResult -DecodeBitStream(ByteArray&& bytes, const Version& version, ErrorCorrectionLevel ecLevel, const std::string& hintedCharset) +ZXING_EXPORT_TEST_ONLY +DecoderResult DecodeBitStream(ByteArray&& bytes, const Version& version, ErrorCorrectionLevel ecLevel) { BitSource bits(bytes); - std::wstring result; - int symbologyIdModifier = 1; // ISO/IEC 18004:2015 Annex F Table F.1 - int appIndValue = -1; // ISO/IEC 18004:2015 7.4.8.3 AIM Application Indicator (FNC1 in second position) + Content result; + Error error; + result.symbology = {'Q', '1', 1}; StructuredAppendInfo structuredAppend; - static const int GB2312_SUBSET = 1; + const int modeBitLength = CodecModeBitsLength(version); try { - CharacterSet currentCharset = CharacterSet::Unknown; - bool fc1InEffect = false; - CodecMode mode; - do { - // While still another segment to read... - if (bits.available() < 4) { - // OK, assume we're done. Really, a TERMINATOR mode should have been recorded here - mode = CodecMode::TERMINATOR; - } - else { - mode = CodecModeForBits(bits.readBits(4)); // mode is encoded by 4 bits - } + while(!IsEndOfStream(bits, version)) { + CodecMode mode; + if (modeBitLength == 0) + mode = CodecMode::NUMERIC; // MicroQRCode version 1 is always NUMERIC and modeBitLength is 0 + else + mode = CodecModeForBits(bits.readBits(modeBitLength), version.isMicroQRCode()); + switch (mode) { - case CodecMode::TERMINATOR: - break; case CodecMode::FNC1_FIRST_POSITION: - fc1InEffect = true; // In Alphanumeric mode undouble doubled percents and treat single percent as - // As converting character set ECIs ourselves and ignoring/skipping non-character ECIs, not using - // modifiers that indicate ECI protocol (ISO/IEC 18004:2015 Annex F Table F.1) - symbologyIdModifier = 3; +// if (!result.empty()) // uncomment to enforce specification +// throw FormatError("GS1 Indicator (FNC1 in first position) at illegal position"); + result.symbology.modifier = '3'; + result.applicationIndicator = "GS1"; // In Alphanumeric mode undouble doubled percents and treat single percent as break; case CodecMode::FNC1_SECOND_POSITION: - fc1InEffect = true; // As above - symbologyIdModifier = 5; // As above - // ISO/IEC 18004:2015 7.4.8.3 AIM Application Indicator "00-99" or "A-Za-z" - appIndValue = bits.readBits(8); // Number 00-99 or ASCII value + 100; prefixed to data below + if (!result.empty()) + throw FormatError("AIM Application Indicator (FNC1 in second position) at illegal position"); + result.symbology.modifier = '5'; // As above + // ISO/IEC 18004:2015 7.4.8.3 AIM Application Indicator (FNC1 in second position), "00-99" or "A-Za-z" + if (int appInd = bits.readBits(8); appInd < 10) // "00-09" + result += '0' + std::to_string(appInd); + else if (appInd < 100) // "10-99" + result += std::to_string(appInd); + else if ((appInd >= 165 && appInd <= 190) || (appInd >= 197 && appInd <= 222)) // "A-Za-z" + result += narrow_cast(appInd - 100); + else + throw FormatError("Invalid AIM Application Indicator"); + result.applicationIndicator = result.bytes.asString(); // see also above break; case CodecMode::STRUCTURED_APPEND: - if (bits.available() < 16) { - return DecodeStatus::FormatError; - } // sequence number and parity is added later to the result metadata // Read next 4 bits of index, 4 bits of symbol count, and 8 bits of parity data, then continue structuredAppend.index = bits.readBits(4); structuredAppend.count = bits.readBits(4) + 1; - structuredAppend.id = std::to_string(bits.readBits(8)); + structuredAppend.id = std::to_string(bits.readBits(8)); break; - case CodecMode::ECI: { + case CodecMode::ECI: // Count doesn't apply to ECI - int value; - auto status = ParseECIValue(bits, value); - if (StatusIsError(status)) { - return status; - } - currentCharset = CharacterSetECI::CharsetFromValue(value); - if (currentCharset == CharacterSet::Unknown) { - return DecodeStatus::FormatError; - } + result.switchEncoding(ParseECIValue(bits)); break; - } case CodecMode::HANZI: { // First handle Hanzi mode which does not start with character count // chinese mode contains a sub set indicator right after mode indicator - int subset = bits.readBits(4); - int countHanzi = bits.readBits(CharacterCountBits(mode, version)); - if (subset == GB2312_SUBSET) { - auto status = DecodeHanziSegment(bits, countHanzi, result); - if (StatusIsError(status)) { - return status; - } - } + if (int subset = bits.readBits(4); subset != 1) // GB2312_SUBSET is the only supported one right now + throw FormatError("Unsupported HANZI subset"); + int count = bits.readBits(CharacterCountBits(mode, version)); + DecodeHanziSegment(bits, count, result); break; } default: { // "Normal" QR code modes: // How many characters will follow, encoded in this mode? int count = bits.readBits(CharacterCountBits(mode, version)); - DecodeStatus status; switch (mode) { - case CodecMode::NUMERIC: - status = DecodeNumericSegment(bits, count, result); - break; - case CodecMode::ALPHANUMERIC: - status = DecodeAlphanumericSegment(bits, count, fc1InEffect, result); - break; - case CodecMode::BYTE: - status = DecodeByteSegment(bits, count, currentCharset, hintedCharset, result); - break; - case CodecMode::KANJI: - status = DecodeKanjiSegment(bits, count, result); - break; - default: - status = DecodeStatus::FormatError; - } - if (StatusIsError(status)) { - return status; + case CodecMode::NUMERIC: DecodeNumericSegment(bits, count, result); break; + case CodecMode::ALPHANUMERIC: DecodeAlphanumericSegment(bits, count, result); break; + case CodecMode::BYTE: DecodeByteSegment(bits, count, result); break; + case CodecMode::KANJI: DecodeKanjiSegment(bits, count, result); break; + default: throw FormatError("Invalid CodecMode"); } break; } } - } while (mode != CodecMode::TERMINATOR); - } - catch (const std::exception &) - { - // from readBits() calls - return DecodeStatus::FormatError; - } - - if (appIndValue >= 0) { - if (appIndValue < 10) { // "00-09" - result.insert(0, L'0' + std::to_wstring(appIndValue)); - } - else if (appIndValue < 100) { // "10-99" - result.insert(0, std::to_wstring(appIndValue)); - } - else if ((appIndValue >= 165 && appIndValue <= 190) || (appIndValue >= 197 && appIndValue <= 222)) { // "A-Za-z" - result.insert(0, 1, static_cast(appIndValue - 100)); - } - else { - return DecodeStatus::FormatError; } + } catch (Error e) { + error = std::move(e); } - std::string symbologyIdentifier("]Q" + std::to_string(symbologyIdModifier)); - return DecoderResult(std::move(bytes), std::move(result)) + .setError(std::move(error)) .setEcLevel(ToString(ecLevel)) - .setSymbologyIdentifier(std::move(symbologyIdentifier)) .setStructuredAppend(structuredAppend); } -static DecoderResult -DoDecode(const BitMatrix& bits, const Version& version, const std::string& hintedCharset, bool mirrored) +DecoderResult Decode(const BitMatrix& bits) { - auto formatInfo = ReadFormatInformation(bits, mirrored); + const Version* pversion = ReadVersion(bits); + if (!pversion) + return FormatError("Invalid version"); + const Version& version = *pversion; + + auto formatInfo = ReadFormatInformation(bits, version.isMicroQRCode()); if (!formatInfo.isValid()) - return DecodeStatus::FormatError; + return FormatError("Invalid format informatino"); // Read codewords - ByteArray codewords = ReadCodewords(bits, version, formatInfo.dataMask(), mirrored); + ByteArray codewords = ReadCodewords(bits, version, formatInfo); if (codewords.empty()) - return DecodeStatus::FormatError; + return FormatError("Failed to read codewords"); // Separate into data blocks - std::vector dataBlocks = DataBlock::GetDataBlocks(codewords, version, formatInfo.errorCorrectionLevel()); + std::vector dataBlocks = DataBlock::GetDataBlocks(codewords, version, formatInfo.ecLevel); if (dataBlocks.empty()) - return DecodeStatus::FormatError; + return FormatError("Failed to get data blocks"); // Count total number of data bytes const auto op = [](auto totalBytes, const auto& dataBlock){ return totalBytes + dataBlock.numDataCodewords();}; @@ -466,31 +372,13 @@ DoDecode(const BitMatrix& bits, const Version& version, const std::string& hinte int numDataCodewords = dataBlock.numDataCodewords(); if (!CorrectErrors(codewordBytes, numDataCodewords)) - return DecodeStatus::ChecksumError; + return ChecksumError(); resultIterator = std::copy_n(codewordBytes.begin(), numDataCodewords, resultIterator); } // Decode the contents of that stream of bytes - return DecodeBitStream(std::move(resultBytes), version, formatInfo.errorCorrectionLevel(), hintedCharset); -} - -DecoderResult Decode(const BitMatrix& bits, const std::string& hintedCharset) -{ - const Version* version = ReadVersion(bits); - if (!version) - return DecodeStatus::FormatError; - - auto res = DoDecode(bits, *version, hintedCharset, false); - if (res.isValid()) - return res; - - if (auto resMirrored = DoDecode(bits, *version, hintedCharset, true); resMirrored.isValid()) { - resMirrored.setIsMirrored(true); - return resMirrored; - } - - return res; + return DecodeBitStream(std::move(resultBytes), version, formatInfo.ecLevel).setIsMirrored(formatInfo.isMirrored); } } // namespace ZXing::QRCode diff --git a/core/src/qrcode/QRDecoder.h b/core/src/qrcode/QRDecoder.h index e66a7c1229..ecfdc92be1 100644 --- a/core/src/qrcode/QRDecoder.h +++ b/core/src/qrcode/QRDecoder.h @@ -1,20 +1,10 @@ -#pragma once /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include @@ -25,10 +15,7 @@ class BitMatrix; namespace QRCode { -/** - * @brief Decodes a QR Code from the BitMatrix and the hinted charset. - */ -DecoderResult Decode(const BitMatrix& bits, const std::string& hintedCharset); +DecoderResult Decode(const BitMatrix& bits); } // QRCode } // ZXing diff --git a/core/src/qrcode/QRDetector.cpp b/core/src/qrcode/QRDetector.cpp index e2834481bb..0070718858 100644 --- a/core/src/qrcode/QRDetector.cpp +++ b/core/src/qrcode/QRDetector.cpp @@ -2,29 +2,20 @@ * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors * Copyright 2020 Axel Waggershauser -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "QRDetector.h" +#include "BitArray.h" #include "BitMatrix.h" #include "BitMatrixCursor.h" #include "ConcentricFinder.h" -#include "DetectorResult.h" #include "GridSampler.h" #include "LogMatrix.h" #include "Pattern.h" +#include "QRFormatInformation.h" +#include "QRVersion.h" #include "Quadrilateral.h" #include "RegressionLine.h" @@ -40,11 +31,9 @@ namespace ZXing::QRCode { -constexpr auto PATTERN = FixedPattern<5, 7>{1, 1, 3, 1, 1}; -constexpr int MIN_MODULES = 1 * 4 + 17; // version 1 -constexpr int MAX_MODULES = 40 * 4 + 17; // version 40 +constexpr auto PATTERN = FixedPattern<5, 7>{1, 1, 3, 1, 1}; -static auto FindFinderPatterns(const BitMatrix& image, bool tryHarder) +std::vector FindFinderPatterns(const BitMatrix& image, bool tryHarder) { constexpr int MIN_SKIP = 3; // 1 pixel/module times 3 modules/center constexpr int MAX_MODULES_FAST = 20 * 4 + 17; // support up to version 20 for mobile clients @@ -93,7 +82,7 @@ static auto FindFinderPatterns(const BitMatrix& image, bool tryHarder) * @param patterns list of ConcentricPattern objects, i.e. found finder pattern squares * @return list of plausible finder pattern sets, sorted by decreasing plausibility */ -static FinderPatternSets GenerateFinderPatternSets(std::vector&& patterns) +FinderPatternSets GenerateFinderPatternSets(FinderPatterns& patterns) { std::sort(patterns.begin(), patterns.end(), [](const auto& a, const auto& b) { return a.size < b.size; }); @@ -121,30 +110,38 @@ static FinderPatternSets GenerateFinderPatternSets(std::vector= distAB && distBC >= distAC) { + if (distBC2 >= distAB2 && distBC2 >= distAC2) { std::swap(a, b); - std::swap(distBC, distAC); - } else if (distAB >= distAC && distAB >= distBC) { + std::swap(distBC2, distAC2); + } else if (distAB2 >= distAC2 && distAB2 >= distBC2) { std::swap(b, c); - std::swap(distAB, distAC); + std::swap(distAB2, distAC2); } + auto distAB = std::sqrt(distAB2); + auto distBC = std::sqrt(distBC2); + // Estimate the module count and ignore this set if it can not result in a valid decoding - if (auto moduleCount = - (std::sqrt(distAB) + std::sqrt(distBC)) / (2 * (a->size + b->size + c->size) / (3 * 7.f)) + 7; + if (auto moduleCount = (distAB + distBC) / (2 * (a->size + b->size + c->size) / (3 * 7.f)) + 7; moduleCount < 21 * 0.9 || moduleCount > 177 * 1.05) continue; + // Make sure the angle between AB and BC does not deviate from 90° by more than 45° + auto alpha = std::acos((distAB2 + distBC2 - distAC2) / (2 * distAB * distBC)) / 3.1415 * 180; +// printf("alpha: %.1f\n", alpha); + if (std::isnan(alpha) || std::abs(90 - alpha) > 45) + continue; + // a^2 + b^2 = c^2 (Pythagorean theorem), and a = b (isosceles triangle). // Since any right triangle satisfies the formula c^2 - b^2 - a^2 = 0, // we need to check both two equal sides separately. // The value of |c^2 - 2 * b^2| + |c^2 - 2 * a^2| increases as dissimilarity // from isosceles right triangle. - double d = std::abs(distAC - 2 * distAB) + std::abs(distAC - 2 * distBC); + double d = (std::abs(distAC2 - 2 * distAB2) + std::abs(distAC2 - 2 * distBC2)) / distAC2; // Use cross product to figure out whether A and C are correct or flipped. // This asks whether BC x BA has a positive z component, which is the arrangement @@ -205,7 +202,7 @@ static DimensionEstimate EstimateDimension(const BitMatrix& image, PointF a, Poi auto moduleSize = (ms_a + ms_b) / 2; - int dimension = std::lround(distance(a, b) / moduleSize) + 7; + int dimension = narrow_cast(std::lround(distance(a, b) / moduleSize) + 7); int error = 1 - (dimension % 4); return {dimension + error, moduleSize, std::abs(error)}; @@ -258,7 +255,7 @@ static double EstimateTilt(const FinderPatternSet& fp) return double(max) / min; } -DetectorResult SampleAtFinderPatternSet(const BitMatrix& image, const FinderPatternSet& fp) +DetectorResult SampleQR(const BitMatrix& image, const FinderPatternSet& fp) { auto top = EstimateDimension(image, fp.tl, fp.tr); auto left = EstimateDimension(image, fp.tl, fp.bl); @@ -303,8 +300,7 @@ DetectorResult SampleAtFinderPatternSet(const BitMatrix& image, const FinderPatt // if we did not land on a black pixel or the concentric pattern finder fails, // leave the intersection of the lines as the best guess if (image.get(brCoR)) { - if (auto brCP = - LocateConcentricPattern(image, FixedPattern<3, 3>{1, 1, 1}, brCoR, moduleSize * 3)) + if (auto brCP = LocateConcentricPattern(image, FixedPattern<3, 3>{1, 1, 1}, brCoR, moduleSize * 3)) return sample(*brCP, quad[2] - PointF(3, 3)); } } @@ -326,7 +322,7 @@ DetectorResult SampleAtFinderPatternSet(const BitMatrix& image, const FinderPatt * around it. This is a specialized method that works exceptionally fast in this special * case. */ -static DetectorResult DetectPure(const BitMatrix& image) +DetectorResult DetectPureQR(const BitMatrix& image) { using Pattern = std::array; @@ -334,6 +330,9 @@ static DetectorResult DetectPure(const BitMatrix& image) SaveAsPBM(image, "weg.pbm"); #endif + constexpr int MIN_MODULES = Version::DimensionOfVersion(1, false); + constexpr int MAX_MODULES = Version::DimensionOfVersion(40, false); + int left, top, width, height; if (!image.findBoundingBox(left, top, width, height, MIN_MODULES) || std::abs(width - height) > 1) return {}; @@ -371,30 +370,100 @@ static DetectorResult DetectPure(const BitMatrix& image) {{left, top}, {right, top}, {right, bottom}, {left, bottom}}}; } -FinderPatternSets FindFinderPatternSets(const BitMatrix& image, bool tryHarder) +DetectorResult DetectPureMQR(const BitMatrix& image) { - return GenerateFinderPatternSets(FindFinderPatterns(image, tryHarder)); -} + using Pattern = std::array; -DetectorResult Detect(const BitMatrix& image, bool tryHarder, bool isPure) -{ -#ifdef PRINT_DEBUG - LogMatrixWriter lmw(log, image, 5, "qr-log.pnm"); -#endif + constexpr int MIN_MODULES = Version::DimensionOfVersion(1, true); + constexpr int MAX_MODULES = Version::DimensionOfVersion(4, true); - if (isPure) - return DetectPure(image); + int left, top, width, height; + if (!image.findBoundingBox(left, top, width, height, MIN_MODULES) || std::abs(width - height) > 1) + return {}; + int right = left + width - 1; + int bottom = top + height - 1; + + // allow corners be moved one pixel inside to accommodate for possible aliasing artifacts + auto diagonal = BitMatrixCursorI(image, {left, top}, {1, 1}).readPatternFromBlack(1); + if (!IsPattern(diagonal, PATTERN)) + return {}; - auto sets = GenerateFinderPatternSets(FindFinderPatterns(image, tryHarder)); + auto fpWidth = Reduce(diagonal); + float moduleSize = float(fpWidth) / 7; + auto dimension = width / moduleSize; - if (sets.empty()) + if (dimension < MIN_MODULES || dimension > MAX_MODULES || + !image.isIn(PointF{left + moduleSize / 2 + (dimension - 1) * moduleSize, + top + moduleSize / 2 + (dimension - 1) * moduleSize})) return {}; #ifdef PRINT_DEBUG - printf("size of sets: %d\n", Size(sets)); + LogMatrix log; + LogMatrixWriter lmw(log, image, 5, "grid2.pnm"); + for (int y = 0; y < dimension; y++) + for (int x = 0; x < dimension; x++) + log(PointF(left + (x + .5f) * moduleSize, top + (y + .5f) * moduleSize)); #endif - return SampleAtFinderPatternSet(image, sets[0]); + // Now just read off the bits (this is a crop + subsample) + return {Deflate(image, dimension, dimension, top + moduleSize / 2, left + moduleSize / 2, moduleSize), + {{left, top}, {right, top}, {right, bottom}, {left, bottom}}}; +} + +DetectorResult SampleMQR(const BitMatrix& image, const ConcentricPattern& fp) +{ + auto fpQuad = FindConcentricPatternCorners(image, fp, fp.size, 2); + if (!fpQuad) + return {}; + + auto srcQuad = Rectangle(7, 7, 0.5); + + constexpr PointI FORMAT_INFO_COORDS[] = {{0, 8}, {1, 8}, {2, 8}, {3, 8}, {4, 8}, {5, 8}, {6, 8}, {7, 8}, {8, 8}, + {8, 7}, {8, 6}, {8, 5}, {8, 4}, {8, 3}, {8, 2}, {8, 1}, {8, 0}}; + + FormatInformation bestFI; + PerspectiveTransform bestPT; + + for (int i = 0; i < 4; ++i) { + auto mod2Pix = PerspectiveTransform(srcQuad, RotatedCorners(*fpQuad, i)); + + auto check = [&](int i, bool checkOne) { + auto p = mod2Pix(centered(FORMAT_INFO_COORDS[i])); + return image.isIn(p) && (!checkOne || image.get(p)); + }; + + // check that we see both innermost timing pattern modules + if (!check(0, true) || !check(8, false) || !check(16, true)) + continue; + + int formatInfoBits = 0; + for (int i = 1; i <= 15; ++i) + AppendBit(formatInfoBits, image.get(mod2Pix(centered(FORMAT_INFO_COORDS[i])))); + + auto fi = FormatInformation::DecodeMQR(formatInfoBits); + if (fi.hammingDistance < bestFI.hammingDistance) { + bestFI = fi; + bestPT = mod2Pix; + } + } + + if (!bestFI.isValid()) + return {}; + + const int dim = Version::DimensionOfVersion(bestFI.microVersion, true); + + // check that we are in fact not looking at a corner of a non-micro QRCode symbol + // we accept at most 1/3rd black pixels in the quite zone (in a QRCode symbol we expect about 1/2). + int blackPixels = 0; + for (int i = 0; i < dim; ++i) { + auto px = bestPT(centered(PointI{i, dim})); + auto py = bestPT(centered(PointI{dim, i})); + blackPixels += (image.isIn(px) && image.get(px)) + (image.isIn(py) && image.get(py)); + } + if (blackPixels > 2 * dim / 3) + return {}; + + return SampleGrid(image, dim, dim, bestPT); } } // namespace ZXing::QRCode diff --git a/core/src/qrcode/QRDetector.h b/core/src/qrcode/QRDetector.h index b11975fffa..4173d59a7a 100644 --- a/core/src/qrcode/QRDetector.h +++ b/core/src/qrcode/QRDetector.h @@ -1,23 +1,14 @@ -#pragma once /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors * Copyright 2021 Axel Waggershauser -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include "ConcentricFinder.h" +#include "DetectorResult.h" #include @@ -33,15 +24,17 @@ struct FinderPatternSet ConcentricPattern bl, tl, tr; }; +using FinderPatterns = std::vector; using FinderPatternSets = std::vector; -FinderPatternSets FindFinderPatternSets(const BitMatrix& image, bool tryHarder); -DetectorResult SampleAtFinderPatternSet(const BitMatrix& image, const FinderPatternSet& fp); +FinderPatterns FindFinderPatterns(const BitMatrix& image, bool tryHarder); +FinderPatternSets GenerateFinderPatternSets(FinderPatterns& patterns); + +DetectorResult SampleQR(const BitMatrix& image, const FinderPatternSet& fp); +DetectorResult SampleMQR(const BitMatrix& image, const ConcentricPattern& fp); -/** - * @brief Detects a QR Code in an image. - */ -DetectorResult Detect(const BitMatrix& image, bool tryHarder, bool isPure); +DetectorResult DetectPureQR(const BitMatrix& image); +DetectorResult DetectPureMQR(const BitMatrix& image); } // QRCode } // ZXing diff --git a/core/src/qrcode/QRECB.h b/core/src/qrcode/QRECB.h index 5bb8017819..37cefea6df 100644 --- a/core/src/qrcode/QRECB.h +++ b/core/src/qrcode/QRECB.h @@ -1,20 +1,10 @@ -#pragma once /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include @@ -47,22 +37,17 @@ struct ECBlocks int codewordsPerBlock; std::array blocks; - int numBlocks() const { - return blocks[0].count + blocks[1].count; - } + int numBlocks() const { return blocks[0].count + blocks[1].count; } - int totalCodewords() const { - return codewordsPerBlock * numBlocks(); - } + int totalCodewords() const { return codewordsPerBlock * numBlocks(); } - int totalDataCodewords() const { + int totalDataCodewords() const + { return blocks[0].count * (blocks[0].dataCodewords + codewordsPerBlock) - + blocks[1].count * (blocks[1].dataCodewords + codewordsPerBlock); + + blocks[1].count * (blocks[1].dataCodewords + codewordsPerBlock); } - const std::array& blockArray() const { - return blocks; - } + const std::array& blockArray() const { return blocks; } }; diff --git a/core/src/qrcode/QREncodeResult.h b/core/src/qrcode/QREncodeResult.h index 366a475215..8898c04dc3 100644 --- a/core/src/qrcode/QREncodeResult.h +++ b/core/src/qrcode/QREncodeResult.h @@ -1,20 +1,10 @@ -#pragma once /* * Copyright 2016 Huy Cuong Nguyen * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include "BitMatrix.h" #include "ByteArray.h" diff --git a/core/src/qrcode/QREncoder.cpp b/core/src/qrcode/QREncoder.cpp index 297da96a31..206e4cd70a 100644 --- a/core/src/qrcode/QREncoder.cpp +++ b/core/src/qrcode/QREncoder.cpp @@ -1,24 +1,13 @@ /* * Copyright 2016 Huy Cuong Nguyen * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "QREncoder.h" #include "BitArray.h" -#include "CharacterSetECI.h" +#include "ECI.h" #include "GenericGF.h" #include "QREncodeResult.h" #include "QRErrorCorrectionLevel.h" @@ -38,7 +27,7 @@ namespace ZXing::QRCode { static const CharacterSet DEFAULT_BYTE_MODE_ENCODING = CharacterSet::ISO8859_1; // The original table is defined in the table 5 of JISX0510:2004 (p.19). -static const std::array ALPHANUMERIC_TABLE = { +static const std::array ALPHANUMERIC_TABLE = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0x00-0x0f -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0x10-0x1f 36, -1, -1, -1, 37, 38, -1, -1, -1, -1, 39, 40, -1, 41, 42, 43, // 0x20-0x2f @@ -114,7 +103,7 @@ CodecMode ChooseMode(const std::wstring& content, CharacterSet encoding) */ static void AppendECI(CharacterSet eci, BitArray& bits) { - int eciValue = CharacterSetECI::ValueForCharset(eci); + int eciValue = ToInt(ToECI(eci)); if (eciValue >= 0 && eciValue <= 999999) { bits.appendBits(static_cast(CodecMode::ECI), 4); if (eciValue <= 127) { @@ -294,7 +283,8 @@ void TerminateBits(int numDataBytes, BitArray& bits) { int capacity = numDataBytes * 8; if (bits.size() > capacity) { - throw std::invalid_argument("data bits cannot fit in the QR Code" + std::to_string(bits.size()) + " > " + std::to_string(capacity)); + throw std::invalid_argument("data bits cannot fit in the QR Code" + std::to_string(bits.size()) + " > " + + std::to_string(capacity)); } for (int i = 0; i < 4 && bits.size() < capacity; ++i) { bits.appendBit(false); @@ -330,7 +320,8 @@ struct BlockPair * JISX0510:2004 (p.30) */ ZXING_EXPORT_TEST_ONLY -void GetNumDataBytesAndNumECBytesForBlockID(int numTotalBytes, int numDataBytes, int numRSBlocks, int blockID, int& numDataBytesInBlock, int& numECBytesInBlock) +void GetNumDataBytesAndNumECBytesForBlockID(int numTotalBytes, int numDataBytes, int numRSBlocks, int blockID, + int& numDataBytesInBlock, int& numECBytesInBlock) { if (blockID >= numRSBlocks) { throw std::invalid_argument("Block ID too large"); @@ -361,11 +352,9 @@ void GetNumDataBytesAndNumECBytesForBlockID(int numTotalBytes, int numDataBytes, throw std::invalid_argument("RS blocks mismatch"); } // 196 = (13 + 26) * 4 + (14 + 26) * 1 - if (numTotalBytes != - ((numDataBytesInGroup1 + numEcBytesInGroup1) * - numRsBlocksInGroup1) + - ((numDataBytesInGroup2 + numEcBytesInGroup2) * - numRsBlocksInGroup2)) { + if (numTotalBytes + != ((numDataBytesInGroup1 + numEcBytesInGroup1) * numRsBlocksInGroup1) + + ((numDataBytesInGroup2 + numEcBytesInGroup2) * numRsBlocksInGroup2)) { throw std::invalid_argument("Total bytes mismatch"); } @@ -387,8 +376,7 @@ void GenerateECBytes(const ByteArray& dataBytes, int numEcBytes, ByteArray& ecBy ReedSolomonEncode(GenericGF::QRCodeField256(), message, numEcBytes); ecBytes.resize(numEcBytes); - std::transform(message.end() - numEcBytes, message.end(), ecBytes.begin(), - [](auto c) { return static_cast(c); }); + std::transform(message.end() - numEcBytes, message.end(), ecBytes.begin(), [](auto c) { return narrow_cast(c); }); } @@ -447,7 +435,8 @@ BitArray InterleaveWithECBytes(const BitArray& bits, int numTotalBytes, int numD } } if (numTotalBytes != output.sizeInBytes()) { // Should be same. - throw std::invalid_argument("Interleaving error: " + std::to_string(numTotalBytes) + " and " + std::to_string(output.sizeInBytes()) + " differ."); + throw std::invalid_argument("Interleaving error: " + std::to_string(numTotalBytes) + " and " + std::to_string(output.sizeInBytes()) + + " differ."); } return output; } diff --git a/core/src/qrcode/QREncoder.h b/core/src/qrcode/QREncoder.h index 95420dee0a..b8e364806a 100644 --- a/core/src/qrcode/QREncoder.h +++ b/core/src/qrcode/QREncoder.h @@ -1,20 +1,10 @@ -#pragma once /* * Copyright 2016 Huy Cuong Nguyen * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include diff --git a/core/src/qrcode/QRErrorCorrectionLevel.cpp b/core/src/qrcode/QRErrorCorrectionLevel.cpp index 7ff749a515..0c66b2263c 100644 --- a/core/src/qrcode/QRErrorCorrectionLevel.cpp +++ b/core/src/qrcode/QRErrorCorrectionLevel.cpp @@ -1,19 +1,8 @@ /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "QRErrorCorrectionLevel.h" @@ -21,10 +10,10 @@ namespace ZXing::QRCode { -const wchar_t* ToString(ErrorCorrectionLevel l) +const char* ToString(ErrorCorrectionLevel l) { assert(l != ErrorCorrectionLevel::Invalid); - static const wchar_t* const LEVEL_STR[] = { L"L", L"M", L"Q", L"H", nullptr }; + static const char* const LEVEL_STR[] = {"L", "M", "Q", "H", nullptr}; return LEVEL_STR[static_cast(l)]; } @@ -35,20 +24,27 @@ ErrorCorrectionLevel ECLevelFromString(const char* str) case 'M': return ErrorCorrectionLevel::Medium; case 'Q': return ErrorCorrectionLevel::Quality; case 'H': return ErrorCorrectionLevel::High; - default: return ErrorCorrectionLevel::Invalid; + default: return ErrorCorrectionLevel::Invalid; } } -ErrorCorrectionLevel ECLevelFromBits(int bits) +ErrorCorrectionLevel ECLevelFromBits(int bits, const bool isMicro) { - static const ErrorCorrectionLevel LEVEL_FOR_BITS[] = { ErrorCorrectionLevel::Medium, ErrorCorrectionLevel::Low, ErrorCorrectionLevel::High, ErrorCorrectionLevel::Quality }; + if (isMicro) { + constexpr ErrorCorrectionLevel LEVEL_FOR_BITS[] = { + ErrorCorrectionLevel::Low, ErrorCorrectionLevel::Low, ErrorCorrectionLevel::Medium, ErrorCorrectionLevel::Low, + ErrorCorrectionLevel::Medium, ErrorCorrectionLevel::Low, ErrorCorrectionLevel::Medium, ErrorCorrectionLevel::Quality}; + return LEVEL_FOR_BITS[bits & 0x07]; + } + constexpr ErrorCorrectionLevel LEVEL_FOR_BITS[] = {ErrorCorrectionLevel::Medium, ErrorCorrectionLevel::Low, + ErrorCorrectionLevel::High, ErrorCorrectionLevel::Quality}; return LEVEL_FOR_BITS[bits & 0x3]; } int BitsFromECLevel(ErrorCorrectionLevel l) { assert(l != ErrorCorrectionLevel::Invalid); - static const int BITS[] = { 1, 0, 3, 2, -1 }; + static const int BITS[] = {1, 0, 3, 2, -1}; return BITS[(int)l]; } diff --git a/core/src/qrcode/QRErrorCorrectionLevel.h b/core/src/qrcode/QRErrorCorrectionLevel.h index 1241b1451b..704fc86939 100644 --- a/core/src/qrcode/QRErrorCorrectionLevel.h +++ b/core/src/qrcode/QRErrorCorrectionLevel.h @@ -1,20 +1,10 @@ -#pragma once /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once namespace ZXing { namespace QRCode { @@ -27,16 +17,16 @@ namespace QRCode { */ enum class ErrorCorrectionLevel { - Low, // L = ~7 % correction - Medium, // M = ~15% correction - Quality, // Q = ~25% correction - High, // H = ~30% correction - Invalid, // denotes in invalid/unknown value + Low, // L = ~7 % correction + Medium, // M = ~15% correction + Quality, // Q = ~25% correction + High, // H = ~30% correction + Invalid, // denotes in invalid/unknown value }; -const wchar_t* ToString(ErrorCorrectionLevel l); +const char* ToString(ErrorCorrectionLevel l); ErrorCorrectionLevel ECLevelFromString(const char* str); -ErrorCorrectionLevel ECLevelFromBits(int bits); +ErrorCorrectionLevel ECLevelFromBits(int bits, const bool isMicro = false); int BitsFromECLevel(ErrorCorrectionLevel l); } // QRCode diff --git a/core/src/qrcode/QRFormatInformation.cpp b/core/src/qrcode/QRFormatInformation.cpp index bc32436f2d..7f4cba4aa8 100644 --- a/core/src/qrcode/QRFormatInformation.cpp +++ b/core/src/qrcode/QRFormatInformation.cpp @@ -1,19 +1,8 @@ /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "QRFormatInformation.h" @@ -28,7 +17,7 @@ static const int FORMAT_INFO_MASK_QR = 0x5412; /** * See ISO 18004:2006, Annex C, Table C.1 */ -static const std::array FORMAT_INFO_DECODE_LOOKUP[] = { +static const std::array, 32> FORMAT_INFO_DECODE_LOOKUP = {{ {0x5412, 0x00}, {0x5125, 0x01}, {0x5E7C, 0x02}, @@ -61,45 +50,97 @@ static const std::array FORMAT_INFO_DECODE_LOOKUP[] = { {0x2183, 0x1D}, {0x2EDA, 0x1E}, {0x2BED, 0x1F}, -}; +}}; -FormatInformation::FormatInformation(int formatInfo) +static const std::array, 32> FORMAT_INFO_DECODE_LOOKUP_MICRO = {{ + {0x4445, 0x00}, + {0x4172, 0x01}, + {0x4E2B, 0x02}, + {0x4B1C, 0x03}, + {0x55AE, 0x04}, + {0x5099, 0x05}, + {0x5FC0, 0x06}, + {0x5AF7, 0x07}, + {0x6793, 0x08}, + {0x62A4, 0x09}, + {0x6DFD, 0x0A}, + {0x68CA, 0x0B}, + {0x7678, 0x0C}, + {0x734F, 0x0D}, + {0x7C16, 0x0E}, + {0x7921, 0x0F}, + {0x06DE, 0x10}, + {0x03E9, 0x11}, + {0x0CB0, 0x12}, + {0x0987, 0x13}, + {0x1735, 0x14}, + {0x1202, 0x15}, + {0x1D5B, 0x16}, + {0x186C, 0x17}, + {0x2508, 0x18}, + {0x203F, 0x19}, + {0x2F66, 0x1A}, + {0x2A51, 0x1B}, + {0x34E3, 0x1C}, + {0x31D4, 0x1D}, + {0x3E8D, 0x1E}, + {0x3BBA, 0x1F}, +}}; + +static FormatInformation FindBestFormatInfo(int mask, const std::array, 32> lookup, + const std::vector& bits) { - // Bits 3,4 - _errorCorrectionLevel = ECLevelFromBits((formatInfo >> 3) & 0x03); - // Bottom 3 bits - _dataMask = static_cast(formatInfo & 0x07); + FormatInformation fi; + + // Some QR codes apparently do not apply the XOR mask. Try without and with additional masking. + for (auto mask : {0, mask}) + for (uint32_t bits : bits) + for (bool mirror : {false, true}) + for (const auto& [pattern, index] : lookup) { + if (mirror) + bits = BitHacks::Reverse(bits) >> 17; + // Find the int in lookup with fewest bits differing + if (int hammingDist = BitHacks::CountBitsSet((bits ^ mask) ^ pattern); hammingDist < fi.hammingDistance) { + fi.index = index; + fi.hammingDistance = hammingDist; + fi.isMirrored = mirror; + } + } + + return fi; } /** * @param formatInfoBits1 format info indicator, with mask still applied -* @param formatInfoBits2 second copy of same info; both are checked at the same time -* to establish best match -* @return information about the format it specifies, or {@code null} -* if doesn't seem to match any known pattern +* @param formatInfoBits2 second copy of same info; both are checked at the same time to establish best match */ -FormatInformation -FormatInformation::DecodeFormatInformation(uint32_t formatInfoBits1, uint32_t formatInfoBits2) +FormatInformation FormatInformation::DecodeQR(uint32_t formatInfoBits1, uint32_t formatInfoBits2) { - // Find the int in FORMAT_INFO_DECODE_LOOKUP with fewest bits differing - int bestDifference = 32; - int bestFormatInfo = -1; + auto fi = FindBestFormatInfo(FORMAT_INFO_MASK_QR, FORMAT_INFO_DECODE_LOOKUP, {formatInfoBits1, formatInfoBits2}); - // Some QR codes apparently do not apply the XOR mask. Try without and with additional masking. - for (auto mask : {0, FORMAT_INFO_MASK_QR}) - for (uint32_t bits : {formatInfoBits1 ^ mask, formatInfoBits2 ^ mask}) - for (auto& [pattern, decodedInfo] : FORMAT_INFO_DECODE_LOOKUP) - if (int bitsDifference = BitHacks::CountBitsSet(bits ^ pattern); bitsDifference < bestDifference) { - bestFormatInfo = decodedInfo; - bestDifference = bitsDifference; - } + // Use bits 3/4 for error correction, and 0-2 for mask. + fi.ecLevel = ECLevelFromBits((fi.index >> 3) & 0x03); + fi.dataMask = static_cast(fi.index & 0x07); + + return fi; +} + +/** + * @param formatInfoBits format info indicator, with mask still applied + */ +FormatInformation FormatInformation::DecodeMQR(uint32_t formatInfoBits) +{ + // We don't use the additional masking (with 0x4445) to work around potentially non complying MircoQRCode encoders + auto fi = FindBestFormatInfo(0, FORMAT_INFO_DECODE_LOOKUP_MICRO, {formatInfoBits}); + + constexpr uint8_t BITS_TO_VERSION[] = {1, 2, 2, 3, 3, 4, 4, 4}; - // Hamming distance of the 32 masked codes is 7, by construction, so <= 3 bits - // differing means we found a match - if (bestDifference <= 3) - return {bestFormatInfo}; + // Bits 2/3/4 contain both error correction level and version, 0/1 contain mask. + fi.ecLevel = ECLevelFromBits((fi.index >> 2) & 0x07, true); + fi.dataMask = static_cast(fi.index & 0x03); + fi.microVersion = BITS_TO_VERSION[(fi.index >> 2) & 0x07]; - return {}; + return fi; } } // namespace ZXing::QRCode diff --git a/core/src/qrcode/QRFormatInformation.h b/core/src/qrcode/QRFormatInformation.h index fbfe967da6..d7d59a2d9d 100644 --- a/core/src/qrcode/QRFormatInformation.h +++ b/core/src/qrcode/QRFormatInformation.h @@ -1,20 +1,10 @@ -#pragma once /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include "QRErrorCorrectionLevel.h" @@ -23,40 +13,28 @@ namespace ZXing { namespace QRCode { -/** -*

Encapsulates a QR Code's format information, including the data mask used and -* error correction level.

-* -* @author Sean Owen -* @see DataMask -* @see ErrorCorrectionLevel -*/ class FormatInformation { public: - FormatInformation() = default; - - static FormatInformation DecodeFormatInformation(uint32_t formatInfoBits1, uint32_t formatInfoBits2); + uint8_t index = 255; + uint8_t hammingDistance = 255; + bool isMirrored = false; + uint8_t dataMask = 0; + uint8_t microVersion = 0; + ErrorCorrectionLevel ecLevel = ErrorCorrectionLevel::Invalid; - ErrorCorrectionLevel errorCorrectionLevel() const { - return _errorCorrectionLevel; - } + FormatInformation() = default; - uint8_t dataMask() const { - return _dataMask; - } + static FormatInformation DecodeQR(uint32_t formatInfoBits1, uint32_t formatInfoBits2); + static FormatInformation DecodeMQR(uint32_t formatInfoBits); - bool isValid() const { return _errorCorrectionLevel != ErrorCorrectionLevel::Invalid; } + // Hamming distance of the 32 masked codes is 7, by construction, so <= 3 bits differing means we found a match + bool isValid() const { return hammingDistance <= 3; } - bool operator==(const FormatInformation& other) const { - return _dataMask == other._dataMask && _errorCorrectionLevel == other._errorCorrectionLevel; + bool operator==(const FormatInformation& other) const + { + return dataMask == other.dataMask && ecLevel == other.ecLevel; } - -private: - ErrorCorrectionLevel _errorCorrectionLevel = ErrorCorrectionLevel::Invalid; - uint8_t _dataMask = 0; - - FormatInformation(int formatInfo); }; } // QRCode diff --git a/core/src/qrcode/QRMaskUtil.cpp b/core/src/qrcode/QRMaskUtil.cpp index 2f327e4f2a..53c9b3ac58 100644 --- a/core/src/qrcode/QRMaskUtil.cpp +++ b/core/src/qrcode/QRMaskUtil.cpp @@ -1,19 +1,8 @@ /* * Copyright 2016 Huy Cuong Nguyen * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "QRMaskUtil.h" @@ -35,7 +24,8 @@ static const int N4 = 10; * Helper function for applyMaskPenaltyRule1. We need this for doing this calculation in both * vertical and horizontal orders respectively. */ -static int ApplyMaskPenaltyRule1Internal(const TritMatrix& matrix, bool isHorizontal) { +static int ApplyMaskPenaltyRule1Internal(const TritMatrix& matrix, bool isHorizontal) +{ int penalty = 0; int width = matrix.width(); int height = matrix.height(); @@ -64,7 +54,6 @@ static int ApplyMaskPenaltyRule1Internal(const TritMatrix& matrix, bool isHorizo return penalty; } - /** * Apply mask penalty rule 1 and return the penalty. Find repetitive cells with the same color and * give penalty to them. Example: 00000 or 11111. @@ -93,8 +82,9 @@ static int ApplyMaskPenaltyRule2(const TritMatrix& matrix) return N2 * penalty; } -template -static bool HasPatternAt(const std::array& pattern, const Trit* begin, int count, int stride) { +template +static bool HasPatternAt(const std::array& pattern, const Trit* begin, int count, int stride) +{ assert(std::abs(count) <= (int)N); auto end = begin + count * stride; if (count < 0) @@ -124,14 +114,14 @@ static int ApplyMaskPenaltyRule3(const TritMatrix& matrix) for (int y = 0; y < height; y++) { for (int x = 0; x < width; x++) { auto i = &matrix.get(x, y); - if (x <= width - finderSize && HasPatternAt(finder, i, finderSize, 1) && - (HasPatternAt(white, i, -std::min(x, whiteSize), 1) || - HasPatternAt(white, i + finderSize, std::min(width - x - finderSize, whiteSize), 1))) { + if (x <= width - finderSize && HasPatternAt(finder, i, finderSize, 1) + && (HasPatternAt(white, i, -std::min(x, whiteSize), 1) + || HasPatternAt(white, i + finderSize, std::min(width - x - finderSize, whiteSize), 1))) { numPenalties++; } - if (y <= height - finderSize && HasPatternAt(finder, i, finderSize, width) && - (HasPatternAt(white, i, -std::min(y, whiteSize), width) || - HasPatternAt(white, i + finderSize * width, std::min(height - y - finderSize, whiteSize), width))) { + if (y <= height - finderSize && HasPatternAt(finder, i, finderSize, width) + && (HasPatternAt(white, i, -std::min(y, whiteSize), width) + || HasPatternAt(white, i + finderSize * width, std::min(height - y - finderSize, whiteSize), width))) { numPenalties++; } } @@ -145,10 +135,10 @@ static int ApplyMaskPenaltyRule3(const TritMatrix& matrix) */ static int ApplyMaskPenaltyRule4(const TritMatrix& matrix) { - auto numDarkCells = std::count_if(matrix.begin(), matrix.end(), [](Trit cell){ return cell; }); + auto numDarkCells = std::count_if(matrix.begin(), matrix.end(), [](Trit cell) { return cell; }); auto numTotalCells = matrix.size(); auto fivePercentVariances = std::abs(numDarkCells * 2 - numTotalCells) * 10 / numTotalCells; - return static_cast(fivePercentVariances * N4); + return narrow_cast(fivePercentVariances * N4); } // The mask penalty calculation is complicated. See Table 21 of JISX0510:2004 (p.45) for details. diff --git a/core/src/qrcode/QRMaskUtil.h b/core/src/qrcode/QRMaskUtil.h index 9e2d4d355d..f7a0c06ddd 100644 --- a/core/src/qrcode/QRMaskUtil.h +++ b/core/src/qrcode/QRMaskUtil.h @@ -1,27 +1,19 @@ -#pragma once /* * Copyright 2016 Huy Cuong Nguyen * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include "TritMatrix.h" namespace ZXing { namespace QRCode { namespace MaskUtil { - int CalculateMaskPenalty(const TritMatrix& matrix); -} -} // QRCode -} // ZXing + +int CalculateMaskPenalty(const TritMatrix& matrix); + +} // namespace MaskUtil +} // namespace QRCode +} // namespace ZXing diff --git a/core/src/qrcode/QRMatrixUtil.cpp b/core/src/qrcode/QRMatrixUtil.cpp index f937a08f5b..4767eebc23 100644 --- a/core/src/qrcode/QRMatrixUtil.cpp +++ b/core/src/qrcode/QRMatrixUtil.cpp @@ -1,19 +1,8 @@ /* * Copyright 2016 Huy Cuong Nguyen * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "QRMatrixUtil.h" @@ -151,7 +140,8 @@ static int FindMSBSet(unsigned value) // // Since all coefficients in the polynomials are 1 or 0, we can do the calculation by bit // operations. We don't care if cofficients are positive or negative. -static int CalculateBCHCode(int value, int poly) { +static int CalculateBCHCode(int value, int poly) +{ // If poly is "1 1111 0010 0101" (version info poly), msbSetInPoly is 13. We'll subtract 1 // from 13 to make it 12. int msbSetInPoly = FindMSBSet(poly); @@ -306,8 +296,7 @@ static void EmbedDataBits(const BitArray& dataBits, int maskPattern, TritMatrix& // Build 2D matrix of QR Code from "dataBits" with "ecLevel", "version" and "getMaskPattern". On // success, store the result in "matrix" and return true. -void BuildMatrix(const BitArray& dataBits, ErrorCorrectionLevel ecLevel, const Version& version, int maskPattern, - TritMatrix& matrix) +void BuildMatrix(const BitArray& dataBits, ErrorCorrectionLevel ecLevel, const Version& version, int maskPattern, TritMatrix& matrix) { matrix.clear(); // Let's get started with embedding big squares at corners. diff --git a/core/src/qrcode/QRMatrixUtil.h b/core/src/qrcode/QRMatrixUtil.h index 837bf99c28..11f922865f 100644 --- a/core/src/qrcode/QRMatrixUtil.h +++ b/core/src/qrcode/QRMatrixUtil.h @@ -1,20 +1,10 @@ -#pragma once /* * Copyright 2016 Huy Cuong Nguyen * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include "TritMatrix.h" @@ -29,8 +19,7 @@ class Version; constexpr int NUM_MASK_PATTERNS = 8; -void BuildMatrix(const BitArray& dataBits, ErrorCorrectionLevel ecLevel, const Version& version, int maskPattern, - TritMatrix& matrix); +void BuildMatrix(const BitArray& dataBits, ErrorCorrectionLevel ecLevel, const Version& version, int maskPattern, TritMatrix& matrix); } // QRCode } // ZXing diff --git a/core/src/qrcode/QRReader.cpp b/core/src/qrcode/QRReader.cpp index effd0e44e1..7d825f7f82 100644 --- a/core/src/qrcode/QRReader.cpp +++ b/core/src/qrcode/QRReader.cpp @@ -1,23 +1,14 @@ /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. +* Copyright 2022 Axel Waggershauser */ +// SPDX-License-Identifier: Apache-2.0 #include "QRReader.h" #include "BinaryBitmap.h" +#include "ConcentricFinder.h" #include "DecodeHints.h" #include "DecoderResult.h" #include "DetectorResult.h" @@ -30,34 +21,31 @@ namespace ZXing::QRCode { -Reader::Reader(const DecodeHints& hints) - : _tryHarder(hints.tryHarder()), _isPure(hints.isPure()), _charset(hints.characterSet()) -{ -} - -Result -Reader::decode(const BinaryBitmap& image) const +Result Reader::decode(const BinaryBitmap& image) const { #if 1 - if (!_isPure) { - auto res = decode(image, 1); - return res.empty() ? Result(DecodeStatus::NotFound) : res.front(); - } + if (!_hints.isPure()) + return FirstOrDefault(decode(image, 1)); #endif auto binImg = image.getBitMatrix(); - if (binImg == nullptr) { - return Result(DecodeStatus::NotFound); - } + if (binImg == nullptr) + return {}; + + DetectorResult detectorResult; + if (_hints.hasFormat(BarcodeFormat::QRCode)) + detectorResult = DetectPureQR(*binImg); + if (_hints.hasFormat(BarcodeFormat::MicroQRCode) && !detectorResult.isValid()) + detectorResult = DetectPureMQR(*binImg); - auto detectorResult = Detect(*binImg, _tryHarder, _isPure); if (!detectorResult.isValid()) - return Result(DecodeStatus::NotFound); + return {}; - auto decoderResult = Decode(detectorResult.bits(), _charset); + auto decoderResult = Decode(detectorResult.bits()); auto position = detectorResult.position(); - return Result(std::move(decoderResult), std::move(position), BarcodeFormat::QRCode); + return Result(std::move(decoderResult), std::move(position), + detectorResult.bits().width() < 21 ? BarcodeFormat::MicroQRCode : BarcodeFormat::QRCode); } Results Reader::decode(const BinaryBitmap& image, int maxSymbols) const @@ -70,25 +58,50 @@ Results Reader::decode(const BinaryBitmap& image, int maxSymbols) const LogMatrixWriter lmw(log, *binImg, 5, "qr-log.pnm"); #endif - FinderPatternSets allFPSets = FindFinderPatternSets(*binImg, _tryHarder); + auto allFPs = FindFinderPatterns(*binImg, _hints.tryHarder()); + std::vector usedFPs; Results results; - for(auto& fpSet : allFPSets) { - if (Contains(usedFPs, fpSet.bl) || Contains(usedFPs, fpSet.tl) || Contains(usedFPs, fpSet.tr)) - continue; - - auto detectorResult = SampleAtFinderPatternSet(*binImg, fpSet); - if (detectorResult.isValid()) { - auto decoderResult = Decode(detectorResult.bits(), _charset); - auto position = detectorResult.position(); - if (decoderResult.isValid()) { - usedFPs.push_back(fpSet.bl); - usedFPs.push_back(fpSet.tl); - usedFPs.push_back(fpSet.tr); - results.emplace_back(std::move(decoderResult), std::move(position), BarcodeFormat::QRCode); - if (maxSymbols && Size(results) == maxSymbols) - break; + if (_hints.hasFormat(BarcodeFormat::QRCode)) { + auto allFPSets = GenerateFinderPatternSets(allFPs); + for (auto& fpSet : allFPSets) { + if (Contains(usedFPs, fpSet.bl) || Contains(usedFPs, fpSet.tl) || Contains(usedFPs, fpSet.tr)) + continue; + + auto detectorResult = SampleQR(*binImg, fpSet); + if (detectorResult.isValid()) { + auto decoderResult = Decode(detectorResult.bits()); + auto position = detectorResult.position(); + if (decoderResult.isValid()) { + usedFPs.push_back(fpSet.bl); + usedFPs.push_back(fpSet.tl); + usedFPs.push_back(fpSet.tr); + } + if (decoderResult.isValid(_hints.returnErrors())) { + results.emplace_back(std::move(decoderResult), std::move(position), BarcodeFormat::QRCode); + if (maxSymbols && Size(results) == maxSymbols) + break; + } + } + } + } + + if (_hints.hasFormat(BarcodeFormat::MicroQRCode) && !(maxSymbols && Size(results) == maxSymbols)) { + for (auto fp : allFPs) { + if (Contains(usedFPs, fp)) + continue; + + auto detectorResult = SampleMQR(*binImg, fp); + if (detectorResult.isValid()) { + auto decoderResult = Decode(detectorResult.bits()); + auto position = detectorResult.position(); + if (decoderResult.isValid(_hints.returnErrors())) { + results.emplace_back(std::move(decoderResult), std::move(position), BarcodeFormat::MicroQRCode); + if (maxSymbols && Size(results) == maxSymbols) + break; + } + } } } diff --git a/core/src/qrcode/QRReader.h b/core/src/qrcode/QRReader.h index 1df4e8f2b1..22d514e254 100644 --- a/core/src/qrcode/QRReader.h +++ b/core/src/qrcode/QRReader.h @@ -1,48 +1,22 @@ -#pragma once /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 -#include "Reader.h" - -#include - -namespace ZXing { +#pragma once -class DecodeHints; +#include "Reader.h" -namespace QRCode { +namespace ZXing::QRCode { -/** -* This implementation can detect and decode QR Codes in an image. -* -* @author Sean Owen -*/ class Reader : public ZXing::Reader { public: - explicit Reader(const DecodeHints& hints); - Result decode(const BinaryBitmap& image) const override; + using ZXing::Reader::Reader; + Result decode(const BinaryBitmap& image) const override; Results decode(const BinaryBitmap& image, int maxSymbols) const override; - -private: - bool _tryHarder, _isPure; - std::string _charset; }; -} // QRCode -} // ZXing +} // namespace ZXing::QRCode diff --git a/core/src/qrcode/QRVersion.cpp b/core/src/qrcode/QRVersion.cpp index 248afbc671..537bc91fc7 100644 --- a/core/src/qrcode/QRVersion.cpp +++ b/core/src/qrcode/QRVersion.cpp @@ -1,19 +1,8 @@ /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "QRVersion.h" @@ -290,37 +279,50 @@ Version::AllVersions() return allVersions; } -Version::Version(int versionNumber, std::initializer_list alignmentPatternCenters, const std::array &ecBlocks) : - _versionNumber(versionNumber), - _alignmentPatternCenters(alignmentPatternCenters), - _ecBlocks(ecBlocks) +const Version* Version::AllMicroVersions() +{ + /** + * See ISO 18004:2006 6.5.1 Table 9 + */ + static const Version allVersions[] = { + {1, {2, 1, 3, 0, 0}}, + {2, {5, 1, 5, 0, 0, 6, 1, 4, 0, 0}}, + {3, {6, 1, 11, 0, 0, 8, 1, 9, 0, 0}}, + {4, {8, 1, 16, 0, 0, 10, 1, 14, 0, 0, 14, 1, 10, 0, 0}}}; + return allVersions; +} + +Version::Version(int versionNumber, std::initializer_list alignmentPatternCenters, const std::array& ecBlocks) + : _versionNumber(versionNumber), _alignmentPatternCenters(alignmentPatternCenters), _ecBlocks(ecBlocks), _isMicro(false) { _totalCodewords = ecBlocks[0].totalDataCodewords(); } -const Version * -Version::VersionForNumber(int versionNumber) +Version::Version(int versionNumber, const std::array& ecBlocks) + : _versionNumber(versionNumber), _ecBlocks(ecBlocks), _isMicro(true) +{ + _totalCodewords = ecBlocks[0].totalDataCodewords(); +} + +const Version* Version::VersionForNumber(int versionNumber, bool isMicro) { - if (versionNumber < 1 || versionNumber > 40) { + if (versionNumber < 1 || versionNumber > (isMicro ? 4 : 40)) { //throw std::invalid_argument("Version should be in range [1-40]."); return nullptr; } - return &AllVersions()[versionNumber - 1]; + return &(isMicro ? AllMicroVersions() : AllVersions())[versionNumber - 1]; } -const Version * -Version::ProvisionalVersionForDimension(int dimension) +const Version* Version::ProvisionalVersionForDimension(int dimension, bool isMicro) { - if (dimension % 4 != 1) { + if (dimension % DimensionStep(isMicro) != 1) { //throw std::invalid_argument("Unexpected dimension"); return nullptr; } - return VersionForNumber((dimension - 17) / 4); + return VersionForNumber((dimension - DimensionOffset(isMicro)) / DimensionStep(isMicro), isMicro); } - -const Version * -Version::DecodeVersionInformation(int versionBits) +const Version* Version::DecodeVersionInformation(int versionBits) { int bestDifference = std::numeric_limits::max(); int bestVersion = 0; @@ -358,34 +360,43 @@ BitMatrix Version::buildFunctionPattern() const // Top left finder pattern + separator + format bitMatrix.setRegion(0, 0, 9, 9); - // Top right finder pattern + separator + format - bitMatrix.setRegion(dimension - 8, 0, 8, 9); - // Bottom left finder pattern + separator + format - bitMatrix.setRegion(0, dimension - 8, 9, 8); - // Alignment patterns - size_t max = _alignmentPatternCenters.size(); - for (size_t x = 0; x < max; ++x) { - int i = _alignmentPatternCenters[x] - 2; - for (size_t y = 0; y < max; ++y) { - if ((x == 0 && (y == 0 || y == max - 1)) || (x == max - 1 && y == 0)) { - // No alignment patterns near the three finder patterns - continue; + if (!_isMicro) { + // Top right finder pattern + separator + format + bitMatrix.setRegion(dimension - 8, 0, 8, 9); + // Bottom left finder pattern + separator + format + bitMatrix.setRegion(0, dimension - 8, 9, 8); + + // Alignment patterns + size_t max = _alignmentPatternCenters.size(); + for (size_t x = 0; x < max; ++x) { + int i = _alignmentPatternCenters[x] - 2; + for (size_t y = 0; y < max; ++y) { + if ((x == 0 && (y == 0 || y == max - 1)) || (x == max - 1 && y == 0)) { + // No alignment patterns near the three finder patterns + continue; + } + bitMatrix.setRegion(_alignmentPatternCenters[y] - 2, i, 5, 5); } - bitMatrix.setRegion(_alignmentPatternCenters[y] - 2, i, 5, 5); } - } - // Vertical timing pattern - bitMatrix.setRegion(6, 9, 1, dimension - 17); - // Horizontal timing pattern - bitMatrix.setRegion(9, 6, dimension - 17, 1); + // Vertical timing pattern + bitMatrix.setRegion(6, 9, 1, dimension - 17); + // Horizontal timing pattern + bitMatrix.setRegion(9, 6, dimension - 17, 1); + + if (_versionNumber > 6) { + // Version info, top right + bitMatrix.setRegion(dimension - 11, 0, 3, 6); + // Version info, bottom left + bitMatrix.setRegion(0, dimension - 11, 6, 3); + } + } else { + // Vertical timing pattern + bitMatrix.setRegion(9, 0, dimension - 9, 1); - if (_versionNumber > 6) { - // Version info, top right - bitMatrix.setRegion(dimension - 11, 0, 3, 6); - // Version info, bottom left - bitMatrix.setRegion(0, dimension - 11, 6, 3); + // Horizontal timing pattern + bitMatrix.setRegion(0, 9, 1, dimension - 9); } return bitMatrix; diff --git a/core/src/qrcode/QRVersion.h b/core/src/qrcode/QRVersion.h index 1c415fd71b..024f1a7387 100644 --- a/core/src/qrcode/QRVersion.h +++ b/core/src/qrcode/QRVersion.h @@ -1,20 +1,10 @@ -#pragma once /* * Copyright 2016 Nu-book Inc. * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include "QRECB.h" #include "QRErrorCorrectionLevel.h" @@ -37,49 +27,49 @@ namespace QRCode { class Version { public: - int versionNumber() const { - return _versionNumber; - } + int versionNumber() const { return _versionNumber; } - const std::vector& alignmentPatternCenters() const { - return _alignmentPatternCenters; - } - - int totalCodewords() const { - return _totalCodewords; - } - - int dimensionForVersion() const { - return 17 + 4 * _versionNumber; - } - - const ECBlocks & ecBlocksForLevel(ErrorCorrectionLevel ecLevel) const { - return _ecBlocks[(int)ecLevel]; - } + const std::vector& alignmentPatternCenters() const { return _alignmentPatternCenters; } + + int totalCodewords() const { return _totalCodewords; } + + int dimensionForVersion() const { return DimensionOfVersion(_versionNumber, _isMicro); } + + const ECBlocks& ecBlocksForLevel(ErrorCorrectionLevel ecLevel) const { return _ecBlocks[(int)ecLevel]; } BitMatrix buildFunctionPattern() const; + bool isMicroQRCode() const { return _isMicro; } + + static constexpr int DimensionStep(bool isMicro) { return std::array{4, 2}[isMicro]; } + static constexpr int DimensionOffset(bool isMicro) { return std::array{17, 9}[isMicro]; } + static constexpr int DimensionOfVersion(int version, bool isMicro) + { + return DimensionOffset(isMicro) + DimensionStep(isMicro) * version; + } + /** - *

Deduces version information purely from QR Code dimensions.

+ *

Deduces version information purely from micro QR or QR Code dimensions.

* * @param dimension dimension in modules * @return Version for a QR Code of that dimension - * @throws FormatException if dimension is not 1 mod 4 */ - static const Version* ProvisionalVersionForDimension(int dimension); + static const Version* ProvisionalVersionForDimension(int dimension, bool isMicro = false); - static const Version* VersionForNumber(int versionNumber); + static const Version* VersionForNumber(int versionNumber, bool isMicro = false); static const Version* DecodeVersionInformation(int versionBits); - private: int _versionNumber; std::vector _alignmentPatternCenters; std::array _ecBlocks; int _totalCodewords; + bool _isMicro; Version(int versionNumber, std::initializer_list alignmentPatternCenters, const std::array &ecBlocks); + Version(int versionNumber, const std::array& ecBlocks); static const Version* AllVersions(); + static const Version* AllMicroVersions(); }; } // QRCode diff --git a/core/src/qrcode/QRWriter.cpp b/core/src/qrcode/QRWriter.cpp index daf97e3b50..8f0597cab3 100644 --- a/core/src/qrcode/QRWriter.cpp +++ b/core/src/qrcode/QRWriter.cpp @@ -1,19 +1,8 @@ /* * Copyright 2016 Huy Cuong Nguyen * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "QRWriter.h" @@ -22,6 +11,7 @@ #include "QREncodeResult.h" #include "QREncoder.h" #include "QRErrorCorrectionLevel.h" +#include "TextUtfEncoding.h" #include #include @@ -30,18 +20,16 @@ namespace ZXing::QRCode { static const int QUIET_ZONE_SIZE = 4; -Writer::Writer() : - _margin(QUIET_ZONE_SIZE), - _ecLevel(ErrorCorrectionLevel::Low), - _encoding(CharacterSet::Unknown), - _version(0), - _useGs1Format(false), - _maskPattern(-1) -{ -} +Writer::Writer() + : _margin(QUIET_ZONE_SIZE), + _ecLevel(ErrorCorrectionLevel::Low), + _encoding(CharacterSet::Unknown), + _version(0), + _useGs1Format(false), + _maskPattern(-1) +{} -BitMatrix -Writer::encode(const std::wstring& contents, int width, int height) const +BitMatrix Writer::encode(const std::wstring& contents, int width, int height) const { if (contents.empty()) { throw std::invalid_argument("Found empty contents"); @@ -55,4 +43,9 @@ Writer::encode(const std::wstring& contents, int width, int height) const return Inflate(std::move(code.matrix), width, height, _margin); } +BitMatrix Writer::encode(const std::string& contents, int width, int height) const +{ + return encode(TextUtfEncoding::FromUtf8(contents), width, height); +} + } // namespace ZXing::QRCode diff --git a/core/src/qrcode/QRWriter.h b/core/src/qrcode/QRWriter.h index c5a12aaae3..d088c8bc20 100644 --- a/core/src/qrcode/QRWriter.h +++ b/core/src/qrcode/QRWriter.h @@ -1,20 +1,10 @@ -#pragma once /* * Copyright 2016 Huy Cuong Nguyen * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include @@ -68,6 +58,7 @@ class Writer } BitMatrix encode(const std::wstring& contents, int width, int height) const; + BitMatrix encode(const std::string& contents, int width, int height) const; private: int _margin; diff --git a/core/src/textcodec/JPTextEncoder.cpp b/core/src/textcodec/JPTextEncoder.cpp index 26cf744d8f..d909ad666f 100644 --- a/core/src/textcodec/JPTextEncoder.cpp +++ b/core/src/textcodec/JPTextEncoder.cpp @@ -37,6 +37,8 @@ #include "JPTextEncoder.h" +#include + /* * This data is derived from Unicode 1.1, * JIS X 0208 (1990) to Unicode mapping table version 0.9 . diff --git a/example/CMakeLists.txt b/example/CMakeLists.txt index ec593db9ae..36d663a67f 100644 --- a/example/CMakeLists.txt +++ b/example/CMakeLists.txt @@ -3,13 +3,7 @@ set (CMAKE_CXX_STANDARD 11) zxing_add_package_stb() -if (BUILD_READERS) - add_executable (ZXingReader ZXingReader.cpp) - - target_link_libraries (ZXingReader ZXing::ZXing stb::stb) - - add_test(NAME ZXingReaderTest COMMAND ZXingReader -fast -format qrcode "${CMAKE_SOURCE_DIR}/test/samples/qrcode-1/1.png") -endif() +include (GNUInstallDirs) if (BUILD_WRITERS) add_executable (ZXingWriter ZXingWriter.cpp) @@ -17,22 +11,33 @@ if (BUILD_WRITERS) target_link_libraries (ZXingWriter ZXing::ZXing stb::stb) add_test(NAME ZXingWriterTest COMMAND ZXingWriter qrcode "I have the best words." test.png) + + install(TARGETS ZXingWriter DESTINATION ${CMAKE_INSTALL_BINDIR}) endif() +if (BUILD_READERS) + add_executable (ZXingReader ZXingReader.cpp) + + target_link_libraries (ZXingReader ZXing::ZXing stb::stb) + + add_test(NAME ZXingReaderTest COMMAND ZXingReader -fast -format qrcode test.png) # see above + + install(TARGETS ZXingReader DESTINATION ${CMAKE_INSTALL_BINDIR}) +endif() if (BUILD_READERS) find_package(Qt5 COMPONENTS Gui Multimedia Quick) set(CMAKE_AUTOMOC ON) set(CMAKE_AUTORCC ON) - if (TARGET Qt5::Gui) + if (TARGET Qt::Gui) add_executable (ZXingQtReader ZXingQtReader.cpp ZXingQtReader.h) - target_link_libraries(ZXingQtReader ZXing::ZXing Qt5::Gui) + target_link_libraries(ZXingQtReader ZXing::ZXing Qt::Gui) endif() - if (TARGET Qt5::Multimedia) + if (TARGET Qt::Multimedia AND TARGET Qt::Quick) add_executable(ZXingQtCamReader ZXingQtCamReader.cpp ZXingQtCamReader.qrc ZXingQtReader.h) - target_link_libraries(ZXingQtCamReader ZXing::ZXing Qt5::Gui Qt5::Multimedia Qt5::Quick) + target_link_libraries(ZXingQtCamReader ZXing::ZXing Qt::Gui Qt::Multimedia Qt::Quick) endif() find_package(OpenCV) diff --git a/example/ZXingOpenCV.cpp b/example/ZXingOpenCV.cpp index 7507068ba7..21411cf779 100644 --- a/example/ZXingOpenCV.cpp +++ b/example/ZXingOpenCV.cpp @@ -1,18 +1,7 @@ /* * Copyright 2021 Axel Waggershauser - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +*/ +// SPDX-License-Identifier: Apache-2.0 #include "ZXingOpenCV.h" @@ -32,9 +21,9 @@ int main() else while (waitKey(25) != 27) { cap >> image; - auto res = ReadBarcode(image); - if (res.isValid()) - DrawResult(image, res); + auto results = ReadBarcodes(image); + for (auto& r : results) + DrawResult(image, r); imshow("Display window", image); } diff --git a/example/ZXingOpenCV.h b/example/ZXingOpenCV.h index b096b0d770..3987458b43 100644 --- a/example/ZXingOpenCV.h +++ b/example/ZXingOpenCV.h @@ -1,22 +1,13 @@ -#pragma once /* - * Copyright 2021 Axel Waggershauser - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Copyright 2020 Axel Waggershauser */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#define ZX_USE_UTF8 1 // see Result.h #include "ReadBarcode.h" -#include "TextUtfEncoding.h" #include @@ -37,9 +28,9 @@ inline ZXing::ImageView ImageViewFromMat(const cv::Mat& image) return {image.data, image.cols, image.rows, fmt}; } -inline ZXing::Result ReadBarcode(const cv::Mat& image, const ZXing::DecodeHints& hints = {}) +inline ZXing::Results ReadBarcodes(const cv::Mat& image, const ZXing::DecodeHints& hints = {}) { - return ZXing::ReadBarcode(ImageViewFromMat(image), hints); + return ZXing::ReadBarcodes(ImageViewFromMat(image), hints); } inline void DrawResult(cv::Mat& img, ZXing::Result res) @@ -51,6 +42,5 @@ inline void DrawResult(cv::Mat& img, ZXing::Result res) int npts = contour.size(); cv::polylines(img, &pts, &npts, 1, true, CV_RGB(0, 255, 0)); - cv::putText(img, ZXing::TextUtfEncoding::ToUtf8(res.text()), cv::Point(10, 20), cv::FONT_HERSHEY_DUPLEX, 0.5, - CV_RGB(0, 255, 0)); + cv::putText(img, res.text(), zx2cv(pos[3]) + cv::Point(0, 20), cv::FONT_HERSHEY_DUPLEX, 0.5, CV_RGB(0, 255, 0)); } diff --git a/example/ZXingQtCamReader.qml b/example/ZXingQt5CamReader.qml similarity index 82% rename from example/ZXingQtCamReader.qml rename to example/ZXingQt5CamReader.qml index 9a90cf20d6..467bb18a63 100644 --- a/example/ZXingQtCamReader.qml +++ b/example/ZXingQt5CamReader.qml @@ -1,18 +1,7 @@ /* * Copyright 2020 Axel Waggershauser - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 import QtQuick 2.12 import QtQuick.Window 2.12 @@ -36,12 +25,13 @@ Window { interval: 2000 } - VideoFilter { - id: zxingFilter + BarcodeReader { + id: barcodeReader - formats: (oneDSwitch.checked ? (ZXing.OneDCodes) : ZXing.None) | (twoDSwitch.checked ? (ZXing.TwoDCodes) : ZXing.None) + formats: (linearSwitch.checked ? (ZXing.LinearCodes) : ZXing.None) | (matrixSwitch.checked ? (ZXing.MatrixCodes) : ZXing.None) tryRotate: tryRotateSwitch.checked tryHarder: tryHarderSwitch.checked + tryDownscale: tryDownscaleSwitch.checked // callback with parameter 'result', called for every successfully processed frame // onFoundBarcode: {} @@ -100,7 +90,7 @@ Window { id: videoOutput Layout.fillHeight: true Layout.fillWidth: true - filters: [zxingFilter] + filters: [barcodeReader] source: camera autoOrientation: true @@ -144,11 +134,13 @@ Window { ColumnLayout { anchors.right: parent.right + anchors.bottom: parent.bottom Switch {id: tryRotateSwitch; text: qsTr("Try Rotate"); checked: true } Switch {id: tryHarderSwitch; text: qsTr("Try Harder"); checked: true } - Switch {id: oneDSwitch; text: qsTr("1D Codes"); checked: true } - Switch {id: twoDSwitch; text: qsTr("2D Codes"); checked: true } + Switch {id: tryDownscaleSwitch; text: qsTr("Try Downscale"); checked: true } + Switch {id: linearSwitch; text: qsTr("Linear Codes"); checked: true } + Switch {id: matrixSwitch; text: qsTr("Matrix Codes"); checked: true } } } } diff --git a/example/ZXingQt6CamReader.qml b/example/ZXingQt6CamReader.qml new file mode 100644 index 0000000000..9234ae1882 --- /dev/null +++ b/example/ZXingQt6CamReader.qml @@ -0,0 +1,148 @@ +/* + * Copyright 2022 Axel Waggershauser + */ +// SPDX-License-Identifier: Apache-2.0 + +import QtQuick +import QtQuick.Window +import QtQuick.Controls +import QtQuick.Layouts +import QtQuick.Shapes +import QtMultimedia +import ZXing + +Window { + visible: true + width: 640 + height: 480 + title: Qt.application.name + + property var nullPoints: [Qt.point(0,0), Qt.point(0,0), Qt.point(0,0), Qt.point(0,0)] + property var points: nullPoints + + Timer { + id: resetInfo + interval: 2000 + } + + BarcodeReader { + id: barcodeReader + videoSink: videoOutput.videoSink + + formats: (linearSwitch.checked ? (ZXing.LinearCodes) : ZXing.None) | (matrixSwitch.checked ? (ZXing.MatrixCodes) : ZXing.None) + tryRotate: tryRotateSwitch.checked + tryHarder: tryHarderSwitch.checked + tryDownscale: tryDownscaleSwitch.checked + + // callback with parameter 'result', called for every successfully processed frame + // onFoundBarcode: {} + + // callback with parameter 'result', called for every processed frame + onNewResult: { + points = result.isValid + ? [result.position.topLeft, result.position.topRight, result.position.bottomRight, result.position.bottomLeft] + : nullPoints + + if (result.isValid) + resetInfo.restart() + + if (result.isValid || !resetInfo.running) + info.text = qsTr("Format: \t %1 \nText: \t %2 \nError: \t %3 \nTime: \t %4 ms").arg(result.formatName).arg(result.text).arg(result.status).arg(result.runTime) + +// console.log(result) + } + } + + MediaDevices { + id: devices + } + + Camera { + id: camera + cameraDevice: devices.videoInputs[camerasComboBox.currentIndex] ? devices.videoInputs[camerasComboBox.currentIndex] : devices.defaultVideoInput + focusMode: Camera.FocusModeAutoNear + onErrorOccurred: console.log("camera error:" + errorString) + } + + CaptureSession { + id: captureSession + camera: camera + videoOutput: videoOutput + } + + ColumnLayout { + anchors.fill: parent + + RowLayout { + Layout.fillWidth: true + Layout.fillHeight: false + visible: devices.videoInputs.length > 1 + Label { + text: qsTr("Camera: ") + Layout.fillWidth: false + } + ComboBox { + id: camerasComboBox + Layout.fillWidth: true + model: devices.videoInputs + textRole: "displayName" + currentIndex: 0 + } + } + + VideoOutput { + id: videoOutput + Layout.fillHeight: true + Layout.fillWidth: true + +// Shape { +// id: polygon +// anchors.fill: parent +// visible: points.length == 4 +// ShapePath { +// strokeWidth: 3 +// strokeColor: "red" +// strokeStyle: ShapePath.SolidLine +// fillColor: "transparent" +// //TODO: really? I don't know qml... +// startX: videoOutput.mapPointToItem(points[3]).x +// startY: videoOutput.mapPointToItem(points[3]).y +// PathLine { +// x: videoOutput.mapPointToItem(points[0]).x +// y: videoOutput.mapPointToItem(points[0]).y +// } +// PathLine { +// x: videoOutput.mapPointToItem(points[1]).x +// y: videoOutput.mapPointToItem(points[1]).y +// } +// PathLine { +// x: videoOutput.mapPointToItem(points[2]).x +// y: videoOutput.mapPointToItem(points[2]).y +// } +// PathLine { +// x: videoOutput.mapPointToItem(points[3]).x +// y: videoOutput.mapPointToItem(points[3]).y +// } +// } +// } + + Label { + id: info + color: "white" + padding: 10 + background: Rectangle { color: "#80808080" } + } + + ColumnLayout { + anchors.right: parent.right + anchors.bottom: parent.bottom + + Switch {id: tryRotateSwitch; text: qsTr("Try Rotate"); checked: true } + Switch {id: tryHarderSwitch; text: qsTr("Try Harder"); checked: true } + Switch {id: tryDownscaleSwitch; text: qsTr("Try Downscale"); checked: true } + Switch {id: linearSwitch; text: qsTr("Linear Codes"); checked: true } + Switch {id: matrixSwitch; text: qsTr("Matrix Codes"); checked: true } + } + } + } +} diff --git a/example/ZXingQtCamReader.cpp b/example/ZXingQtCamReader.cpp index db11009b25..3815bfe43b 100644 --- a/example/ZXingQtCamReader.cpp +++ b/example/ZXingQtCamReader.cpp @@ -1,18 +1,7 @@ /* * Copyright 2020 Axel Waggershauser - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +*/ +// SPDX-License-Identifier: Apache-2.0 #include #include @@ -21,14 +10,20 @@ int main(int argc, char *argv[]) { +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); +#endif ZXingQt::registerQmlAndMetaTypes(); QGuiApplication app(argc, argv); app.setApplicationName("ZXingQtCamReader"); QQmlApplicationEngine engine; - engine.load(QUrl(QStringLiteral("qrc:/ZXingQtCamReader.qml"))); +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + engine.load(QUrl(QStringLiteral("qrc:/ZXingQt5CamReader.qml"))); +#else + engine.load(QUrl(QStringLiteral("qrc:/ZXingQt6CamReader.qml"))); +#endif if (engine.rootObjects().isEmpty()) return -1; diff --git a/example/ZXingQtCamReader.qrc b/example/ZXingQtCamReader.qrc index 967e6ec7d1..b6b772c75c 100644 --- a/example/ZXingQtCamReader.qrc +++ b/example/ZXingQtCamReader.qrc @@ -1,5 +1,6 @@ - ZXingQtCamReader.qml + ZXingQt5CamReader.qml + ZXingQt6CamReader.qml diff --git a/example/ZXingQtReader.cpp b/example/ZXingQtReader.cpp index dedd621780..757cabd87c 100644 --- a/example/ZXingQtReader.cpp +++ b/example/ZXingQtReader.cpp @@ -1,18 +1,7 @@ /* * Copyright 2020 Axel Waggershauser - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +*/ +// SPDX-License-Identifier: Apache-2.0 #include "ZXingQtReader.h" @@ -37,15 +26,18 @@ int main(int argc, char* argv[]) } auto hints = DecodeHints() - .setFormats(BarcodeFormat::QRCode) + .setFormats(BarcodeFormat::Any) .setTryRotate(false) - .setBinarizer(Binarizer::FixedThreshold); + .setMaxNumberOfSymbols(10); - auto result = ReadBarcode(fileImage, hints); + auto results = ReadBarcodes(fileImage, hints); - qDebug() << "Text: " << result.text(); - qDebug() << "Format: " << result.format(); - qDebug() << "Error: " << result.status(); + for (auto& result : results) { + qDebug() << "Text: " << result.text(); + qDebug() << "Format: " << result.format(); + qDebug() << "Content:" << result.contentType(); + qDebug() << ""; + } - return result.isValid() ? 0 : 1; + return results.isEmpty() ? 1 : 0; } diff --git a/example/ZXingQtReader.h b/example/ZXingQtReader.h index 8a316ca206..a181a4b1a3 100644 --- a/example/ZXingQtReader.h +++ b/example/ZXingQtReader.h @@ -1,28 +1,26 @@ -#pragma once /* * Copyright 2020 Axel Waggershauser - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once + +#define ZX_USE_UTF8 1 // see Result.h #include "ReadBarcode.h" #include #include #include +#include #ifdef QT_MULTIMEDIA_LIB +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) #include +#else +#include +#include +#endif #include #endif @@ -38,37 +36,33 @@ Q_NAMESPACE enum class BarcodeFormat { None = 0, ///< Used as a return value if no valid barcode has been detected - Aztec = (1 << 0), ///< Aztec (2D) - Codabar = (1 << 1), ///< Codabar (1D) - Code39 = (1 << 2), ///< Code39 (1D) - Code93 = (1 << 3), ///< Code93 (1D) - Code128 = (1 << 4), ///< Code128 (1D) + Aztec = (1 << 0), ///< Aztec + Codabar = (1 << 1), ///< Codabar + Code39 = (1 << 2), ///< Code39 + Code93 = (1 << 3), ///< Code93 + Code128 = (1 << 4), ///< Code128 DataBar = (1 << 5), ///< GS1 DataBar, formerly known as RSS 14 DataBarExpanded = (1 << 6), ///< GS1 DataBar Expanded, formerly known as RSS EXPANDED - DataMatrix = (1 << 7), ///< DataMatrix (2D) - EAN8 = (1 << 8), ///< EAN-8 (1D) - EAN13 = (1 << 9), ///< EAN-13 (1D) - ITF = (1 << 10), ///< ITF (Interleaved Two of Five) (1D) - MaxiCode = (1 << 11), ///< MaxiCode (2D) - PDF417 = (1 << 12), ///< PDF417 (1D) or (2D) - QRCode = (1 << 13), ///< QR Code (2D) - UPCA = (1 << 14), ///< UPC-A (1D) - UPCE = (1 << 15), ///< UPC-E (1D) - - OneDCodes = Codabar | Code39 | Code93 | Code128 | EAN8 | EAN13 | ITF | DataBar | DataBarExpanded | UPCA | UPCE, - TwoDCodes = Aztec | DataMatrix | MaxiCode | PDF417 | QRCode, + DataMatrix = (1 << 7), ///< DataMatrix + EAN8 = (1 << 8), ///< EAN-8 + EAN13 = (1 << 9), ///< EAN-13 + ITF = (1 << 10), ///< ITF (Interleaved Two of Five) + MaxiCode = (1 << 11), ///< MaxiCode + PDF417 = (1 << 12), ///< PDF417 or + QRCode = (1 << 13), ///< QR Code + UPCA = (1 << 14), ///< UPC-A + UPCE = (1 << 15), ///< UPC-E + MicroQRCode = (1 << 16), ///< Micro QR Code + + LinearCodes = Codabar | Code39 | Code93 | Code128 | EAN8 | EAN13 | ITF | DataBar | DataBarExpanded | UPCA | UPCE, + MatrixCodes = Aztec | DataMatrix | MaxiCode | PDF417 | QRCode | MicroQRCode, }; -enum class DecodeStatus -{ - NoError = 0, - NotFound, - FormatError, - ChecksumError, -}; +enum class ContentType { Text, Binary, Mixed, GS1, ISO15434, UnknownECI }; + #else using ZXing::BarcodeFormat; -using ZXing::DecodeStatus; +using ZXing::ContentType; #endif using ZXing::DecodeHints; @@ -76,7 +70,7 @@ using ZXing::Binarizer; using ZXing::BarcodeFormats; Q_ENUM_NS(BarcodeFormat) -Q_ENUM_NS(DecodeStatus) +Q_ENUM_NS(ContentType) template QDebug operator<<(QDebug dbg, const T& v) @@ -106,22 +100,21 @@ class Result : private ZXing::Result Q_PROPERTY(BarcodeFormat format READ format) Q_PROPERTY(QString formatName READ formatName) Q_PROPERTY(QString text READ text) - Q_PROPERTY(QByteArray rawBytes READ rawBytes) + Q_PROPERTY(QByteArray bytes READ bytes) Q_PROPERTY(bool isValid READ isValid) - Q_PROPERTY(DecodeStatus status READ status) + Q_PROPERTY(ContentType contentType READ contentType) Q_PROPERTY(Position position READ position) QString _text; - QByteArray _rawBytes; + QByteArray _bytes; Position _position; public: - Result() : ZXing::Result(ZXing::DecodeStatus::NotFound) {} // required for qmetatype machinery + Result() = default; // required for qmetatype machinery explicit Result(ZXing::Result&& r) : ZXing::Result(std::move(r)) { - _text = QString::fromWCharArray(ZXing::Result::text().c_str()); - _rawBytes = QByteArray(reinterpret_cast(ZXing::Result::rawBytes().data()), - Size(ZXing::Result::rawBytes())); + _text = QString::fromStdString(ZXing::Result::text()); + _bytes = QByteArray(reinterpret_cast(ZXing::Result::bytes().data()), Size(ZXing::Result::bytes())); auto& pos = ZXing::Result::position(); auto qp = [&pos](int i) { return QPoint(pos[i].x, pos[i].y); }; _position = {qp(0), qp(1), qp(2), qp(3)}; @@ -130,10 +123,10 @@ class Result : private ZXing::Result using ZXing::Result::isValid; BarcodeFormat format() const { return static_cast(ZXing::Result::format()); } - DecodeStatus status() const { return static_cast(ZXing::Result::status()); } + ContentType contentType() const { return static_cast(ZXing::Result::contentType()); } QString formatName() const { return QString::fromStdString(ZXing::ToString(ZXing::Result::format())); } const QString& text() const { return _text; } - const QByteArray& rawBytes() const { return _rawBytes; } + const QByteArray& bytes() const { return _bytes; } const Position& position() const { return _position; } // For debugging/development @@ -141,7 +134,15 @@ class Result : private ZXing::Result Q_PROPERTY(int runTime MEMBER runTime) }; -inline Result ReadBarcode(const QImage& img, const DecodeHints& hints = {}) +inline QList QListResults(ZXing::Results&& zxres) +{ + QList res; + for (auto&& r : zxres) + res.push_back(Result(std::move(r))); + return res; +} + +inline QList ReadBarcodes(const QImage& img, const DecodeHints& hints = {}) { using namespace ZXing; @@ -163,33 +164,51 @@ inline Result ReadBarcode(const QImage& img, const DecodeHints& hints = {}) }; auto exec = [&](const QImage& img) { - return Result(ZXing::ReadBarcode( - {img.bits(), img.width(), img.height(), ImgFmtFromQImg(img), img.bytesPerLine()}, hints)); + return QListResults(ZXing::ReadBarcodes( + {img.bits(), img.width(), img.height(), ImgFmtFromQImg(img), static_cast(img.bytesPerLine())}, hints)); }; - return ImgFmtFromQImg(img) == ImageFormat::None ? exec(img.convertToFormat(QImage::Format_RGBX8888)) : exec(img); + return ImgFmtFromQImg(img) == ImageFormat::None ? exec(img.convertToFormat(QImage::Format_Grayscale8)) : exec(img); +} + +inline Result ReadBarcode(const QImage& img, const DecodeHints& hints = {}) +{ + auto res = ReadBarcodes(img, DecodeHints(hints).setMaxNumberOfSymbols(1)); + return !res.isEmpty() ? res.takeFirst() : Result(); } #ifdef QT_MULTIMEDIA_LIB -inline Result ReadBarcode(const QVideoFrame& frame, const DecodeHints& hints = {}) +inline QList ReadBarcodes(const QVideoFrame& frame, const DecodeHints& hints = {}) { using namespace ZXing; auto img = frame; // shallow copy just get access to non-const map() function +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) if (!frame.isValid() || !img.map(QAbstractVideoBuffer::ReadOnly)){ +#else + if (!frame.isValid() || !img.map(QVideoFrame::ReadOnly)){ +#endif qWarning() << "invalid QVideoFrame: could not map memory"; return {}; } - //TODO c++17: SCOPE_EXIT([&] { img.unmap(); }); + auto unmap = qScopeGuard([&] { img.unmap(); }); ImageFormat fmt = ImageFormat::None; int pixStride = 0; int pixOffset = 0; +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) +#define FORMAT(F5, F6) QVideoFrame::Format_##F5 +#define FIRST_PLANE +#else +#define FORMAT(F5, F6) QVideoFrameFormat::Format_##F6 +#define FIRST_PLANE 0 +#endif + switch (img.pixelFormat()) { - case QVideoFrame::Format_ARGB32: - case QVideoFrame::Format_ARGB32_Premultiplied: - case QVideoFrame::Format_RGB32: + case FORMAT(ARGB32, ARGB8888): + case FORMAT(ARGB32_Premultiplied, ARGB8888_Premultiplied): + case FORMAT(RGB32, RGBX8888): #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN fmt = ImageFormat::BGRX; #else @@ -197,11 +216,9 @@ inline Result ReadBarcode(const QVideoFrame& frame, const DecodeHints& hints = { #endif break; - case QVideoFrame::Format_RGB24: fmt = ImageFormat::RGB; break; - - case QVideoFrame::Format_BGRA32: - case QVideoFrame::Format_BGRA32_Premultiplied: - case QVideoFrame::Format_BGR32: + case FORMAT(BGRA32, BGRA8888): + case FORMAT(BGRA32_Premultiplied, BGRA8888_Premultiplied): + case FORMAT(BGR32, BGRX8888): #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN fmt = ImageFormat::RGBX; #else @@ -209,10 +226,17 @@ inline Result ReadBarcode(const QVideoFrame& frame, const DecodeHints& hints = { #endif break; +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + case QVideoFrame::Format_RGB24: fmt = ImageFormat::RGB; break; case QVideoFrame::Format_BGR24: fmt = ImageFormat::BGR; break; + case QVideoFrame::Format_YUV444: fmt = ImageFormat::Lum, pixStride = 3; break; +#else + case QVideoFrameFormat::Format_P010: + case QVideoFrameFormat::Format_P016: fmt = ImageFormat::Lum, pixStride = 1; break; +#endif - case QVideoFrame::Format_AYUV444: - case QVideoFrame::Format_AYUV444_Premultiplied: + case FORMAT(AYUV444, AYUV): + case FORMAT(AYUV444_Premultiplied, AYUV_Premultiplied): #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN fmt = ImageFormat::Lum, pixStride = 4, pixOffset = 3; #else @@ -220,23 +244,22 @@ inline Result ReadBarcode(const QVideoFrame& frame, const DecodeHints& hints = { #endif break; - case QVideoFrame::Format_YUV444: fmt = ImageFormat::Lum, pixStride = 3; break; - case QVideoFrame::Format_YUV420P: - case QVideoFrame::Format_NV12: - case QVideoFrame::Format_NV21: - case QVideoFrame::Format_IMC1: - case QVideoFrame::Format_IMC2: - case QVideoFrame::Format_IMC3: - case QVideoFrame::Format_IMC4: - case QVideoFrame::Format_YV12: fmt = ImageFormat::Lum; break; - case QVideoFrame::Format_UYVY: fmt = ImageFormat::Lum, pixStride = 2, pixOffset = 1; break; - case QVideoFrame::Format_YUYV: fmt = ImageFormat::Lum, pixStride = 2; break; - - case QVideoFrame::Format_Y8: fmt = ImageFormat::Lum; break; - case QVideoFrame::Format_Y16: fmt = ImageFormat::Lum, pixStride = 2, pixOffset = 1; break; + case FORMAT(YUV420P, YUV420P): + case FORMAT(NV12, NV12): + case FORMAT(NV21, NV21): + case FORMAT(IMC1, IMC1): + case FORMAT(IMC2, IMC2): + case FORMAT(IMC3, IMC3): + case FORMAT(IMC4, IMC4): + case FORMAT(YV12, YV12): fmt = ImageFormat::Lum; break; + case FORMAT(UYVY, UYVY): fmt = ImageFormat::Lum, pixStride = 2, pixOffset = 1; break; + case FORMAT(YUYV, YUYV): fmt = ImageFormat::Lum, pixStride = 2; break; + + case FORMAT(Y8, Y8): fmt = ImageFormat::Lum; break; + case FORMAT(Y16, Y16): fmt = ImageFormat::Lum, pixStride = 2, pixOffset = 1; break; #if (QT_VERSION >= QT_VERSION_CHECK(5, 13, 0)) - case QVideoFrame::Format_ABGR32: + case FORMAT(ABGR32, ABGR8888): #if Q_BYTE_ORDER == Q_LITTLE_ENDIAN fmt = ImageFormat::RGBX; #else @@ -245,25 +268,30 @@ inline Result ReadBarcode(const QVideoFrame& frame, const DecodeHints& hints = { break; #endif #if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) - case QVideoFrame::Format_YUV422P: fmt = ImageFormat::Lum; break; + case FORMAT(YUV422P, YUV422P): fmt = ImageFormat::Lum; break; #endif default: break; } - Result res; if (fmt != ImageFormat::None) { - res = Result( - ZXing::ReadBarcode({img.bits() + pixOffset, img.width(), img.height(), fmt, img.bytesPerLine(), pixStride}, - hints)); + return QListResults(ZXing::ReadBarcodes( + {img.bits(FIRST_PLANE) + pixOffset, img.width(), img.height(), fmt, img.bytesPerLine(FIRST_PLANE), pixStride}, hints)); } else { - auto qfmt = QVideoFrame::imageFormatFromPixelFormat(img.pixelFormat()); - if (qfmt != QImage::Format_Invalid) - res = ReadBarcode(QImage(img.bits(), img.width(), img.height(), qfmt), hints); +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + if (QVideoFrame::imageFormatFromPixelFormat(img.pixelFormat()) != QImage::Format_Invalid) + return ReadBarcodes(img.image(), hints); + qWarning() << "unsupported QVideoFrame::pixelFormat"; + return {}; +#else + return ReadBarcodes(img.toImage(), hints); +#endif } +} - img.unmap(); - - return res; +inline Result ReadBarcode(const QVideoFrame& frame, const DecodeHints& hints = {}) +{ + auto res = ReadBarcodes(frame, DecodeHints(hints).setMaxNumberOfSymbols(1)); + return !res.isEmpty() ? res.takeFirst() : Result(); } #define ZQ_PROPERTY(Type, name, setter) \ @@ -279,14 +307,21 @@ public: \ } \ Q_SIGNAL void name##Changed(); -class VideoFilter : public QAbstractVideoFilter, private DecodeHints + +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) +class BarcodeReader : public QAbstractVideoFilter, private DecodeHints +#else +class BarcodeReader : public QObject, private DecodeHints +#endif { Q_OBJECT public: - VideoFilter(QObject* parent = nullptr) : QAbstractVideoFilter(parent) {} - - QVideoFilterRunnable* createFilterRunnable() override; +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + BarcodeReader(QObject* parent = nullptr) : QAbstractVideoFilter(parent) {} +#else + BarcodeReader(QObject* parent = nullptr) : QObject(parent) {} +#endif // TODO: find out how to properly expose QFlags to QML // simply using ZQ_PROPERTY(BarcodeFormats, formats, setFormats) @@ -309,9 +344,10 @@ class VideoFilter : public QAbstractVideoFilter, private DecodeHints ZQ_PROPERTY(bool, tryRotate, setTryRotate) ZQ_PROPERTY(bool, tryHarder, setTryHarder) + ZQ_PROPERTY(bool, tryDownscale, setTryDownscale) public slots: - Result process(const QVideoFrame& image) + ZXingQt::Result process(const QVideoFrame& image) { QElapsedTimer t; t.start(); @@ -327,18 +363,41 @@ public slots: } signals: - void newResult(Result result); - void foundBarcode(Result result); + void newResult(ZXingQt::Result result); + void foundBarcode(ZXingQt::Result result); + +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) +public: + QVideoFilterRunnable *createFilterRunnable() override; +#else +private: + QVideoSink *_sink = nullptr; + +public: + void setVideoSink(QVideoSink* sink) { + if (_sink == sink) + return; + + if (_sink) + disconnect(_sink, nullptr, this, nullptr); + + _sink = sink; + connect(_sink, &QVideoSink::videoFrameChanged, this, &BarcodeReader::process); + } + Q_PROPERTY(QVideoSink* videoSink WRITE setVideoSink) +#endif + }; #undef ZX_PROPERTY +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) class VideoFilterRunnable : public QVideoFilterRunnable { - VideoFilter* _filter = nullptr; + BarcodeReader* _filter = nullptr; public: - explicit VideoFilterRunnable(VideoFilter* filter) : _filter(filter) {} + explicit VideoFilterRunnable(BarcodeReader* filter) : _filter(filter) {} QVideoFrame run(QVideoFrame* input, const QVideoSurfaceFormat& /*surfaceFormat*/, RunFlags /*flags*/) override { @@ -347,10 +406,11 @@ class VideoFilterRunnable : public QVideoFilterRunnable } }; -inline QVideoFilterRunnable* VideoFilter::createFilterRunnable() +inline QVideoFilterRunnable* BarcodeReader::createFilterRunnable() { return new VideoFilterRunnable(this); } +#endif #endif // QT_MULTIMEDIA_LIB @@ -369,7 +429,7 @@ namespace ZXingQt { inline void registerQmlAndMetaTypes() { qRegisterMetaType("BarcodeFormat"); - qRegisterMetaType("DecodeStatus"); + qRegisterMetaType("ContentType"); // supposedly the Q_DECLARE_METATYPE should be used with the overload without a custom name // but then the qml side complains about "unregistered type" @@ -378,7 +438,7 @@ inline void registerQmlAndMetaTypes() qmlRegisterUncreatableMetaObject( ZXingQt::staticMetaObject, "ZXing", 1, 0, "ZXing", "Access to enums & flags only"); - qmlRegisterType("ZXing", 1, 0, "VideoFilter"); + qmlRegisterType("ZXing", 1, 0, "BarcodeReader"); } } // namespace ZXingQt diff --git a/example/ZXingReader.cpp b/example/ZXingReader.cpp index 15150e2897..163cf39858 100644 --- a/example/ZXingReader.cpp +++ b/example/ZXingReader.cpp @@ -1,18 +1,10 @@ /* * Copyright 2016 Nu-book Inc. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. +* Copyright 2019 Axel Waggershauser */ +// SPDX-License-Identifier: Apache-2.0 + +#define ZX_USE_UTF8 1 // see Result.h #include "ReadBarcode.h" #include "TextUtfEncoding.h" @@ -33,19 +25,22 @@ #include using namespace ZXing; -using namespace TextUtfEncoding; static void PrintUsage(const char* exePath) { - std::cout << "Usage: " << exePath << " [-fast] [-norotate] [-format ] [-pngout ] [-ispure] [-1] ...\n" + std::cout << "Usage: " << exePath << " [options] ...\n" << " -fast Skip some lines/pixels during detection (faster)\n" << " -norotate Don't try rotated image during detection (faster)\n" << " -noscale Don't try downscaled images during detection (faster)\n" - << " -format Only detect given format(s) (faster)\n" + << " -format \n" + << " Only detect given format(s) (faster)\n" << " -ispure Assume the image contains only a 'pure'/perfect code (faster)\n" - << " -1 Print only file name, text and status on one line per file/barcode\n" - << " -escape Escape non-graphical characters in angle brackets (ignored for -1 option, which always escapes)\n" - << " -pngout Write a copy of the input image with barcodes outlined by a green line\n" + << " -errors Include results with errors (like checksum error)\n" + << " -1 Print only file name, content/error on one line per file/barcode (implies '-escape')\n" + << " -escape Escape non-graphical characters in angle brackets\n" + << " -bytes Write (only) the bytes content of the symbol(s) to stdout\n" + << " -pngout \n" + << " Write a copy of the input image with barcodes outlined by a green line\n" << "\n" << "Supported formats are:\n"; for (auto f : BarcodeFormats::all()) { @@ -54,7 +49,7 @@ static void PrintUsage(const char* exePath) std::cout << "Formats can be lowercase, with or without '-', separated by ',' and/or '|'\n"; } -static bool ParseOptions(int argc, char* argv[], DecodeHints& hints, bool& oneLine, bool& angleEscape, +static bool ParseOptions(int argc, char* argv[], DecodeHints& hints, bool& oneLine, bool& angleEscape, bool& bytesOnly, std::vector& filePaths, std::string& outPath) { for (int i = 1; i < argc; ++i) { @@ -67,6 +62,8 @@ static bool ParseOptions(int argc, char* argv[], DecodeHints& hints, bool& oneLi } else if (strcmp(argv[i], "-ispure") == 0) { hints.setIsPure(true); hints.setBinarizer(Binarizer::FixedThreshold); + } else if (strcmp(argv[i], "-errors") == 0) { + hints.setReturnErrors(true); } else if (strcmp(argv[i], "-format") == 0) { if (++i == argc) return false; @@ -80,6 +77,8 @@ static bool ParseOptions(int argc, char* argv[], DecodeHints& hints, bool& oneLi oneLine = true; } else if (strcmp(argv[i], "-escape") == 0) { angleEscape = true; + } else if (strcmp(argv[i], "-bytes") == 0) { + bytesOnly = true; } else if (strcmp(argv[i], "-pngout") == 0) { if (++i == argc) return false; @@ -99,7 +98,7 @@ std::ostream& operator<<(std::ostream& os, const Position& points) return os; } -void drawLine(const ImageView& iv, PointI a, PointI b) +void drawLine(const ImageView& iv, PointI a, PointI b, bool error) { int steps = maxAbsComponent(b - a); PointF dir = bresenhamDirection(PointF(b - a)); @@ -107,40 +106,47 @@ void drawLine(const ImageView& iv, PointI a, PointI b) for (int i = 0; i < steps; ++i) { auto p = PointI(centered(a + i * dir)); auto* dst = const_cast(iv.data(p.x, p.y)); - dst[R] = dst[B] = 0; - dst[G] = 0xff; + dst[R] = error ? 0xff : 0; + dst[G] = error ? 0 : 0xff; + dst[B] = 0; } } -void drawRect(const ImageView& image, const Position& pos) +void drawRect(const ImageView& image, const Position& pos, bool error) { for (int i = 0; i < 4; ++i) - drawLine(image, pos[i], pos[(i + 1) % 4]); + drawLine(image, pos[i], pos[(i + 1) % 4], error); +} + +std::string escapeNonGraphical(const std::string& str) +{ + return TextUtfEncoding::ToUtf8(TextUtfEncoding::FromUtf8(str), true); } int main(int argc, char* argv[]) { DecodeHints hints; std::vector filePaths; + Results allResults; std::string outPath; bool oneLine = false; bool angleEscape = false; + bool bytesOnly = false; int ret = 0; - if (!ParseOptions(argc, argv, hints, oneLine, angleEscape, filePaths, outPath)) { + if (!ParseOptions(argc, argv, hints, oneLine, angleEscape, bytesOnly, filePaths, outPath)) { PrintUsage(argv[0]); return -1; } hints.setEanAddOnSymbol(EanAddOnSymbol::Read); - if (oneLine) - angleEscape = true; - if (angleEscape) std::setlocale(LC_CTYPE, "en_US.UTF-8"); // Needed so `std::iswgraph()` in `ToUtf8(angleEscape)` does not 'swallow' all printable non-ascii utf8 chars + std::cout.setf(std::ios::boolalpha); + for (const auto& filePath : filePaths) { int width, height, channels; std::unique_ptr buffer(stbi_load(filePath.c_str(), &width, &height, &channels, 3), stbi_image_free); @@ -154,21 +160,33 @@ int main(int argc, char* argv[]) // if we did not find anything, insert a dummy to produce some output for each file if (results.empty()) - results.emplace_back(DecodeStatus::NotFound); + results.emplace_back(); + + allResults.insert(allResults.end(), results.begin(), results.end()); + if (filePath == filePaths.back()) { + auto merged = MergeStructuredAppendSequences(allResults); + // report all merged sequences as part of the last file to make the logic not overly complicated here + results.insert(results.end(), merged.begin(), merged.end()); + } for (auto&& result : results) { if (!outPath.empty()) - drawRect(image, result.position()); + drawRect(image, result.position(), bool(result.error())); - ret |= static_cast(result.status()); + ret |= static_cast(result.error().type()); + + if (bytesOnly) { + std::cout.write(reinterpret_cast(result.bytes().data()), result.bytes().size()); + continue; + } if (oneLine) { std::cout << filePath << " " << ToString(result.format()); if (result.isValid()) - std::cout << " \"" << ToUtf8(result.text(), angleEscape) << "\""; - else if (result.format() != BarcodeFormat::None) - std::cout << " " << ToString(result.status()); + std::cout << " \"" << escapeNonGraphical(result.text()) << "\""; + else if (result.error()) + std::cout << " " << ToString(result.error()); std::cout << "\n"; continue; } @@ -181,37 +199,50 @@ int main(int argc, char* argv[]) std::cout << "File: " << filePath << "\n"; firstFile = false; } - std::cout << "Text: \"" << ToUtf8(result.text(), angleEscape) << "\"\n" + + if (result.format() == BarcodeFormat::None) { + std::cout << "No barcode found\n"; + continue; + } + + std::cout << "Text: \"" << (angleEscape ? escapeNonGraphical(result.text()) : result.text()) << "\"\n" + << "Bytes: " << ToHex(result.bytes()) << "\n" + << "BytesECI: " << ToHex(result.bytesECI()) << "\n" << "Format: " << ToString(result.format()) << "\n" << "Identifier: " << result.symbologyIdentifier() << "\n" + << "Content: " << ToString(result.contentType()) << "\n" + << "HasECI: " << result.hasECI() << "\n" << "Position: " << result.position() << "\n" << "Rotation: " << result.orientation() << " deg\n" - << "IsMirrored: " << (result.isMirrored() ? "true" : "false") << "\n" - << "Error: " << ToString(result.status()) << "\n"; + << "IsMirrored: " << result.isMirrored() << "\n"; auto printOptional = [](const char* key, const std::string& v) { if (!v.empty()) std::cout << key << v << "\n"; }; - printOptional("EC Level: ", ToUtf8(result.ecLevel())); + printOptional("EC Level: ", result.ecLevel()); + printOptional("Error: ", ToString(result.error())); if (result.lineCount()) std::cout << "Lines: " << result.lineCount() << "\n"; if ((BarcodeFormat::EAN13 | BarcodeFormat::EAN8 | BarcodeFormat::UPCA | BarcodeFormat::UPCE) .testFlag(result.format())) { - printOptional("Country: ", GTIN::LookupCountryIdentifier(ToUtf8(result.text()), result.format())); + printOptional("Country: ", GTIN::LookupCountryIdentifier(result.text(), result.format())); printOptional("Add-On: ", GTIN::EanAddOn(result)); printOptional("Price: ", GTIN::Price(GTIN::EanAddOn(result))); printOptional("Issue #: ", GTIN::IssueNr(GTIN::EanAddOn(result))); - } else if (result.format() == BarcodeFormat::ITF && result.text().length() == 14) { - printOptional("Country: ", GTIN::LookupCountryIdentifier(ToUtf8(result.text()), result.format())); + } else if (result.format() == BarcodeFormat::ITF && Size(result.bytes()) == 14) { + printOptional("Country: ", GTIN::LookupCountryIdentifier(result.text(), result.format())); } if (result.isPartOfSequence()) std::cout << "Structured Append: symbol " << result.sequenceIndex() + 1 << " of " << result.sequenceSize() << " (parity/id: '" << result.sequenceId() << "')\n"; + else if (result.sequenceSize() > 0) + std::cout << "Structured Append: merged result from " << result.sequenceSize() << " symbols (parity/id: '" + << result.sequenceId() << "')\n"; if (result.readerInit()) std::cout << "Reader Initialisation/Programming\n"; diff --git a/example/ZXingWriter.cpp b/example/ZXingWriter.cpp index cd6188bcf8..80a62d5c58 100644 --- a/example/ZXingWriter.cpp +++ b/example/ZXingWriter.cpp @@ -1,28 +1,19 @@ /* * Copyright 2016 Nu-book Inc. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "BarcodeFormat.h" #include "BitMatrix.h" +#include "BitMatrixIO.h" +#include "CharacterSet.h" #include "MultiFormatWriter.h" #include "TextUtfEncoding.h" -#include "CharacterSetECI.h" #include #include #include +#include #include #include @@ -40,10 +31,11 @@ static void PrintUsage(const char* exePath) << " -ecc Error correction level, [0-8]\n" << "\n" << "Supported formats are:\n"; - for (auto f : BarcodeFormats::all()) { + for (auto f : BarcodeFormatsFromString("Aztec Codabar Code39 Code93 Code128 DataMatrix EAN8 EAN13 ITF PDF417 QRCode UPCA UPCE")) std::cout << " " << ToString(f) << "\n"; - } - std::cout << "Format can be lowercase letters, with or without '-'.\n"; + + std::cout << "Format can be lowercase letters, with or without '-'.\n" + << "Output format is determined by file name, supported are png, jpg and svg.\n"; } static bool ParseSize(std::string str, int* width, int* height) @@ -81,7 +73,7 @@ static bool ParseOptions(int argc, char* argv[], int* width, int* height, int* m } else if (strcmp(argv[i], "-encoding") == 0) { if (++i == argc) return false; - *encoding = CharacterSetECI::CharsetFromName(argv[i]); + *encoding = CharacterSetFromString(argv[i]); } else if (nonOptArgCount == 0) { *format = BarcodeFormatFromString(argv[i]); if (*format == BarcodeFormat::None) { @@ -129,7 +121,8 @@ int main(int argc, char* argv[]) try { auto writer = MultiFormatWriter(format).setMargin(margin).setEncoding(encoding).setEccLevel(eccLevel); - auto bitmap = ToMatrix(writer.encode(TextUtfEncoding::FromUtf8(text), width, height)); + auto matrix = writer.encode(TextUtfEncoding::FromUtf8(text), width, height); + auto bitmap = ToMatrix(matrix); auto ext = GetExtension(filePath); int success = 0; @@ -137,6 +130,8 @@ int main(int argc, char* argv[]) success = stbi_write_png(filePath.c_str(), bitmap.width(), bitmap.height(), 1, bitmap.data(), 0); } else if (ext == "jpg" || ext == "jpeg") { success = stbi_write_jpg(filePath.c_str(), bitmap.width(), bitmap.height(), 1, bitmap.data(), 0); + } else if (ext == "svg") { + success = (std::ofstream(filePath) << ToSVG(matrix)).good(); } if (!success) { diff --git a/test/blackbox/BlackboxTestRunner.cpp b/test/blackbox/BlackboxTestRunner.cpp index 9899cef628..aec499faa4 100644 --- a/test/blackbox/BlackboxTestRunner.cpp +++ b/test/blackbox/BlackboxTestRunner.cpp @@ -1,27 +1,16 @@ /* * Copyright 2016 Nu-book Inc. * Copyright 2019 Axel Waggershauser -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "BlackboxTestRunner.h" +#include "DecoderResult.h" #include "ImageLoader.h" #include "ReadBarcode.h" -#include "TextUtfEncoding.h" #include "ThresholdBinarizer.h" -#include "ZXContainerAlgorithms.h" +#include "ZXAlgorithms.h" #include "pdf417/PDFReader.h" #include "qrcode/QRReader.h" @@ -59,9 +48,7 @@ namespace { TC tc[2] = {}; int rotation = 0; // The rotation in degrees clockwise to use for this test. - TestCase(int mntf, int mnts, int mmf, int mms, int r) - : tc{{"fast", mntf, mmf}, {"slow", mnts, mms}}, rotation(r) - {} + TestCase(int mntf, int mnts, int mmf, int mms, int r) : tc{{"fast", mntf, mmf}, {"slow", mnts, mms}}, rotation(r) {} TestCase(int mntf, int mnts, int r) : TestCase(mntf, mnts, 0, 0, r) {} TestCase(int mntp, int mmp, PureTag) : tc{{"pure", mntp, mmp}} {} }; @@ -76,12 +63,12 @@ namespace { // Helper for `compareResult()` - map `key` to Result property, converting value to std::string static std::string getResultValue(const Result& result, const std::string& key) { + if (key == "contentType") + return ToString(result.contentType()); if (key == "ecLevel") - return TextUtfEncoding::ToUtf8(result.ecLevel()); + return result.ecLevel(); if (key == "orientation") return std::to_string(result.orientation()); - if (key == "numBits") - return std::to_string(result.numBits()); if (key == "symbologyIdentifier") return result.symbologyIdentifier(); if (key == "sequenceSize") @@ -149,14 +136,15 @@ static std::string checkResult(const fs::path& imgPath, std::string_view expecte } if (auto expected = readFile(".txt")) { - auto utf8Result = TextUtfEncoding::ToUtf8(result.text()); + auto utf8Result = result.text(); return utf8Result != *expected ? fmt::format("Content mismatch: expected '{}' but got '{}'", *expected, utf8Result) : ""; } if (auto expected = readFile(".bin")) { - std::string latin1Result(result.text().length(), '\0'); - std::transform(result.text().begin(), result.text().end(), latin1Result.begin(), [](wchar_t c) { return static_cast(c); }); - return latin1Result != *expected ? fmt::format("Content mismatch: expected '{}' but got '{}'", *expected, latin1Result) : ""; + ByteArray binaryExpected(*expected); + return result.bytes() != binaryExpected + ? fmt::format("Content mismatch: expected '{}' but got '{}'", ToHex(binaryExpected), ToHex(result.bytes())) + : ""; } return "Error reading file"; @@ -168,7 +156,7 @@ static int totalImageLoadTime = 0; int timeSince(std::chrono::steady_clock::time_point startTime) { auto duration = std::chrono::steady_clock::now() - startTime; - return static_cast(std::chrono::duration_cast(duration).count()); + return narrow_cast(std::chrono::duration_cast(duration).count()); } // pre-load images into cache, so the disc io time does not end up in the timing measurement @@ -185,8 +173,7 @@ static void printPositiveTestStats(int imageCount, const TestCase::TC& tc) { int passCount = imageCount - Size(tc.misReadFiles) - Size(tc.notDetectedFiles); - fmt::print(" | {}: {:3} of {:3}, misread {} of {}", tc.name, passCount, tc.minPassCount, Size(tc.misReadFiles), - tc.maxMisreads); + fmt::print(" | {}: {:3} of {:3}, misread {} of {}", tc.name, passCount, tc.minPassCount, Size(tc.misReadFiles), tc.maxMisreads); if (passCount < tc.minPassCount && !tc.notDetectedFiles.empty()) { fmt::print("\nFAILED: Not detected ({}):", tc.name); @@ -217,8 +204,8 @@ static std::vector getImagesInDirectory(const fs::path& directory) return result; } -static void doRunTests( - const fs::path& directory, std::string_view format, int totalTests, const std::vector& tests, DecodeHints hints) +static void doRunTests(const fs::path& directory, std::string_view format, int totalTests, const std::vector& tests, + DecodeHints hints) { auto imgPaths = getImagesInDirectory(directory); auto folderName = directory.stem(); @@ -259,36 +246,18 @@ static void doRunTests( static Result readMultiple(const std::vector& imgPaths, std::string_view format) { - std::list allResults; + Results allResults; for (const auto& imgPath : imgPaths) { - auto results = - ReadBarcodes(ImageLoader::load(imgPath), - DecodeHints().setFormats(BarcodeFormatFromString(format.data())).setTryDownscale(false)); + auto results = ReadBarcodes(ImageLoader::load(imgPath), + DecodeHints().setFormats(BarcodeFormatFromString(format.data())).setTryDownscale(false)); allResults.insert(allResults.end(), results.begin(), results.end()); } - if (allResults.empty()) - return Result(DecodeStatus::NotFound); - - allResults.sort([](const Result& r1, const Result& r2) { return r1.sequenceIndex() < r2.sequenceIndex(); }); - - if (allResults.back().sequenceSize() != Size(allResults) || - !std::all_of(allResults.begin(), allResults.end(), - [&](Result& it) { return it.sequenceId() == allResults.front().sequenceId(); })) - return Result(DecodeStatus::FormatError); - - std::wstring text; - for (const auto& r : allResults) - text.append(r.text()); - - const auto& first = allResults.front(); - StructuredAppendInfo sai{ first.sequenceIndex(), first.sequenceSize(), first.sequenceId() }; - return Result(std::move(text), {}, first.format(), std::string(first.symbologyIdentifier()), {}, std::move(sai), - first.readerInit()); + return MergeStructuredAppendSequence(allResults); } -static void doRunStructuredAppendTest( - const fs::path& directory, std::string_view format, int totalTests, const std::vector& tests) +static void doRunStructuredAppendTest(const fs::path& directory, std::string_view format, int totalTests, + const std::vector& tests) { auto imgPaths = getImagesInDirectory(directory); auto folderName = directory.stem(); @@ -301,8 +270,7 @@ static void doRunStructuredAppendTest( } if (Size(imageGroups) != totalTests) - fmt::print("TEST {} => Expected number of tests: {}, got: {} => FAILED\n", folderName, totalTests, - imageGroups.size()); + fmt::print("TEST {} => Expected number of tests: {}, got: {} => FAILED\n", folderName, totalTests, imageGroups.size()); for (auto& test : tests) { fmt::print("{:20} @ {:3}, {:3}", folderName.string(), test.rotation, Size(imgPaths)); @@ -339,7 +307,8 @@ int runBlackBoxTests(const fs::path& testPathPrefix, const std::set doRunTests(testPathPrefix / directory, format, total, tests, hints); }; - auto runStructuredAppendTest = [&](std::string_view directory, std::string_view format, int total, const std::vector& tests) { + auto runStructuredAppendTest = [&](std::string_view directory, std::string_view format, int total, + const std::vector& tests) { if (hasTest(directory)) doRunStructuredAppendTest(testPathPrefix / directory, format, total, tests); }; @@ -556,20 +525,22 @@ int runBlackBoxTests(const fs::path& testPathPrefix, const std::set }); runTests("rssexpanded-3", "DataBarExpanded", 118, { - { 118, 118, 0 }, - { 118, 118, 180 }, - { 118, 0, pure }, + // TODO: See HRIFromGS1. 13.png and 66.png are seemingly invalid symbols + { 116, 116, 0 }, + { 116, 116, 180 }, + { 116, 0, pure }, }); runTests("rssexpandedstacked-1", "DataBarExpanded", 65, { - { 60, 65, 0 }, - { 60, 65, 180 }, + // TODO: See HRIFromGS1. 13.png is seemingly invalid symbol + { 60, 64, 0 }, + { 60, 64, 180 }, { 60, 0, pure }, }); - runTests("rssexpandedstacked-2", "DataBarExpanded", 7, { - { 2, 7, 0 }, - { 2, 7, 180 }, + runTests("rssexpandedstacked-2", "DataBarExpanded", 2, { + { 2, 2, 0 }, + { 2, 2, 180 }, }); runTests("qrcode-1", "QRCode", 16, { @@ -620,30 +591,42 @@ int runBlackBoxTests(const fs::path& testPathPrefix, const std::set { 1, 1, 0 }, }); + runTests("microqrcode-1", "MicroQRCode", 16, { + { 15, 15, 0 }, + { 15, 15, 90 }, + { 15, 15, 180 }, + { 14, 14, 270 }, + { 9, 0, pure }, + }); + runTests("pdf417-1", "PDF417", 17, { - { 16, 16, 0 }, - { 1, 1, 90 }, - { 16, 16, 180 }, - { 1, 1, 270 }, + { 16, 17, 0 }, + { 1, 17, 90 }, + { 16, 17, 180 }, + { 1, 17, 270 }, { 17, 0, pure }, }); runTests("pdf417-2", "PDF417", 25, { { 25, 25, 0 }, + { 0, 25, 90 }, { 25, 25, 180 }, + { 0, 25, 270 }, }); runTests("pdf417-3", "PDF417", 16, { { 16, 16, 0 }, + { 0, 16, 90 }, { 16, 16, 180 }, + { 0, 16, 270 }, { 7, 0, pure }, }); - runStructuredAppendTest("pdf417-4", "PDF417", 2, { - { 2, 2, 0 }, + runStructuredAppendTest("pdf417-4", "PDF417", 3, { + { 3, 3, 0 }, }); - runTests("falsepositives-1", "None", 25, { + runTests("falsepositives-1", "None", 26, { { 0, 0, 0, 0, 0 }, { 0, 0, 0, 0, 90 }, { 0, 0, 0, 0, 180 }, diff --git a/test/blackbox/BlackboxTestRunner.h b/test/blackbox/BlackboxTestRunner.h index e1229a4508..a4527b100f 100644 --- a/test/blackbox/BlackboxTestRunner.h +++ b/test/blackbox/BlackboxTestRunner.h @@ -1,19 +1,9 @@ -#pragma once /* * Copyright 2016 Nu-book Inc. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include "ZXFilesystem.h" diff --git a/test/blackbox/CMakeLists.txt b/test/blackbox/CMakeLists.txt index f20f4127c7..2d7d9e3036 100644 --- a/test/blackbox/CMakeLists.txt +++ b/test/blackbox/CMakeLists.txt @@ -15,6 +15,7 @@ if (BUILD_READERS) ZXing::ZXing fmt::fmt stb::stb $<$,$,9.0>>:stdc++fs> ) + target_compile_definitions(ReaderTest PRIVATE ZX_USE_UTF8) add_test(NAME ReaderTest COMMAND ReaderTest ${CMAKE_CURRENT_SOURCE_DIR}/../samples) endif() diff --git a/test/blackbox/ImageLoader.cpp b/test/blackbox/ImageLoader.cpp index 51e0066886..1f1f073421 100644 --- a/test/blackbox/ImageLoader.cpp +++ b/test/blackbox/ImageLoader.cpp @@ -1,24 +1,13 @@ /* * Copyright 2016 Nu-book Inc. * Copyright 2019 Axel Waggersauser. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "ImageLoader.h" #include "BinaryBitmap.h" -#include "ReadBarcode.h" +#include "ImageView.h" #include #include diff --git a/test/blackbox/ImageLoader.h b/test/blackbox/ImageLoader.h index ff1497b690..1d96e71c3d 100644 --- a/test/blackbox/ImageLoader.h +++ b/test/blackbox/ImageLoader.h @@ -1,21 +1,11 @@ -#pragma once /* * Copyright 2016 Nu-book Inc. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once -#include "ReadBarcode.h" +#include "ImageView.h" #include "ZXFilesystem.h" namespace ZXing::Test::ImageLoader { diff --git a/test/blackbox/TestReaderMain.cpp b/test/blackbox/TestReaderMain.cpp index cabc70267f..31f9063092 100644 --- a/test/blackbox/TestReaderMain.cpp +++ b/test/blackbox/TestReaderMain.cpp @@ -1,24 +1,13 @@ /* * Copyright 2016 Nu-book Inc. * Copyright 2017 Axel Waggershauser -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "BlackboxTestRunner.h" #include "ImageLoader.h" -#include "TextUtfEncoding.h" -#include "ZXContainerAlgorithms.h" +#include "ReadBarcode.h" +#include "ZXAlgorithms.h" #include "ZXFilesystem.h" #include @@ -55,12 +44,12 @@ int main(int argc, char** argv) Result result = ReadBarcode(ImageLoader::load(argv[i]).rotated(rotation), hints); std::cout << argv[i] << ": "; if (result.isValid()) - std::cout << ToString(result.format()) << ": " << TextUtfEncoding::ToUtf8(result.text()) << "\n"; + std::cout << ToString(result.format()) << ": " << result.text() << "\n"; else std::cout << "FAILED\n"; if (result.isValid() && getenv("WRITE_TEXT")) { std::ofstream f(fs::path(argv[i]).replace_extension(".txt")); - f << TextUtfEncoding::ToUtf8(result.text()); + f << result.text(); } } return 0; diff --git a/test/blackbox/TestWriterMain.cpp b/test/blackbox/TestWriterMain.cpp index 8dfc63e841..420f0bf6ca 100644 --- a/test/blackbox/TestWriterMain.cpp +++ b/test/blackbox/TestWriterMain.cpp @@ -1,19 +1,8 @@ /* * Copyright 2016 Nu-book Inc. * Copyright 2019 Axel Waggershauser -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "BitMatrix.h" #include "MultiFormatWriter.h" @@ -34,7 +23,7 @@ void savePng(const BitMatrix& matrix, BarcodeFormat format) int main() { - std::wstring text = L"http://www.google.com/"; + std::string text = "http://www.google.com/"; for (auto format : { BarcodeFormat::Aztec, BarcodeFormat::DataMatrix, @@ -44,7 +33,7 @@ int main() savePng(MultiFormatWriter(format).encode(text, 200, 200), format); } - text = L"012345678901234567890123456789"; + text = "012345678901234567890123456789"; using FormatSpecs = std::vector>; for (const auto& [format, length] : FormatSpecs({ {BarcodeFormat::Codabar, 0}, diff --git a/test/blackbox/ZXFilesystem.h b/test/blackbox/ZXFilesystem.h index add9236e41..45f08d3455 100644 --- a/test/blackbox/ZXFilesystem.h +++ b/test/blackbox/ZXFilesystem.h @@ -1,19 +1,9 @@ -#pragma once /* * Copyright 2019 Axel Waggershauser. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #if __has_include() # include diff --git a/test/fuzz/fuzzDBEDecoder.cpp b/test/fuzz/fuzzDBEDecoder.cpp index 4a14761611..292a7b9ce7 100644 --- a/test/fuzz/fuzzDBEDecoder.cpp +++ b/test/fuzz/fuzzDBEDecoder.cpp @@ -1,3 +1,8 @@ +/* + * Copyright 2021 Axel Waggershauser + */ +// SPDX-License-Identifier: Apache-2.0 + #include #include diff --git a/test/fuzz/fuzzDMDecoder.cpp b/test/fuzz/fuzzDMDecoder.cpp index 455679c70c..6b4500d8c7 100644 --- a/test/fuzz/fuzzDMDecoder.cpp +++ b/test/fuzz/fuzzDMDecoder.cpp @@ -1,3 +1,8 @@ +/* + * Copyright 2021 Axel Waggershauser + */ +// SPDX-License-Identifier: Apache-2.0 + #include #include @@ -7,7 +12,7 @@ using namespace ZXing; namespace ZXing::DataMatrix::DecodedBitStreamParser { -DecoderResult Decode(ByteArray&& bytes, const std::string& characterSet); +DecoderResult Decode(ByteArray&& bytes, const bool isDMRE); } extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) @@ -18,7 +23,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) ByteArray ba; ba.insert(ba.begin(), data, data + size); try { - DataMatrix::DecodedBitStreamParser::Decode(std::move(ba), ""); + DataMatrix::DecodedBitStreamParser::Decode(std::move(ba), false); } catch (...) { } diff --git a/test/fuzz/fuzzDMEncoder.cpp b/test/fuzz/fuzzDMEncoder.cpp index 2d9d85c6fd..0a56d9b0fc 100644 --- a/test/fuzz/fuzzDMEncoder.cpp +++ b/test/fuzz/fuzzDMEncoder.cpp @@ -1,3 +1,8 @@ +/* + * Copyright 2021 Axel Waggershauser + */ +// SPDX-License-Identifier: Apache-2.0 + #include #include diff --git a/test/fuzz/fuzzODDecoders.cpp b/test/fuzz/fuzzODDecoders.cpp index df39599041..2ffd01392d 100644 --- a/test/fuzz/fuzzODDecoders.cpp +++ b/test/fuzz/fuzzODDecoders.cpp @@ -1,3 +1,8 @@ +/* + * Copyright 2021 Axel Waggershauser + */ +// SPDX-License-Identifier: Apache-2.0 + #include #include @@ -22,7 +27,7 @@ bool init() readers.emplace_back(new MultiUPCEANReader(hints)); readers.emplace_back(new Code39Reader(hints)); readers.emplace_back(new Code93Reader()); - readers.emplace_back(new Code128Reader(hints)); + readers.emplace_back(new Code128Reader()); readers.emplace_back(new ITFReader(hints)); readers.emplace_back(new CodabarReader(hints)); readers.emplace_back(new DataBarReader(hints)); diff --git a/test/samples/aztec-1/mixed-ecis-41x41.bin b/test/samples/aztec-1/mixed-ecis-41x41.bin new file mode 100644 index 0000000000..a51ee9f519 Binary files /dev/null and b/test/samples/aztec-1/mixed-ecis-41x41.bin differ diff --git a/test/samples/aztec-1/mixed-ecis-41x41.txt b/test/samples/aztec-1/mixed-ecis-41x41.txt deleted file mode 100644 index 6c534d58d7..0000000000 --- a/test/samples/aztec-1/mixed-ecis-41x41.txt +++ /dev/null @@ -1 +0,0 @@ -á¡ĦБĄテ点¡ðŒ¶é¾˜é¾¤Ã©ê°€ê°é½„،¢ \ No newline at end of file diff --git a/test/samples/code128-1/1.result.txt b/test/samples/code128-1/1.result.txt index 90af6c5d09..ec5103cdec 100644 --- a/test/samples/code128-1/1.result.txt +++ b/test/samples/code128-1/1.result.txt @@ -1 +1,2 @@ symbologyIdentifier=]C1 +contentType=GS1 diff --git a/test/samples/datamatrix-1/eci-mixed.bin b/test/samples/datamatrix-1/eci-mixed.bin new file mode 100644 index 0000000000..7f4b77e09b --- /dev/null +++ b/test/samples/datamatrix-1/eci-mixed.bin @@ -0,0 +1 @@ +á¡¡¡¡Í±ðŒ¶@@@@@@@@@@_ \ No newline at end of file diff --git a/test/samples/datamatrix-1/eci-mixed.result.txt b/test/samples/datamatrix-1/eci-mixed.result.txt new file mode 100644 index 0000000000..352fff3edf --- /dev/null +++ b/test/samples/datamatrix-1/eci-mixed.result.txt @@ -0,0 +1,2 @@ +symbologyIdentifier=]d1 +contentType=UnknownECI diff --git a/test/samples/datamatrix-1/eci-mixed.txt b/test/samples/datamatrix-1/eci-mixed.txt deleted file mode 100644 index 18e1efa017..0000000000 --- a/test/samples/datamatrix-1/eci-mixed.txt +++ /dev/null @@ -1 +0,0 @@ -á¡¡ĦĦͱðŒ¶@@@@@@@@@@_ \ No newline at end of file diff --git a/test/samples/datamatrix-1/gs1-figure-4.15.1-2-32x32.result.txt b/test/samples/datamatrix-1/gs1-figure-4.15.1-2-32x32.result.txt index c31c096dbb..1edb45e39f 100644 --- a/test/samples/datamatrix-1/gs1-figure-4.15.1-2-32x32.result.txt +++ b/test/samples/datamatrix-1/gs1-figure-4.15.1-2-32x32.result.txt @@ -1 +1,2 @@ symbologyIdentifier=]d2 +contentType=GS1 diff --git a/test/samples/datamatrix-3/dm-c.bin b/test/samples/datamatrix-3/dm-c.bin new file mode 100644 index 0000000000..18dbeccbc8 Binary files /dev/null and b/test/samples/datamatrix-3/dm-c.bin differ diff --git a/test/samples/datamatrix-3/dm-c.result.txt b/test/samples/datamatrix-3/dm-c.result.txt new file mode 100644 index 0000000000..d0aaba1474 --- /dev/null +++ b/test/samples/datamatrix-3/dm-c.result.txt @@ -0,0 +1 @@ +contentType=Binary diff --git a/test/samples/datamatrix-3/dm-c.txt b/test/samples/datamatrix-3/dm-c.txt deleted file mode 100644 index 427bebc63e..0000000000 Binary files a/test/samples/datamatrix-3/dm-c.txt and /dev/null differ diff --git a/test/samples/falsepositives-1/MQR-falsepositive.jpg b/test/samples/falsepositives-1/MQR-falsepositive.jpg new file mode 100644 index 0000000000..fdb661127f Binary files /dev/null and b/test/samples/falsepositives-1/MQR-falsepositive.jpg differ diff --git a/test/samples/maxicode-1/mode4-mixed-ecis.bin b/test/samples/maxicode-1/mode4-mixed-ecis.bin new file mode 100644 index 0000000000..c8ab77e10b Binary files /dev/null and b/test/samples/maxicode-1/mode4-mixed-ecis.bin differ diff --git a/test/samples/maxicode-1/mode4-mixed-ecis.txt b/test/samples/maxicode-1/mode4-mixed-ecis.txt deleted file mode 100644 index 9fcc6b661d..0000000000 --- a/test/samples/maxicode-1/mode4-mixed-ecis.txt +++ /dev/null @@ -1 +0,0 @@ -á¡ĦБĄテ点¡ðŒ¶é¾˜é¾¤Ã©ê°€ê°é½„ØŒ \ No newline at end of file diff --git a/test/samples/microqrcode-1/1.png b/test/samples/microqrcode-1/1.png new file mode 100644 index 0000000000..35c855d0d7 Binary files /dev/null and b/test/samples/microqrcode-1/1.png differ diff --git a/test/samples/microqrcode-1/1.txt b/test/samples/microqrcode-1/1.txt new file mode 100644 index 0000000000..121eab0377 --- /dev/null +++ b/test/samples/microqrcode-1/1.txt @@ -0,0 +1 @@ +Wikipedia \ No newline at end of file diff --git a/test/samples/microqrcode-1/11.jpg b/test/samples/microqrcode-1/11.jpg new file mode 100644 index 0000000000..bfff33fbba Binary files /dev/null and b/test/samples/microqrcode-1/11.jpg differ diff --git a/test/samples/microqrcode-1/11.txt b/test/samples/microqrcode-1/11.txt new file mode 100644 index 0000000000..64209c1239 --- /dev/null +++ b/test/samples/microqrcode-1/11.txt @@ -0,0 +1 @@ +Loser \ No newline at end of file diff --git a/test/samples/microqrcode-1/12.jpg b/test/samples/microqrcode-1/12.jpg new file mode 100644 index 0000000000..4724b6c948 Binary files /dev/null and b/test/samples/microqrcode-1/12.jpg differ diff --git a/test/samples/microqrcode-1/12.txt b/test/samples/microqrcode-1/12.txt new file mode 100644 index 0000000000..7d3298dfa5 --- /dev/null +++ b/test/samples/microqrcode-1/12.txt @@ -0,0 +1 @@ +SN888623311 \ No newline at end of file diff --git a/test/samples/microqrcode-1/3.jpg b/test/samples/microqrcode-1/3.jpg new file mode 100644 index 0000000000..9a984ddc09 Binary files /dev/null and b/test/samples/microqrcode-1/3.jpg differ diff --git a/test/samples/microqrcode-1/3.txt b/test/samples/microqrcode-1/3.txt new file mode 100644 index 0000000000..b513fa617f --- /dev/null +++ b/test/samples/microqrcode-1/3.txt @@ -0,0 +1 @@ +malgajninto \ No newline at end of file diff --git a/test/samples/microqrcode-1/7.jpg b/test/samples/microqrcode-1/7.jpg new file mode 100644 index 0000000000..d92a678bdc Binary files /dev/null and b/test/samples/microqrcode-1/7.jpg differ diff --git a/test/samples/microqrcode-1/7.txt b/test/samples/microqrcode-1/7.txt new file mode 100644 index 0000000000..ae75576b8f --- /dev/null +++ b/test/samples/microqrcode-1/7.txt @@ -0,0 +1 @@ +Victus \ No newline at end of file diff --git a/test/samples/microqrcode-1/9.jpg b/test/samples/microqrcode-1/9.jpg new file mode 100644 index 0000000000..682f4d11f3 Binary files /dev/null and b/test/samples/microqrcode-1/9.jpg differ diff --git a/test/samples/microqrcode-1/9.txt b/test/samples/microqrcode-1/9.txt new file mode 100644 index 0000000000..8dd8a1403c --- /dev/null +++ b/test/samples/microqrcode-1/9.txt @@ -0,0 +1 @@ +ezik \ No newline at end of file diff --git a/test/samples/microqrcode-1/M1-Numeric.png b/test/samples/microqrcode-1/M1-Numeric.png new file mode 100644 index 0000000000..8a7d18a480 Binary files /dev/null and b/test/samples/microqrcode-1/M1-Numeric.png differ diff --git a/test/samples/microqrcode-1/M1-Numeric.txt b/test/samples/microqrcode-1/M1-Numeric.txt new file mode 100644 index 0000000000..bd41cba781 --- /dev/null +++ b/test/samples/microqrcode-1/M1-Numeric.txt @@ -0,0 +1 @@ +12345 \ No newline at end of file diff --git a/test/samples/microqrcode-1/M2-Alpha.png b/test/samples/microqrcode-1/M2-Alpha.png new file mode 100644 index 0000000000..eefdaa3f5e Binary files /dev/null and b/test/samples/microqrcode-1/M2-Alpha.png differ diff --git a/test/samples/microqrcode-1/M2-Alpha.txt b/test/samples/microqrcode-1/M2-Alpha.txt new file mode 100644 index 0000000000..48b83b862e --- /dev/null +++ b/test/samples/microqrcode-1/M2-Alpha.txt @@ -0,0 +1 @@ +ABC \ No newline at end of file diff --git a/test/samples/microqrcode-1/M2-Numeric.png b/test/samples/microqrcode-1/M2-Numeric.png new file mode 100644 index 0000000000..ea9810f9fb Binary files /dev/null and b/test/samples/microqrcode-1/M2-Numeric.png differ diff --git a/test/samples/microqrcode-1/M2-Numeric.txt b/test/samples/microqrcode-1/M2-Numeric.txt new file mode 100644 index 0000000000..6a537b5b36 --- /dev/null +++ b/test/samples/microqrcode-1/M2-Numeric.txt @@ -0,0 +1 @@ +1234567890 \ No newline at end of file diff --git a/test/samples/microqrcode-1/M3-Binary.png b/test/samples/microqrcode-1/M3-Binary.png new file mode 100644 index 0000000000..889b4a3ae0 Binary files /dev/null and b/test/samples/microqrcode-1/M3-Binary.png differ diff --git a/test/samples/microqrcode-1/M3-Binary.txt b/test/samples/microqrcode-1/M3-Binary.txt new file mode 100644 index 0000000000..29f3003ab7 --- /dev/null +++ b/test/samples/microqrcode-1/M3-Binary.txt @@ -0,0 +1 @@ +E=mc² \ No newline at end of file diff --git a/test/samples/microqrcode-1/M3-Kanji.png b/test/samples/microqrcode-1/M3-Kanji.png new file mode 100644 index 0000000000..d8d0679091 Binary files /dev/null and b/test/samples/microqrcode-1/M3-Kanji.png differ diff --git a/test/samples/microqrcode-1/M3-Kanji.txt b/test/samples/microqrcode-1/M3-Kanji.txt new file mode 100644 index 0000000000..b40554e368 --- /dev/null +++ b/test/samples/microqrcode-1/M3-Kanji.txt @@ -0,0 +1 @@ +誠 \ No newline at end of file diff --git a/test/samples/microqrcode-1/M3-Mixed.png b/test/samples/microqrcode-1/M3-Mixed.png new file mode 100644 index 0000000000..5ae95b6877 Binary files /dev/null and b/test/samples/microqrcode-1/M3-Mixed.png differ diff --git a/test/samples/microqrcode-1/M3-Mixed.txt b/test/samples/microqrcode-1/M3-Mixed.txt new file mode 100644 index 0000000000..070ee250b1 --- /dev/null +++ b/test/samples/microqrcode-1/M3-Mixed.txt @@ -0,0 +1 @@ +1234 ABCD \ No newline at end of file diff --git a/test/samples/microqrcode-1/M4-Binary.png b/test/samples/microqrcode-1/M4-Binary.png new file mode 100644 index 0000000000..8f4ca80beb Binary files /dev/null and b/test/samples/microqrcode-1/M4-Binary.png differ diff --git a/test/samples/microqrcode-1/M4-Binary.txt b/test/samples/microqrcode-1/M4-Binary.txt new file mode 100644 index 0000000000..35aefb1756 --- /dev/null +++ b/test/samples/microqrcode-1/M4-Binary.txt @@ -0,0 +1 @@ +!"§$%&/()=?` \ No newline at end of file diff --git a/test/samples/microqrcode-1/M4-Mixed.png b/test/samples/microqrcode-1/M4-Mixed.png new file mode 100644 index 0000000000..e26ea016f6 Binary files /dev/null and b/test/samples/microqrcode-1/M4-Mixed.png differ diff --git a/test/samples/microqrcode-1/M4-Mixed.txt b/test/samples/microqrcode-1/M4-Mixed.txt new file mode 100644 index 0000000000..34cbb7729e --- /dev/null +++ b/test/samples/microqrcode-1/M4-Mixed.txt @@ -0,0 +1 @@ +1234 ABCD abcd \ No newline at end of file diff --git a/test/samples/microqrcode-1/MQR-needs-br-update.jpg b/test/samples/microqrcode-1/MQR-needs-br-update.jpg new file mode 100644 index 0000000000..26eddefec6 Binary files /dev/null and b/test/samples/microqrcode-1/MQR-needs-br-update.jpg differ diff --git a/test/samples/microqrcode-1/MQR-needs-br-update.txt b/test/samples/microqrcode-1/MQR-needs-br-update.txt new file mode 100644 index 0000000000..222d0af5dc --- /dev/null +++ b/test/samples/microqrcode-1/MQR-needs-br-update.txt @@ -0,0 +1 @@ +Micro QR Code \ No newline at end of file diff --git a/test/samples/microqrcode-1/NoQuietZone.png b/test/samples/microqrcode-1/NoQuietZone.png new file mode 100644 index 0000000000..f7a917df87 Binary files /dev/null and b/test/samples/microqrcode-1/NoQuietZone.png differ diff --git a/test/samples/microqrcode-1/NoQuietZone.txt b/test/samples/microqrcode-1/NoQuietZone.txt new file mode 100644 index 0000000000..bd41cba781 --- /dev/null +++ b/test/samples/microqrcode-1/NoQuietZone.txt @@ -0,0 +1 @@ +12345 \ No newline at end of file diff --git a/test/samples/pdf417-4/03-01.png b/test/samples/pdf417-4/03-01.png new file mode 100644 index 0000000000..3e54a6e9e2 Binary files /dev/null and b/test/samples/pdf417-4/03-01.png differ diff --git a/test/samples/pdf417-4/03.txt b/test/samples/pdf417-4/03.txt new file mode 100644 index 0000000000..b158215975 --- /dev/null +++ b/test/samples/pdf417-4/03.txt @@ -0,0 +1 @@ +US:$439.97;CN:ï¿¥ 3149.79;DE:444,90 €; \ No newline at end of file diff --git a/test/samples/qrcode-7/01.result.txt b/test/samples/qrcode-7/01.result.txt index 7867b23fec..0631ce5a33 100644 --- a/test/samples/qrcode-7/01.result.txt +++ b/test/samples/qrcode-7/01.result.txt @@ -1,6 +1,6 @@ symbologyIdentifier=]Q1 # ecLevel not set when "runStructuredAppendTest" sequenceSize=4 -# sequenceIndex set to first when "runStructuredAppendTest" -sequenceIndex=0 +# sequenceIndex set to -1 in MergeStructuredAppendResults +sequenceIndex=-1 sequenceId=95 diff --git a/test/samples/rssexpandedstacked-2/13.png b/test/samples/rssexpandedstacked-2/13.png deleted file mode 100644 index 21dc744571..0000000000 Binary files a/test/samples/rssexpandedstacked-2/13.png and /dev/null differ diff --git a/test/samples/rssexpandedstacked-2/13.txt b/test/samples/rssexpandedstacked-2/13.txt deleted file mode 100644 index 0429d93c29..0000000000 --- a/test/samples/rssexpandedstacked-2/13.txt +++ /dev/null @@ -1 +0,0 @@ -(01)90012345678908(3922)795888888888888888888888888888888888888888888888888888 \ No newline at end of file diff --git a/test/samples/rssexpandedstacked-2/19.png b/test/samples/rssexpandedstacked-2/19.png deleted file mode 100644 index f21183e01b..0000000000 Binary files a/test/samples/rssexpandedstacked-2/19.png and /dev/null differ diff --git a/test/samples/rssexpandedstacked-2/19.txt b/test/samples/rssexpandedstacked-2/19.txt deleted file mode 100644 index 8f0841f935..0000000000 --- a/test/samples/rssexpandedstacked-2/19.txt +++ /dev/null @@ -1 +0,0 @@ -(01)12345678901231(10)UNIVERSITY-OF-DEUSTO \ No newline at end of file diff --git a/test/samples/rssexpandedstacked-2/20.png b/test/samples/rssexpandedstacked-2/20.png deleted file mode 100644 index 7f5d8326ef..0000000000 Binary files a/test/samples/rssexpandedstacked-2/20.png and /dev/null differ diff --git a/test/samples/rssexpandedstacked-2/20.txt b/test/samples/rssexpandedstacked-2/20.txt deleted file mode 100644 index 89fda98695..0000000000 --- a/test/samples/rssexpandedstacked-2/20.txt +++ /dev/null @@ -1 +0,0 @@ -(01)12345678901231(10)PIRAMIDE-PROJECT \ No newline at end of file diff --git a/test/samples/rssexpandedstacked-2/22.png b/test/samples/rssexpandedstacked-2/22.png deleted file mode 100644 index 0e668916c4..0000000000 Binary files a/test/samples/rssexpandedstacked-2/22.png and /dev/null differ diff --git a/test/samples/rssexpandedstacked-2/22.txt b/test/samples/rssexpandedstacked-2/22.txt deleted file mode 100644 index 09d4208414..0000000000 --- a/test/samples/rssexpandedstacked-2/22.txt +++ /dev/null @@ -1 +0,0 @@ -(01)98898765432106(15)991231(3103)001750(10)12A(422)123(21)123456(423)012345678901 \ No newline at end of file diff --git a/test/samples/rssexpandedstacked-2/23.png b/test/samples/rssexpandedstacked-2/23.png deleted file mode 100644 index 95ddce318b..0000000000 Binary files a/test/samples/rssexpandedstacked-2/23.png and /dev/null differ diff --git a/test/samples/rssexpandedstacked-2/23.txt b/test/samples/rssexpandedstacked-2/23.txt deleted file mode 100644 index 5e76631589..0000000000 --- a/test/samples/rssexpandedstacked-2/23.txt +++ /dev/null @@ -1 +0,0 @@ -(15)991231(3103)001750(10)12A(422)123(21)123456(423)0123456789012 \ No newline at end of file diff --git a/test/unit/BarcodeFormatTest.cpp b/test/unit/BarcodeFormatTest.cpp index 425ce40066..9413314067 100644 --- a/test/unit/BarcodeFormatTest.cpp +++ b/test/unit/BarcodeFormatTest.cpp @@ -1,18 +1,7 @@ /* * Copyright 2020 Axel Waggershauser -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "BarcodeFormat.h" @@ -24,9 +13,11 @@ using namespace ZXing; TEST(BarcodeFormatTest, BarcodeFormat) { - EXPECT_EQ(ToString(BarcodeFormat::QRCode), std::string("QRCode")); - EXPECT_EQ(ToString(BarcodeFormat::None), std::string("None")); - EXPECT_EQ(ToString(BarcodeFormat::DataMatrix | BarcodeFormat::EAN13), std::string("DataMatrix|EAN-13")); + using namespace std::literals; + + EXPECT_EQ(ToString(BarcodeFormat::QRCode), "QRCode"s); + EXPECT_EQ(ToString(BarcodeFormat::None), "None"s); + EXPECT_EQ(ToString(BarcodeFormat::DataMatrix | BarcodeFormat::EAN13), "DataMatrix|EAN-13"); EXPECT_EQ(BarcodeFormat::EAN8, BarcodeFormatFromString("EAN_8")); EXPECT_EQ(BarcodeFormat::EAN8, BarcodeFormatFromString("EAN-8")); diff --git a/test/unit/BitArrayUtility.cpp b/test/unit/BitArrayUtility.cpp index a5d67f6586..e6ab50deb0 100644 --- a/test/unit/BitArrayUtility.cpp +++ b/test/unit/BitArrayUtility.cpp @@ -1,18 +1,7 @@ /* * Copyright 2017 Huy Cuong Nguyen -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "BitArrayUtility.h" #include "BitArray.h" diff --git a/test/unit/BitHacksTest.cpp b/test/unit/BitHacksTest.cpp index 554f55f8e7..8edfb96252 100644 --- a/test/unit/BitHacksTest.cpp +++ b/test/unit/BitHacksTest.cpp @@ -1,18 +1,7 @@ /* * Copyright 2018 Axel Waggershauser -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "BitHacks.h" diff --git a/test/unit/CMakeLists.txt b/test/unit/CMakeLists.txt index 1c33901a39..871bac6f76 100644 --- a/test/unit/CMakeLists.txt +++ b/test/unit/CMakeLists.txt @@ -13,7 +13,10 @@ add_executable (UnitTest PseudoRandom.h BitHacksTest.cpp CharacterSetECITest.cpp + ContentTest.cpp + ErrorTest.cpp GTINTest.cpp + GS1Test.cpp ReedSolomonTest.cpp TextDecoderTest.cpp TextUtfEncodingTest.cpp @@ -43,8 +46,9 @@ add_executable (UnitTest oned/ODITFWriterTest.cpp oned/ODUPCAWriterTest.cpp oned/ODUPCEWriterTest.cpp - oned/rss/ODRSSExpandedBinaryDecoderTest.cpp - oned/rss/ODRSSFieldParserTest.cpp + oned/ODDataBarExpandedBitDecoderTest.cpp + qrcode/MQRDecoderTest.cpp + qrcode/QRBitMatrixParserTest.cpp qrcode/QRDataMaskTest.cpp qrcode/QRDecodedBitStreamParserTest.cpp qrcode/QREncoderTest.cpp @@ -62,5 +66,6 @@ add_executable (UnitTest target_include_directories (UnitTest PRIVATE .) target_link_libraries (UnitTest ZXing::ZXing GTest::gtest_main GTest::gmock) +target_compile_definitions(UnitTest PRIVATE ZX_USE_UTF8) add_test(NAME UnitTest COMMAND UnitTest) diff --git a/test/unit/CharacterSetECITest.cpp b/test/unit/CharacterSetECITest.cpp index be587237d4..e34dd9640f 100644 --- a/test/unit/CharacterSetECITest.cpp +++ b/test/unit/CharacterSetECITest.cpp @@ -1,112 +1,32 @@ /* * Copyright 2021 gitlost -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 -#include "CharacterSetECI.h" +#include "CharacterSet.h" +#include "ECI.h" #include "gtest/gtest.h" #include "gmock/gmock.h" using namespace ZXing; -using namespace ZXing::CharacterSetECI; using namespace testing; -TEST(CharacterSetECITest, ValueForCharset) +TEST(CharacterSetECITest, Charset2ECI) { - EXPECT_EQ(ValueForCharset(CharacterSet::ISO8859_1), 3); - EXPECT_EQ(ValueForCharset(CharacterSet::ISO8859_2), 4); - EXPECT_EQ(ValueForCharset(CharacterSet::ASCII), 27); - EXPECT_EQ(ValueForCharset(CharacterSet::EUC_KR), 30); - EXPECT_EQ(ValueForCharset(CharacterSet::BINARY), 899); - EXPECT_EQ(ValueForCharset(CharacterSet::Unknown), -1); + EXPECT_EQ(ToInt(ToECI(CharacterSet::ISO8859_1)), 3); + EXPECT_EQ(ToInt(ToECI(CharacterSet::ISO8859_2)), 4); + EXPECT_EQ(ToInt(ToECI(CharacterSet::ASCII)), 27); + EXPECT_EQ(ToInt(ToECI(CharacterSet::EUC_KR)), 30); + EXPECT_EQ(ToInt(ToECI(CharacterSet::BINARY)), 899); + EXPECT_EQ(ToInt(ToECI(CharacterSet::Unknown)), -1); } -TEST(CharacterSetECITest, InitEncoding) +TEST(CharacterSetECITest, CharacterSetFromString) { - EXPECT_EQ(InitEncoding(std::string()), CharacterSet::ISO8859_1); - EXPECT_EQ(InitEncoding(std::string(), CharacterSet::ISO8859_2), CharacterSet::ISO8859_2); - EXPECT_EQ(InitEncoding(std::string("asdfasdf")), CharacterSet::ISO8859_1); - EXPECT_EQ(InitEncoding(std::string("asdfasdf"), CharacterSet::ISO8859_2), CharacterSet::ISO8859_2); - EXPECT_EQ(InitEncoding(std::string("ISO-8859-1")), CharacterSet::ISO8859_1); - EXPECT_EQ(InitEncoding(std::string("ISO-8859-2")), CharacterSet::ISO8859_2); - EXPECT_EQ(InitEncoding(std::string("UTF-16BE")), CharacterSet::UnicodeBig); - EXPECT_EQ(InitEncoding(std::string(), CharacterSet::Unknown), CharacterSet::Unknown); -} - -TEST(CharacterSetECITest, OnChangeAppendReset) -{ - { - std::string data; - std::wstring encoded; - - // Null - auto result = OnChangeAppendReset(3, encoded, data, CharacterSet::Unknown); - EXPECT_EQ(result, CharacterSet::ISO8859_1); - EXPECT_TRUE(data.empty()); - EXPECT_TRUE(encoded.empty()); - } - - { - static const uint8_t bytes[] = { 'A', 0xE9, 'Z' }; - std::string data(reinterpret_cast(&bytes), sizeof(bytes)); - std::wstring encoded; - - // Encoding change - auto result = OnChangeAppendReset(3, encoded, data, CharacterSet::Unknown); - EXPECT_EQ(result, CharacterSet::ISO8859_1); - EXPECT_TRUE(data.empty()); - EXPECT_EQ(encoded, std::wstring(L"A\u00E9Z")); - } - - { - static const uint8_t bytes[] = { 'A', 0xE9, 'Z' }; - std::string data(reinterpret_cast(&bytes), sizeof(bytes)); - std::wstring encoded; - - // Encoding same - auto result = OnChangeAppendReset(3, encoded, data, CharacterSet::ISO8859_1); - EXPECT_EQ(result, CharacterSet::ISO8859_1); - EXPECT_EQ(data, std::string("A\xE9Z")); - EXPECT_TRUE(encoded.empty()); - } - - { - CharacterSet result; - static const uint8_t bytes[] = { 'A', 0xE9, 'Z' }; - std::string data(reinterpret_cast(&bytes), sizeof(bytes)); - std::wstring encoded(L"A\u00E9Z"); - - // Encoding change - result = OnChangeAppendReset(20, encoded, data, CharacterSet::ISO8859_5); - EXPECT_EQ(result, CharacterSet::Shift_JIS); - EXPECT_TRUE(data.empty()); - EXPECT_EQ(encoded, std::wstring(L"A\u00E9ZA\u0449Z")); - - static const uint8_t bytes2[] = { 'A', 0x83, 0x65, 'Z' }; - std::string data2(reinterpret_cast(&bytes2), sizeof(bytes2)); - - // Encoding same - result = OnChangeAppendReset(20, encoded, data2, result); - EXPECT_EQ(result, CharacterSet::Shift_JIS); - EXPECT_THAT(data2, ElementsAreArray(bytes2, sizeof(bytes2))); - EXPECT_EQ(encoded, std::wstring(L"A\u00E9ZA\u0449Z")); - - // Encoding change - result = OnChangeAppendReset(4, encoded, data2, result); - EXPECT_EQ(result, CharacterSet::ISO8859_2); - EXPECT_TRUE(data2.empty()); - EXPECT_EQ(encoded, std::wstring(L"A\u00E9ZA\u0449ZA\u30C6Z")); - } + EXPECT_EQ(CharacterSet::ISO8859_1, CharacterSetFromString("ISO-8859-1")); + EXPECT_EQ(CharacterSet::ISO8859_1, CharacterSetFromString("ISO8859_1")); + EXPECT_EQ(CharacterSet::ISO8859_1, CharacterSetFromString("ISO 8859-1")); + EXPECT_EQ(CharacterSet::ISO8859_1, CharacterSetFromString("iso88591")); + EXPECT_EQ(CharacterSet::Unknown, CharacterSetFromString("invalid-name")); } diff --git a/test/unit/ContentTest.cpp b/test/unit/ContentTest.cpp new file mode 100644 index 0000000000..39fa72ba25 --- /dev/null +++ b/test/unit/ContentTest.cpp @@ -0,0 +1,94 @@ +/* +* Copyright 2022 Axel Waggershauser +*/ +// SPDX-License-Identifier: Apache-2.0 + +#include "Content.h" +#include "ECI.h" + +#include "gtest/gtest.h" +#include "gmock/gmock.h" + +using namespace ZXing; +using namespace testing; + +TEST(ContentTest, Base) +{ + { // Null + Content c; + EXPECT_EQ(c.guessEncoding(), CharacterSet::Unknown); + EXPECT_EQ(c.symbology.toString(), ""); + EXPECT_TRUE(c.empty()); + } + + { // set latin1 + Content c; + c.switchEncoding(CharacterSet::ISO8859_1); + c.append(ByteArray{'A', 0xE9, 'Z'}); + EXPECT_EQ(c.utf16(), L"A\u00E9Z"); + } + + { // set CharacterSet::ISO8859_5 + Content c; + c.switchEncoding(CharacterSet::ISO8859_5); + c.append(ByteArray{'A', 0xE9, 'Z'}); + EXPECT_EQ(c.utf16(), L"A\u0449Z"); + } + + { // switch to CharacterSet::ISO8859_5 + Content c; + c.append(ByteArray{'A', 0xE9, 'Z'}); + EXPECT_FALSE(c.hasECI); + c.switchEncoding(CharacterSet::ISO8859_5); + EXPECT_FALSE(c.hasECI); + c.append(ByteArray{'A', 0xE9, 'Z'}); + EXPECT_EQ(c.utf16(), L"A\u00E9ZA\u0449Z"); + } +} + +TEST(ContentTest, GuessEncoding) +{ + { // guess latin1 + Content c; + c.append(ByteArray{'A', 0xE9, 'Z'}); + EXPECT_EQ(c.guessEncoding(), CharacterSet::ISO8859_1); + EXPECT_EQ(c.utf16(), L"A\u00E9Z"); + EXPECT_EQ(c.bytesECI(), c.bytes); + } + + { // guess Shift_JIS + Content c; + c.append(ByteArray{'A', 0x83, 0x65, 'Z'}); + EXPECT_EQ(c.guessEncoding(), CharacterSet::Shift_JIS); + EXPECT_EQ(c.utf16(), L"A\u30C6Z"); + } +} + +TEST(ContentTest, ECI) +{ + { // switch to ECI::ISO8859_5 + Content c; + c.append(ByteArray{'A', 0xE9, 'Z'}); + c.switchEncoding(ECI::ISO8859_5); + c.append(ByteArray{'A', 0xE9, 'Z'}); + EXPECT_TRUE(c.hasECI); + EXPECT_EQ(c.utf16(), L"A\u00E9ZA\u0449Z"); + EXPECT_EQ(c.bytesECI().asString(), std::string_view("\\000003A\xE9Z\\000007A\xE9Z")); + } + + { // switch ECI -> latin1 for unknown (instead of Shift_JIS) + Content c; + c.append(ByteArray{'A', 0x83, 0x65, 'Z'}); + c.switchEncoding(ECI::ISO8859_5); + c.append(ByteArray{'A', 0xE9, 'Z'}); + EXPECT_EQ(c.utf16(), L"A\u0083\u0065ZA\u0449Z"); + EXPECT_EQ(c.bytesECI().asString(), std::string_view("\\000003A\x83\x65Z\\000007A\xE9Z")); + } + + { // double '\' + Content c; + c.append("C:\\Test"); + EXPECT_EQ(c.utf16(), L"C:\\Test"); + EXPECT_EQ(c.bytesECI().asString(), std::string_view("C:\\\\Test")); + } +} diff --git a/test/unit/ErrorTest.cpp b/test/unit/ErrorTest.cpp new file mode 100644 index 0000000000..66eb6ac611 --- /dev/null +++ b/test/unit/ErrorTest.cpp @@ -0,0 +1,43 @@ +/* +* Copyright 2022 Axel Waggershauser +*/ +// SPDX-License-Identifier: Apache-2.0 + +#include "Error.h" + +#include "gtest/gtest.h" + +using namespace ZXing; + +TEST(ErrorTest, Default) +{ + Error e; + + EXPECT_FALSE(e); + EXPECT_EQ(e.type(), Error::Type::None); + EXPECT_EQ(e.msg().empty(), true); + EXPECT_EQ(e.location().empty(), true); +} + +TEST(ErrorTest, Empty) +{ + Error e = ChecksumError(); + + EXPECT_TRUE(e); + EXPECT_EQ(e.type(), Error::Type::Checksum); + EXPECT_EQ(e.type(), Error::Checksum); + EXPECT_EQ(e, Error::Checksum); + EXPECT_EQ(Error::Checksum, e); + EXPECT_EQ(e.msg().empty(), true); + EXPECT_EQ(e.location().empty(), false); +} + +TEST(ErrorTest, WithMsg) +{ + Error e = FormatError("something is wrong"); int line = __LINE__; + + EXPECT_TRUE(e); + EXPECT_EQ(e, Error::Format); + EXPECT_EQ(e.msg(), "something is wrong"); + EXPECT_EQ(e.location(), "ErrorTest.cpp:" + std::to_string(line)); +} diff --git a/test/unit/GS1Test.cpp b/test/unit/GS1Test.cpp new file mode 100644 index 0000000000..122e09228a --- /dev/null +++ b/test/unit/GS1Test.cpp @@ -0,0 +1,346 @@ +/* + * Copyright 2022 gitlost + */ +// SPDX-License-Identifier: Apache-2.0 + +#include "GS1.h" + +#include "gtest/gtest.h" + +using namespace ZXing; + +TEST(HRIFromGS1, Single) +{ + // 2-digit AIs + + // Fixed length + EXPECT_EQ(HRIFromGS1("00123456789012345678"), "(00)123456789012345678"); + // Incorrect lengths + EXPECT_EQ(HRIFromGS1("0012345678901234567"), ""); + EXPECT_EQ(HRIFromGS1("001234567890123456789"), ""); + + // Fixed length + EXPECT_EQ(HRIFromGS1("16123456"), "(16)123456"); + // Incorrect lengths + EXPECT_EQ(HRIFromGS1("1612345"), ""); + EXPECT_EQ(HRIFromGS1("161234567"), ""); + + // Max length + EXPECT_EQ(HRIFromGS1("2212345678901234567890"), "(22)12345678901234567890"); + EXPECT_EQ(HRIFromGS1("221234567890123456789"), "(22)1234567890123456789"); + // Too long + EXPECT_EQ(HRIFromGS1("22123456789012345678901"), ""); + + // Max length + EXPECT_EQ(HRIFromGS1("91123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"), + "(91)123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"); + EXPECT_EQ(HRIFromGS1("9112345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"), + "(91)12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"); + // Too long + EXPECT_EQ(HRIFromGS1("911234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901"), ""); + + // Max length + EXPECT_EQ(HRIFromGS1("99123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"), + "(99)123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"); + EXPECT_EQ(HRIFromGS1("9912345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"), + "(99)12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"); + // Too long + EXPECT_EQ(HRIFromGS1("991234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901"), ""); + + // 3-digit AIs + + EXPECT_EQ(HRIFromGS1("310"), ""); // incomplete prefix + + // Max length + EXPECT_EQ(HRIFromGS1("2351234567890123456789012345678"), "(235)1234567890123456789012345678"); + EXPECT_EQ(HRIFromGS1("235123456789012345678901234567"), "(235)123456789012345678901234567"); + // Too long + EXPECT_EQ(HRIFromGS1("23512345678901234567890123456789"), ""); + + // Max length + EXPECT_EQ(HRIFromGS1("24312345678901234567890"), "(243)12345678901234567890"); + EXPECT_EQ(HRIFromGS1("2431234567890123456789"), "(243)1234567890123456789"); + // Too long + EXPECT_EQ(HRIFromGS1("243123456789012345678901"), ""); + + // Max length + EXPECT_EQ(HRIFromGS1("253123456789012345678901234567890"), "(253)123456789012345678901234567890"); + EXPECT_EQ(HRIFromGS1("25312345678901234567890123456789"), "(253)12345678901234567890123456789"); + // Too long + EXPECT_EQ(HRIFromGS1("2531234567890123456789012345678901"), ""); + + // Max length + EXPECT_EQ(HRIFromGS1("2551234567890123456789012345"), "(255)1234567890123456789012345"); + EXPECT_EQ(HRIFromGS1("255123456789012345678901234"), "(255)123456789012345678901234"); + // Too long + EXPECT_EQ(HRIFromGS1("25512345678901234567890123456"), ""); + + // Fixed length + EXPECT_EQ(HRIFromGS1("4151234567890123"), "(415)1234567890123"); + // Incorrect lengths + EXPECT_EQ(HRIFromGS1("415123456789012"), ""); + EXPECT_EQ(HRIFromGS1("41512345678901234"), ""); + + // Fixed length + EXPECT_EQ(HRIFromGS1("4171234567890123"), "(417)1234567890123"); + // Incorrect lengths + EXPECT_EQ(HRIFromGS1("417123456789012"), ""); + EXPECT_EQ(HRIFromGS1("41712345678901234"), ""); + + // Max length + EXPECT_EQ(HRIFromGS1("421123456789012"), "(421)123456789012"); + EXPECT_EQ(HRIFromGS1("42112345678901"), "(421)12345678901"); + // Too long + EXPECT_EQ(HRIFromGS1("4211234567890123"), ""); + + // Max length + EXPECT_EQ(HRIFromGS1("425123456789012345"), "(425)123456789012345"); + EXPECT_EQ(HRIFromGS1("42512345678901234"), "(425)12345678901234"); + // Too long + EXPECT_EQ(HRIFromGS1("4251234567890123456"), ""); + + // Max length + EXPECT_EQ(HRIFromGS1("427123"), "(427)123"); + EXPECT_EQ(HRIFromGS1("42712"), "(427)12"); + // Too long + EXPECT_EQ(HRIFromGS1("4271234"), ""); + + // Max length + EXPECT_EQ(HRIFromGS1("71012345678901234567890"), "(710)12345678901234567890"); + EXPECT_EQ(HRIFromGS1("7101234567890123456789"), "(710)1234567890123456789"); + // Too long + EXPECT_EQ(HRIFromGS1("710123456789012345678901"), ""); + + // Max length + EXPECT_EQ(HRIFromGS1("71512345678901234567890"), "(715)12345678901234567890"); + EXPECT_EQ(HRIFromGS1("7151234567890123456789"), "(715)1234567890123456789"); + // Too long + EXPECT_EQ(HRIFromGS1("715123456789012345678901"), ""); + + // 4-digit variable 4th + + // Fixed length + EXPECT_EQ(HRIFromGS1("3370123456"), "(3370)123456"); + // Incorrect lengths + EXPECT_EQ(HRIFromGS1("337012345"), ""); + EXPECT_EQ(HRIFromGS1("33701234567"), ""); + + // Fixed length + EXPECT_EQ(HRIFromGS1("3375123456"), "(3375)123456"); + // Incorrect lengths + EXPECT_EQ(HRIFromGS1("33751234567"), ""); + EXPECT_EQ(HRIFromGS1("337512345"), ""); + + // EXPECT_EQ(ParseFieldsInGeneralPurpose("3376123456"), // Allow although > max 3375 + + // Fixed length + EXPECT_EQ(HRIFromGS1("39401234"), "(3940)1234"); + // Incorrect lengths + EXPECT_EQ(HRIFromGS1("394012345"), ""); + EXPECT_EQ(HRIFromGS1("3940123"), ""); + + // Fixed length + EXPECT_EQ(HRIFromGS1("39431234"), "(3943)1234"); + // Incorrect lengths + EXPECT_EQ(HRIFromGS1("394312345"), ""); + EXPECT_EQ(HRIFromGS1("3943123"), ""); + + // EXPECT_EQ(ParseFieldsInGeneralPurpose("39441234"), // Allow although > max 3943 + + // Fixed length + EXPECT_EQ(HRIFromGS1("3950123456"), "(3950)123456"); + // Incorrect lengths + EXPECT_EQ(HRIFromGS1("39501234567"), ""); + EXPECT_EQ(HRIFromGS1("395012345"), ""); + + // Fixed length + EXPECT_EQ(HRIFromGS1("3955123456"), "(3955)123456"); + // Incorrect lengths + EXPECT_EQ(HRIFromGS1("39551234567"), ""); + EXPECT_EQ(HRIFromGS1("395512345"), ""); + + // EXPECT_EQ(ParseFieldsInGeneralPurpose("3956123456"), // Allow although > max 3955 + + // Max length + EXPECT_EQ(HRIFromGS1("7230123456789012345678901234567890"), "(7230)123456789012345678901234567890"); + EXPECT_EQ(HRIFromGS1("723012345678901234567890123456789"), "(7230)12345678901234567890123456789"); + // Too long + EXPECT_EQ(HRIFromGS1("72301234567890123456789012345678901"), ""); + + // Max length + EXPECT_EQ(HRIFromGS1("7239123456789012345678901234567890"), "(7239)123456789012345678901234567890"); + EXPECT_EQ(HRIFromGS1("723912345678901234567890123456789"), "(7239)12345678901234567890123456789"); + // Too long + EXPECT_EQ(HRIFromGS1("72391234567890123456789012345678901"), ""); + + // 4-digit AIs + + // Max length + EXPECT_EQ(HRIFromGS1("430012345678901234567890123456789012345"), "(4300)12345678901234567890123456789012345"); + EXPECT_EQ(HRIFromGS1("43001234567890123456789012345678901234"), "(4300)1234567890123456789012345678901234"); + // Too long + EXPECT_EQ(HRIFromGS1("4300123456789012345678901234567890123456"), ""); + + // Fixed length + EXPECT_EQ(HRIFromGS1("430712"), "(4307)12"); + // Incorrect lengths + EXPECT_EQ(HRIFromGS1("4307123"), ""); + EXPECT_EQ(HRIFromGS1("43071"), ""); + + // Max length + EXPECT_EQ(HRIFromGS1("4308123456789012345678901234567890"), "(4308)123456789012345678901234567890"); + EXPECT_EQ(HRIFromGS1("430812345678901234567890123456789"), "(4308)12345678901234567890123456789"); + // Too long + EXPECT_EQ(HRIFromGS1("43081234567890123456789012345678901"), ""); + + // Fixed length + EXPECT_EQ(HRIFromGS1("431712"), "(4317)12"); + // Incorrect lengths + EXPECT_EQ(HRIFromGS1("4317123"), ""); + EXPECT_EQ(HRIFromGS1("43171"), ""); + + // Max length + EXPECT_EQ(HRIFromGS1("431812345678901234567890"), "(4318)12345678901234567890"); + EXPECT_EQ(HRIFromGS1("43181234567890123456789"), "(4318)1234567890123456789"); + // Too long + EXPECT_EQ(HRIFromGS1("4318123456789012345678901"), ""); + + // Fixed length + EXPECT_EQ(HRIFromGS1("43211"), "(4321)1"); + // Incorrect lengths + EXPECT_EQ(HRIFromGS1("432112"), ""); + EXPECT_EQ(HRIFromGS1("4321"), ""); + + // Fixed length + EXPECT_EQ(HRIFromGS1("4326123456"), "(4326)123456"); + // Incorrect lengths + EXPECT_EQ(HRIFromGS1("43261234567"), ""); + EXPECT_EQ(HRIFromGS1("432612345"), ""); + + // Max length + EXPECT_EQ(HRIFromGS1("70041234"), "(7004)1234"); + EXPECT_EQ(HRIFromGS1("7004123"), "(7004)123"); + // Too long + EXPECT_EQ(HRIFromGS1("700412345"), ""); + + // Fixed length + EXPECT_EQ(HRIFromGS1("7006123456"), "(7006)123456"); + // Incorrect lengths + EXPECT_EQ(HRIFromGS1("70061234567"), ""); + EXPECT_EQ(HRIFromGS1("700612345"), ""); + + // Max length + EXPECT_EQ(HRIFromGS1("701012"), "(7010)12"); + EXPECT_EQ(HRIFromGS1("70101"), "(7010)1"); + // Too long + EXPECT_EQ(HRIFromGS1("7010123"), ""); + + // Max length + EXPECT_EQ(HRIFromGS1("702012345678901234567890"), "(7020)12345678901234567890"); + EXPECT_EQ(HRIFromGS1("70201234567890123456789"), "(7020)1234567890123456789"); + // Too long + EXPECT_EQ(HRIFromGS1("7020123456789012345678901"), ""); + + // Max length + EXPECT_EQ(HRIFromGS1("7023123456789012345678901234567890"), "(7023)123456789012345678901234567890"); + EXPECT_EQ(HRIFromGS1("702312345678901234567890123456789"), "(7023)12345678901234567890123456789"); + // Too long + EXPECT_EQ(HRIFromGS1("70231234567890123456789012345678901"), ""); + + // Max length + EXPECT_EQ(HRIFromGS1("70401234"), "(7040)1234"); + EXPECT_EQ(HRIFromGS1("704012345"), ""); + // Too long + EXPECT_EQ(HRIFromGS1("7040123"), ""); + + // Max length + EXPECT_EQ(HRIFromGS1("724012345678901234567890"), "(7240)12345678901234567890"); + EXPECT_EQ(HRIFromGS1("72401234567890123456789"), "(7240)1234567890123456789"); + // Too long + EXPECT_EQ(HRIFromGS1("7240123456789012345678901"), ""); + + // Max length + EXPECT_EQ(HRIFromGS1("80071234567890123456789012345678901234"), "(8007)1234567890123456789012345678901234"); + EXPECT_EQ(HRIFromGS1("8007123456789012345678901234567890123"), "(8007)123456789012345678901234567890123"); + // Too long + EXPECT_EQ(HRIFromGS1("800712345678901234567890123456789012345"), ""); + + // Max length + EXPECT_EQ(HRIFromGS1("800912345678901234567890123456789012345678901234567890"), + + "(8009)12345678901234567890123456789012345678901234567890"); + EXPECT_EQ(HRIFromGS1("80091234567890123456789012345678901234567890123456789"), + + "(8009)1234567890123456789012345678901234567890123456789"); + // Too long + EXPECT_EQ(HRIFromGS1("8009123456789012345678901234567890123456789012345678901"), ""); + + // Max length + EXPECT_EQ(HRIFromGS1("80131234567890123456789012345"), "(8013)1234567890123456789012345"); + EXPECT_EQ(HRIFromGS1("8013123456789012345678901234"), "(8013)123456789012345678901234"); + // Too long + EXPECT_EQ(HRIFromGS1("801312345678901234567890123456"), ""); + + // Fixed length + EXPECT_EQ(HRIFromGS1("8017123456789012345678"), "(8017)123456789012345678"); + // Incorrect lengths + EXPECT_EQ(HRIFromGS1("80171234567890123456789"), ""); + EXPECT_EQ(HRIFromGS1("801712345678901234567"), ""); + + // Max length + EXPECT_EQ(HRIFromGS1("80191234567890"), "(8019)1234567890"); + EXPECT_EQ(HRIFromGS1("8019123456789"), "(8019)123456789"); + // Too long + EXPECT_EQ(HRIFromGS1("801912345678901"), ""); + + // Fixed length + EXPECT_EQ(HRIFromGS1("8026123456789012345678"), "(8026)123456789012345678"); + // Incorrect lengths + EXPECT_EQ(HRIFromGS1("80261234567890123456789"), ""); + EXPECT_EQ(HRIFromGS1("802612345678901234567"), ""); + + // Non-existing + EXPECT_EQ(HRIFromGS1("8100123456"), ""); + EXPECT_EQ(HRIFromGS1("81011234567890"), ""); + EXPECT_EQ(HRIFromGS1("810212"), ""); + + // Max length + EXPECT_EQ(HRIFromGS1("81101234567890123456789012345678901234567890123456789012345678901234567890"), + "(8110)1234567890123456789012345678901234567890123456789012345678901234567890"); + EXPECT_EQ(HRIFromGS1("8110123456789012345678901234567890123456789012345678901234567890123456789"), + "(8110)123456789012345678901234567890123456789012345678901234567890123456789"); + // Too long + EXPECT_EQ(HRIFromGS1("811012345678901234567890123456789012345678901234567890123456789012345678901"), ""); + + // Fixed length + EXPECT_EQ(HRIFromGS1("81111234"), "(8111)1234"); + // Incorrect lengths + EXPECT_EQ(HRIFromGS1("811112345"), ""); + EXPECT_EQ(HRIFromGS1("8111123"), ""); + + // Max length + EXPECT_EQ(HRIFromGS1("81121234567890123456789012345678901234567890123456789012345678901234567890"), + "(8112)1234567890123456789012345678901234567890123456789012345678901234567890"); + EXPECT_EQ(HRIFromGS1("8112123456789012345678901234567890123456789012345678901234567890123456789"), + "(8112)123456789012345678901234567890123456789012345678901234567890123456789"); + // Too long + EXPECT_EQ(HRIFromGS1("811212345678901234567890123456789012345678901234567890123456789012345678901"), ""); + + // Max length + EXPECT_EQ(HRIFromGS1("82001234567890123456789012345678901234567890123456789012345678901234567890"), + "(8200)1234567890123456789012345678901234567890123456789012345678901234567890"); + EXPECT_EQ(HRIFromGS1("8200123456789012345678901234567890123456789012345678901234567890123456789"), + "(8200)123456789012345678901234567890123456789012345678901234567890123456789"); + // Too long + EXPECT_EQ(HRIFromGS1("820012345678901234567890123456789012345678901234567890123456789012345678901"), ""); +} + +TEST(HRIFromGS1, MultiFixed) +{ + EXPECT_EQ(HRIFromGS1("81111234430712"), "(8111)1234(4307)12"); +} + +TEST(HRIFromGS1, MultiVariable) +{ + EXPECT_EQ(HRIFromGS1("70041234\x1d""81111234"), "(7004)1234(8111)1234"); +} diff --git a/test/unit/GTINTest.cpp b/test/unit/GTINTest.cpp index ddaf02db2b..10f89909e9 100644 --- a/test/unit/GTINTest.cpp +++ b/test/unit/GTINTest.cpp @@ -1,18 +1,7 @@ /* * Copyright 2022 gitlost -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "GTIN.h" diff --git a/test/unit/ReedSolomonTest.cpp b/test/unit/ReedSolomonTest.cpp index 9be8b6fca4..870c33b268 100644 --- a/test/unit/ReedSolomonTest.cpp +++ b/test/unit/ReedSolomonTest.cpp @@ -1,19 +1,8 @@ /* * Copyright 2017 Huy Cuong Nguyen * Copyright 2013 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "GenericGF.h" #include "PseudoRandom.h" diff --git a/test/unit/TextDecoderTest.cpp b/test/unit/TextDecoderTest.cpp index b782df3638..5276c4e7f5 100644 --- a/test/unit/TextDecoderTest.cpp +++ b/test/unit/TextDecoderTest.cpp @@ -1,18 +1,7 @@ /* * Copyright 2021 gitlost -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "CharacterSet.h" #include "TextDecoder.h" @@ -101,7 +90,7 @@ TEST(TextDecoderTest, AppendShift_JIS) static const uint8_t data[] = { 0x5C }; std::wstring str; TextDecoder::Append(str, data, sizeof(data), CharacterSet::Shift_JIS); - EXPECT_EQ(str, std::wstring(L"\u005C")); // Would normally be "\u00A5" + EXPECT_EQ(str, L"\u005C"); // Would normally be "\u00A5" EXPECT_EQ(ToUtf8(str), "\\"); // "Â¥" ditto } @@ -110,7 +99,7 @@ TEST(TextDecoderTest, AppendShift_JIS) static const uint8_t data[] = { 0x81, 0x5F }; std::wstring str; TextDecoder::Append(str, data, sizeof(data), CharacterSet::Shift_JIS); - EXPECT_EQ(str, std::wstring(L"\uFF3C")); + EXPECT_EQ(str, L"\uFF3C"); EXPECT_EQ(ToUtf8(str), "ï¼¼"); } @@ -119,7 +108,7 @@ TEST(TextDecoderTest, AppendShift_JIS) static const uint8_t data[] = { 0xA5 }; std::wstring str; TextDecoder::Append(str, data, sizeof(data), CharacterSet::Shift_JIS); - EXPECT_EQ(str, std::wstring(L"\uFF65")); + EXPECT_EQ(str, L"\uFF65"); EXPECT_EQ(ToUtf8(str), "ï½¥"); } @@ -128,7 +117,7 @@ TEST(TextDecoderTest, AppendShift_JIS) static const uint8_t data[] = { 0x7E }; std::wstring str; TextDecoder::Append(str, data, sizeof(data), CharacterSet::Shift_JIS); - EXPECT_EQ(str, std::wstring(L"~")); // Would normally be "\u203E" + EXPECT_EQ(str, L"~"); // Would normally be "\u203E" EXPECT_EQ(ToUtf8(str), "~"); // "‾" ditto } @@ -137,7 +126,7 @@ TEST(TextDecoderTest, AppendShift_JIS) 0xE4, 0xAA, 0x83, 0x65 }; std::wstring str; TextDecoder::Append(str, data, sizeof(data), CharacterSet::Shift_JIS); - EXPECT_EQ(str, std::wstring(L"a\u03B2c\u0416\uFF65\uFF7F\uFF3C\u70B9\u8317\u30C6")); + EXPECT_EQ(str, L"a\u03B2c\u0416\uFF65\uFF7F\uFF3C\u70B9\u8317\u30C6"); EXPECT_EQ(ToUtf8(str), "aβcЖ・ソ\点茗テ"); } } @@ -148,7 +137,7 @@ TEST(TextDecoderTest, AppendBig5) static const uint8_t data[] = { 0xA1, 0x5A }; // Drawings box light left in Big5-2003; not in original Big5 std::wstring str; TextDecoder::Append(str, data, sizeof(data), CharacterSet::Big5); - EXPECT_EQ(str, std::wstring(L"\u2574")); + EXPECT_EQ(str, L"\u2574"); EXPECT_EQ(ToUtf8(str), "â•´"); } @@ -156,7 +145,7 @@ TEST(TextDecoderTest, AppendBig5) static const uint8_t data[] = { 0xA1, 0x56 }; // En dash U+2013 in Big5, horizontal bar U+2015 in Big5-2003 std::wstring str; TextDecoder::Append(str, data, sizeof(data), CharacterSet::Big5); - EXPECT_EQ(str, std::wstring(L"\u2013")); + EXPECT_EQ(str, L"\u2013"); EXPECT_EQ(ToUtf8(str), "–"); } @@ -164,7 +153,7 @@ TEST(TextDecoderTest, AppendBig5) static const uint8_t data[] = { 0x1, ' ', 0xA1, 0x71, '@', 0xC0, 0x40, 0xF9, 0xD5, 0x7F }; std::wstring str; TextDecoder::Append(str, data, sizeof(data), CharacterSet::Big5); - EXPECT_EQ(str, std::wstring(L"\u0001 \u3008@\u9310\u9F98\u007F")); + EXPECT_EQ(str, L"\u0001 \u3008@\u9310\u9F98\u007F"); EXPECT_EQ(ToUtf8(str), "\x01 〈@éŒé¾˜\x7F"); } } @@ -175,7 +164,7 @@ TEST(TextDecoderTest, AppendGB2312) static const uint8_t data[] = { 'a', 0xA6, 0xC2, 'c', 0xA1, 0xA4, 0xA1, 0xAA, 0xA8, 0xA6, 'Z' }; std::wstring str; TextDecoder::Append(str, data, sizeof(data), CharacterSet::GB2312); - EXPECT_EQ(str, std::wstring(L"a\u03B2c\u00B7\u2014\u00E9Z")); + EXPECT_EQ(str, L"a\u03B2c\u00B7\u2014\u00E9Z"); EXPECT_EQ(ToUtf8(str), "aβc·—éZ"); } } @@ -187,8 +176,8 @@ TEST(TextDecoderTest, AppendGB18030) 0xA8, 0xA6, 'Z' }; std::wstring str; TextDecoder::Append(str, data, sizeof(data), CharacterSet::GB18030); - EXPECT_EQ(str, std::wstring(L"a\u03B2c\u30FB\u00B7\u2014\u00E9Z")); - EXPECT_EQ(ToUtf8(str), std::string("aβc・·—éZ")); + EXPECT_EQ(str, L"a\u03B2c\u30FB\u00B7\u2014\u00E9Z"); + EXPECT_EQ(ToUtf8(str), "aβc・·—éZ"); } } @@ -198,16 +187,16 @@ TEST(TextDecoderTest, AppendEUC_KR) static const uint8_t data[] = { 0xA2, 0xE6 }; // Euro sign U+20AC added KS X 1001:1998, not supported std::wstring str; TextDecoder::Append(str, data, sizeof(data), CharacterSet::EUC_KR); - EXPECT_EQ(str, std::wstring(L"\uFFFD")); - EXPECT_EQ(ToUtf8(str), std::string("\xEF\xBF\xBD")); + EXPECT_EQ(str, L"\uFFFD"); + EXPECT_EQ(ToUtf8(str), "\xEF\xBF\xBD"); } { static const uint8_t data[] = { 'a', 0xA4, 0xA1, 'Z' }; std::wstring str; TextDecoder::Append(str, data, sizeof(data), CharacterSet::EUC_KR); - EXPECT_EQ(str, std::wstring(L"a\u3131Z")); - EXPECT_EQ(ToUtf8(str), std::string("aㄱZ")); + EXPECT_EQ(str, L"a\u3131Z"); + EXPECT_EQ(ToUtf8(str), "aㄱZ"); } } @@ -218,15 +207,15 @@ TEST(TextDecoderTest, AppendUnicodeBig) static const uint8_t data[] = { 0x00, 0x01, 0x00, 0x7F, 0x00, 0x80, 0x00, 0xFF, 0x01, 0xFF, 0x10, 0xFF, 0xFF, 0xFD }; TextDecoder::Append(str, data, sizeof(data), CharacterSet::UnicodeBig); - EXPECT_EQ(str, std::wstring(L"\u0001\u007F\u0080\u00FF\u01FF\u10FF\uFFFD")); - EXPECT_EQ(ToUtf8(str), std::string("\x01\x7F\xC2\x80ÿǿჿ\xEF\xBF\xBD")); + EXPECT_EQ(str, L"\u0001\u007F\u0080\u00FF\u01FF\u10FF\uFFFD"); + EXPECT_EQ(ToUtf8(str), "\x01\x7F\xC2\x80ÿǿჿ\xEF\xBF\xBD"); } { std::wstring str; static const uint8_t data[] = { 0xD8, 0x00, 0xDC, 0x00 }; // Surrogate pair U+10000 TextDecoder::Append(str, data, sizeof(data), CharacterSet::UnicodeBig); - EXPECT_EQ(str, std::wstring(L"\U00010000")); - EXPECT_EQ(ToUtf8(str), std::string("ð€€")); + EXPECT_EQ(str, L"\U00010000"); + EXPECT_EQ(ToUtf8(str), "ð€€"); } } diff --git a/test/unit/TextUtfEncodingTest.cpp b/test/unit/TextUtfEncodingTest.cpp index e7c2deaadb..f37e1bfb65 100644 --- a/test/unit/TextUtfEncodingTest.cpp +++ b/test/unit/TextUtfEncodingTest.cpp @@ -1,18 +1,7 @@ /* * Copyright 2021 gitlost -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "TextUtfEncoding.h" @@ -30,11 +19,11 @@ TEST(TextUtfEncodingTest, ToUtf8AngleEscape) EXPECT_EQ(ctype_locale, std::string("C")); #ifndef _WIN32 - EXPECT_EQ(ToUtf8(std::wstring(L"\u00B6\u0416"), angleEscape), std::string("")); + EXPECT_EQ(ToUtf8(L"\u00B6\u0416", angleEscape), ""); #else - EXPECT_EQ(ToUtf8(std::wstring(L"\u00B6\u0416"), angleEscape), std::string("¶Ж")); + EXPECT_EQ(ToUtf8(L"\u00B6\u0416", angleEscape), "¶Ж"); #endif - EXPECT_EQ(ToUtf8(std::wstring(L"\u2602"), angleEscape), std::string("")); + EXPECT_EQ(ToUtf8(L"\u2602", angleEscape), ""); #ifndef _WIN32 std::setlocale(LC_CTYPE, "en_US.UTF-8"); @@ -44,33 +33,33 @@ TEST(TextUtfEncodingTest, ToUtf8AngleEscape) EXPECT_TRUE(std::string(std::setlocale(LC_CTYPE, NULL)).find("utf8") != std::string::npos); #endif - EXPECT_EQ(ToUtf8(std::wstring(L"\u00B6\u0416"), angleEscape), std::string("¶Ж")); + EXPECT_EQ(ToUtf8(L"\u00B6\u0416", angleEscape), "¶Ж"); #ifndef _WIN32 - EXPECT_EQ(ToUtf8(std::wstring(L"\u2602"), angleEscape), std::string("☂")); + EXPECT_EQ(ToUtf8(L"\u2602", angleEscape), "☂"); #else - EXPECT_EQ(ToUtf8(std::wstring(L"\u2602"), angleEscape), std::string("")); + EXPECT_EQ(ToUtf8(L"\u2602", angleEscape), ""); #endif - EXPECT_EQ(ToUtf8(std::wstring(L"\x01\x1F\x7F"), angleEscape), std::string("")); - EXPECT_EQ(ToUtf8(std::wstring(L"\x80\x9F"), angleEscape), std::string("")); - EXPECT_EQ(ToUtf8(std::wstring(L"\xA0"), angleEscape), std::string("")); // NO-BREAK space (nbsp) - EXPECT_EQ(ToUtf8(std::wstring(L"\x2007"), angleEscape), std::string("")); // NO-BREAK space (numsp) - EXPECT_EQ(ToUtf8(std::wstring(L"\xFFEF"), angleEscape), std::string("")); // Was NO-BREAK space but now isn't (BOM) - EXPECT_EQ(ToUtf8(std::wstring(L"\u0100"), angleEscape), std::string("Ä€")); - EXPECT_EQ(ToUtf8(std::wstring(L"\u1000"), angleEscape), std::string("က")); - EXPECT_EQ(ToUtf8(std::wstring(L"\u2000"), angleEscape), std::string("")); // Space char (nqsp) + EXPECT_EQ(ToUtf8(L"\x01\x1F\x7F", angleEscape), ""); + EXPECT_EQ(ToUtf8(L"\x80\x9F", angleEscape), ""); + EXPECT_EQ(ToUtf8(L"\xA0", angleEscape), ""); // NO-BREAK space (nbsp) + EXPECT_EQ(ToUtf8(L"\x2007", angleEscape), ""); // NO-BREAK space (numsp) + EXPECT_EQ(ToUtf8(L"\xFFEF", angleEscape), ""); // Was NO-BREAK space but now isn't (BOM) + EXPECT_EQ(ToUtf8(L"\u0100", angleEscape), "Ä€"); + EXPECT_EQ(ToUtf8(L"\u1000", angleEscape), "က"); + EXPECT_EQ(ToUtf8(L"\u2000", angleEscape), ""); // Space char (nqsp) #ifndef _WIN32 - EXPECT_EQ(ToUtf8(std::wstring(L"\uFFFD"), angleEscape), std::string("�")); + EXPECT_EQ(ToUtf8(L"\uFFFD", angleEscape), "�"); #else - EXPECT_EQ(ToUtf8(std::wstring(L"\uFFFD"), angleEscape), std::string("")); + EXPECT_EQ(ToUtf8(L"\uFFFD", angleEscape), ""); #endif - EXPECT_EQ(ToUtf8(std::wstring(L"\uFFFF"), angleEscape), std::string("")); + EXPECT_EQ(ToUtf8(L"\uFFFF", angleEscape), ""); #ifndef __APPLE__ - EXPECT_EQ(ToUtf8(std::wstring(L"\U00010000"), angleEscape), std::string("ð€€")); + EXPECT_EQ(ToUtf8(L"\U00010000", angleEscape), "ð€€"); #else - EXPECT_EQ(ToUtf8(std::wstring(L"\U00010000"), angleEscape), std::string("")); + EXPECT_EQ(ToUtf8(L"\U00010000", angleEscape), ""); #endif - EXPECT_EQ(ToUtf8(std::wstring(L"\xD800Z"), angleEscape), std::string("Z")); // Unpaired high surrogate - EXPECT_EQ(ToUtf8(std::wstring(L"A\xDC00"), angleEscape), std::string("A")); // Unpaired low surrogate + EXPECT_EQ(ToUtf8(L"\xD800Z", angleEscape), "Z"); // Unpaired high surrogate + EXPECT_EQ(ToUtf8(L"A\xDC00", angleEscape), "A"); // Unpaired low surrogate std::setlocale(LC_CTYPE, ctype_locale.c_str()); } diff --git a/test/unit/ThresholdBinarizerTest.cpp b/test/unit/ThresholdBinarizerTest.cpp index 0a9e54f189..bcf8ab6839 100644 --- a/test/unit/ThresholdBinarizerTest.cpp +++ b/test/unit/ThresholdBinarizerTest.cpp @@ -1,18 +1,7 @@ /* * Copyright 2022 gitlost -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "ThresholdBinarizer.h" #include "oned/ODReader.h" @@ -24,7 +13,7 @@ using namespace ZXing; // Helper to parse a 0/1 string into a BitMatrix static BitMatrix ParseBitMatrix(const std::string& str, const int width) { - const int height = static_cast(str.length() / width); + const int height = narrow_cast(str.length() / width); BitMatrix mat(width, height); for (int y = 0; y < height; ++y) { @@ -57,7 +46,6 @@ TEST(ThresholdBinarizerTest, PatternRowClear) BitMatrix bits; DecodeHints hints; std::vector buf; - Result result(DecodeStatus::NotFound); // Test that ThresholdBinarizer::getPatternRow() clears row first (same as GlobalHistogramBinarizer) // Following was failing due to OneD::DoDecode() accumulating bars in loop when using ThresholdBinarizer @@ -109,7 +97,7 @@ TEST(ThresholdBinarizerTest, PatternRowClear) hints.setFormats(BarcodeFormat::DataBarExpanded); OneD::Reader reader(hints); - result = reader.decode(ThresholdBinarizer(getImageView(buf, bits), 0x7F)); + Result result = reader.decode(ThresholdBinarizer(getImageView(buf, bits), 0x7F)); EXPECT_TRUE(result.isValid()); - EXPECT_EQ(result.text(), L"(91)12345678901234567890123456789012345678901234567890123456789012345678"); + EXPECT_EQ(result.text(), "(91)12345678901234567890123456789012345678901234567890123456789012345678"); } diff --git a/test/unit/aztec/AZDecoderTest.cpp b/test/unit/aztec/AZDecoderTest.cpp index 242348897c..43f39c4872 100644 --- a/test/unit/aztec/AZDecoderTest.cpp +++ b/test/unit/aztec/AZDecoderTest.cpp @@ -1,19 +1,8 @@ /* * Copyright 2017 Huy Cuong Nguyen * Copyright 2014 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "aztec/AZDecoder.h" #include "BitArray.h" @@ -28,14 +17,7 @@ namespace ZXing::Aztec { -struct AztecData -{ - std::wstring text; - std::string symbologyIdentifier; - StructuredAppendInfo sai; -}; - -AztecData GetEncodedData(const BitArray& bits, const std::string& characterSet = ""); +DecoderResult Decode(const BitArray& bits); } @@ -78,11 +60,6 @@ TEST(AZDecoderTest, AztecResult) DecoderResult result = parse(std::move(bits), false, 30, 2); EXPECT_EQ(result.isValid(), true); EXPECT_EQ(result.text(), L"88888TTTTTTTTTTTTTTTTTTTTTTTTTTTTTT"); - EXPECT_EQ(result.rawBytes(), ByteArray({ - 0xf5, 0x55, 0x55, 0x75, 0x6b, 0x5a, 0xd6, 0xb5, 0xad, 0x6b, - 0x5a, 0xd6, 0xb5, 0xad, 0x6b, 0x5a, 0xd6, 0xb5, 0xad, 0x6b, - 0x5a, 0xd6, 0xb0 })); - EXPECT_EQ(result.numBits(), 180); EXPECT_EQ(result.symbologyIdentifier(), "]z0"); } @@ -119,7 +96,7 @@ TEST(AZDecoderTest, DecodeTooManyErrors) , 'X', true); DecoderResult result = parse(std::move(bits), true, 16, 4); - EXPECT_EQ(result.errorCode(), DecodeStatus::FormatError); + EXPECT_EQ(result.error(), Error::Checksum); } TEST(AZDecoderTest, DecodeTooManyErrors2) @@ -155,18 +132,18 @@ TEST(AZDecoderTest, DecodeTooManyErrors2) , 'X', true); DecoderResult result = parse(std::move(bits), true, 16, 4); - EXPECT_EQ(result.errorCode(), DecodeStatus::FormatError); + EXPECT_EQ(result.error(), Error::Checksum); } // Helper taking bit string to call GetEncodedData() -static Aztec::AztecData getData(std::string_view bitStr) +static DecoderResult getData(std::string_view bitStr) { BitArray bits; for (auto b : bitStr) bits.appendBit(b == '1'); - return Aztec::GetEncodedData(bits); + return Aztec::Decode(bits); } TEST(AZDecoderTest, SymbologyIdentifier) @@ -174,101 +151,101 @@ TEST(AZDecoderTest, SymbologyIdentifier) { // Plain auto data = getData("00010"); - EXPECT_EQ(data.symbologyIdentifier, "]z0"); - EXPECT_EQ(data.text, L"A"); + EXPECT_EQ(data.symbologyIdentifier(), "]z0"); + EXPECT_EQ(data.text(), L"A"); } { // GS1 ("PS FLGN(0) DL (20)01") auto data = getData("0000000000000111100100001000100011"); - EXPECT_EQ(data.symbologyIdentifier, "]z1"); - EXPECT_EQ(data.text, L"2001"); + EXPECT_EQ(data.symbologyIdentifier(), "]z1"); + EXPECT_EQ(data.text(), L"2001"); } { // AIM ("A PS FLGN(0) B") auto data = getData("00010000000000000000011"); - EXPECT_EQ(data.symbologyIdentifier, "]z2"); - EXPECT_EQ(data.text, L"AB"); + EXPECT_EQ(data.symbologyIdentifier(), "]z2"); + EXPECT_EQ(data.text(), L"AB"); } { // AIM ("DL 99 UL PS FLGN(0) B") auto data = getData("11110101110111110000000000000000011"); - EXPECT_EQ(data.symbologyIdentifier, "]z2"); - EXPECT_EQ(data.text, L"99B"); + EXPECT_EQ(data.symbologyIdentifier(), "]z2"); + EXPECT_EQ(data.text(), L"99B"); } { // Structured Append ("UL ML A D A") auto data = getData("1110111101000100010100010"); - EXPECT_EQ(data.symbologyIdentifier, "]z6"); - EXPECT_EQ(data.text, L"A"); - EXPECT_EQ(data.sai.index, 0); - EXPECT_EQ(data.sai.count, 4); + EXPECT_EQ(data.symbologyIdentifier(), "]z6"); + EXPECT_EQ(data.text(), L"A"); + EXPECT_EQ(data.structuredAppend().index, 0); + EXPECT_EQ(data.structuredAppend().count, 4); } { // Structured Append with GS1 ("UL ML A D PS FLGN(0) DL (20)01") auto data = getData("111011110100010001010000000000000111100100001000100011"); - EXPECT_EQ(data.symbologyIdentifier, "]z7"); - EXPECT_EQ(data.text, L"2001"); - EXPECT_EQ(data.sai.index, 0); - EXPECT_EQ(data.sai.count, 4); + EXPECT_EQ(data.symbologyIdentifier(), "]z7"); + EXPECT_EQ(data.text(), L"2001"); + EXPECT_EQ(data.structuredAppend().index, 0); + EXPECT_EQ(data.structuredAppend().count, 4); } { // Structured Append with AIM ("UL ML A D A PS FLGN(0) B") auto data = getData("1110111101000100010100010000000000000000011"); - EXPECT_EQ(data.symbologyIdentifier, "]z8"); - EXPECT_EQ(data.text, L"AB"); - EXPECT_EQ(data.sai.index, 0); - EXPECT_EQ(data.sai.count, 4); + EXPECT_EQ(data.symbologyIdentifier(), "]z8"); + EXPECT_EQ(data.text(), L"AB"); + EXPECT_EQ(data.structuredAppend().index, 0); + EXPECT_EQ(data.structuredAppend().count, 4); } { // Plain with FNC1 not in first/second position ("A B PS FLGN(0) C") auto data = getData("0001000011000000000000000100"); - EXPECT_EQ(data.symbologyIdentifier, "]z0"); - EXPECT_EQ(data.text, L"AB\u001DC"); // "ABC" + EXPECT_EQ(data.symbologyIdentifier(), "]z0"); + EXPECT_EQ(data.text(), L"AB\u001DC"); // "ABC" } { // Plain with FNC1 not in first/second position ("A B C PS FLGN(0) D") auto data = getData("000100001100100000000000000000101"); - EXPECT_EQ(data.symbologyIdentifier, "]z0"); - EXPECT_EQ(data.text, L"ABC\u001DD"); // "ABCD" + EXPECT_EQ(data.symbologyIdentifier(), "]z0"); + EXPECT_EQ(data.text(), L"ABC\u001DD"); // "ABCD" } { // Plain with FNC1 not in first/second position ("DL 1 UL PS FLGN(0) A") auto data = getData("1111000111110000000000000000010"); - EXPECT_EQ(data.symbologyIdentifier, "]z0"); - EXPECT_EQ(data.text, L"1\u001DA"); // "1D" + EXPECT_EQ(data.symbologyIdentifier(), "]z0"); + EXPECT_EQ(data.text(), L"1\u001DA"); // "1D" } } // Helper taking 5-bit word array to call GetEncodedData() -static Aztec::AztecData getData(const ByteArray& bytes) +static DecoderResult getData(const ByteArray& bytes) { BitArray bits; // 5-bit words (assuming no digits/binary) for (auto b : bytes) bits.appendBits(b, 5); - return Aztec::GetEncodedData(bits); + return Aztec::Decode(bits); } // Shorthand to return Structured Append given 5-bit word array static StructuredAppendInfo sai(const ByteArray& bytes) { - return getData(bytes).sai; + return getData(bytes).structuredAppend(); } // Shorthand to return string result given 5-bit word array static std::wstring text(const ByteArray& bytes) { - return getData(bytes).text; + return getData(bytes).text(); } TEST(AZDecoderTest, StructuredAppend) @@ -346,30 +323,30 @@ TEST(AZDecoderTest, StructuredAppend) // Invalid Ids { auto data = getData({29, 29, 1, 10, 5, 2, 5, 2}); // No terminating space - EXPECT_TRUE(data.sai.id.empty()); - EXPECT_EQ(data.sai.index, -1); // Not recognized as sequence - EXPECT_EQ(data.sai.count, -1); - EXPECT_EQ(data.text, L" IDADA"); // Bad ID and sequencing left in result + EXPECT_TRUE(data.structuredAppend().id.empty()); + EXPECT_EQ(data.structuredAppend().index, -1); // Not recognized as sequence + EXPECT_EQ(data.structuredAppend().count, -1); + EXPECT_EQ(data.text(), L" IDADA"); // Bad ID and sequencing left in result } { auto data = getData({29, 29, 1, 1, 2, 5, 2}); // Blank - EXPECT_TRUE(data.sai.id.empty()); - EXPECT_EQ(data.sai.index, 0); // Recognized as sequence - EXPECT_EQ(data.sai.count, 4); - EXPECT_EQ(data.text, L"A"); + EXPECT_TRUE(data.structuredAppend().id.empty()); + EXPECT_EQ(data.structuredAppend().index, 0); // Recognized as sequence + EXPECT_EQ(data.structuredAppend().count, 4); + EXPECT_EQ(data.text(), L"A"); } { auto data = getData({29, 29, 1, 10, 1, 5, 1, 2, 5, 2}); // Space in "I D" - EXPECT_TRUE(data.sai.id.empty()); - EXPECT_EQ(data.sai.index, -1); // Not recognized as sequence as sequence count invalid (space) - EXPECT_EQ(data.sai.count, -1); - EXPECT_EQ(data.text, L" I D ADA"); // Bad ID and sequencing left in result + EXPECT_TRUE(data.structuredAppend().id.empty()); + EXPECT_EQ(data.structuredAppend().index, -1); // Not recognized as sequence as sequence count invalid (space) + EXPECT_EQ(data.structuredAppend().count, -1); + EXPECT_EQ(data.text(), L" I D ADA"); // Bad ID and sequencing left in result } { auto data = getData({29, 29, 1, 10, 1, 2, 5, 1, 2, 5, 2}); // "I AD" (happens to have valid sequencing at end) - EXPECT_EQ(data.sai.id, "I"); - EXPECT_EQ(data.sai.index, 0); - EXPECT_EQ(data.sai.count, 4); - EXPECT_EQ(data.text, L" ADA"); // Trailing space and "real" sequencing left in result + EXPECT_EQ(data.structuredAppend().id, "I"); + EXPECT_EQ(data.structuredAppend().index, 0); + EXPECT_EQ(data.structuredAppend().count, 4); + EXPECT_EQ(data.text(), L" ADA"); // Trailing space and "real" sequencing left in result } } diff --git a/test/unit/aztec/AZDetectorTest.cpp b/test/unit/aztec/AZDetectorTest.cpp index 42a9885ee9..fd7a4f1191 100644 --- a/test/unit/aztec/AZDetectorTest.cpp +++ b/test/unit/aztec/AZDetectorTest.cpp @@ -1,19 +1,8 @@ /* * Copyright 2017 Huy Cuong Nguyen * Copyright 2013 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "aztec/AZDetector.h" diff --git a/test/unit/aztec/AZEncodeDecodeTest.cpp b/test/unit/aztec/AZEncodeDecodeTest.cpp index d09f0bd6f9..b28b9135e3 100644 --- a/test/unit/aztec/AZEncodeDecodeTest.cpp +++ b/test/unit/aztec/AZEncodeDecodeTest.cpp @@ -1,19 +1,8 @@ /* * Copyright 2017 Huy Cuong Nguyen * Copyright 2013 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "BitMatrix.h" #include "CharacterSet.h" @@ -97,10 +86,9 @@ namespace { EXPECT_EQ(aztec.matrix, matrix); - std::wstring expectedData = TextDecoder::ToUnicode(textBytes, CharacterSet::ISO8859_1); DecoderResult res = parse(matrix.copy(), aztec.compact, aztec.codeWords, aztec.layers); EXPECT_EQ(res.isValid(), true); - EXPECT_EQ(res.text(), expectedData); + EXPECT_EQ(res.content().bytes, ByteArray(textBytes)); // Check error correction by introducing up to eccPercent/2 errors int ecWords = aztec.codeWords * eccPercent / 100 / 2; @@ -117,7 +105,7 @@ namespace { } res = parse(std::move(matrix), aztec.compact, aztec.codeWords, aztec.layers); EXPECT_EQ(res.isValid(), true); - EXPECT_EQ(res.text(), expectedData); + EXPECT_EQ(res.content().bytes, ByteArray(textBytes)); } } diff --git a/test/unit/aztec/AZEncoderTest.cpp b/test/unit/aztec/AZEncoderTest.cpp index 7fa4b69d53..045f15e3f3 100644 --- a/test/unit/aztec/AZEncoderTest.cpp +++ b/test/unit/aztec/AZEncoderTest.cpp @@ -1,19 +1,8 @@ /* * Copyright 2017 Huy Cuong Nguyen * Copyright 2013 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "aztec/AZEncoder.h" #include "BitArray.h" diff --git a/test/unit/aztec/AZHighLevelEncoderTest.cpp b/test/unit/aztec/AZHighLevelEncoderTest.cpp index 2b55de86a9..0869921bdf 100644 --- a/test/unit/aztec/AZHighLevelEncoderTest.cpp +++ b/test/unit/aztec/AZHighLevelEncoderTest.cpp @@ -1,23 +1,13 @@ /* * Copyright 2017 Huy Cuong Nguyen * Copyright 2013 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "aztec/AZHighLevelEncoder.h" #include "BitArray.h" #include "BitArrayUtility.h" +#include "DecoderResult.h" #include "StructuredAppend.h" #include "TextDecoder.h" @@ -26,14 +16,7 @@ namespace ZXing::Aztec { -struct AztecData -{ - std::wstring text; - std::string symbologyIdentifier; - StructuredAppendInfo sai; -}; - -AztecData GetEncodedData(const BitArray& bits, const std::string& characterSet = ""); +DecoderResult Decode(const BitArray& bits); } @@ -48,16 +31,14 @@ namespace { void TestHighLevelEncodeString(const std::string& s, const std::string& expectedBits) { BitArray bits = Aztec::HighLevelEncoder::Encode(s); EXPECT_EQ(Utility::ToString(bits), StripSpaces(expectedBits)) << "highLevelEncode() failed for input string: " + s; - EXPECT_EQ(TextDecoder::FromLatin1(s), Aztec::GetEncodedData(bits).text); + EXPECT_EQ(TextDecoder::FromLatin1(s), Aztec::Decode(bits).text()); } void TestHighLevelEncodeString(const std::string& s, int expectedReceivedBits) { BitArray bits = Aztec::HighLevelEncoder::Encode(s); int receivedBitCount = Size(Utility::ToString(bits)); EXPECT_EQ(receivedBitCount, expectedReceivedBits) << "highLevelEncode() failed for input string: " + s; - std::string symbologyIdentifier; - StructuredAppendInfo sai; - EXPECT_EQ(TextDecoder::FromLatin1(s), Aztec::GetEncodedData(bits).text); + EXPECT_EQ(ByteArray(s), Aztec::Decode(bits).content().bytes); } } diff --git a/test/unit/datamatrix/DMDecodedBitStreamParserTest.cpp b/test/unit/datamatrix/DMDecodedBitStreamParserTest.cpp index ad3db44716..1e03a453dd 100644 --- a/test/unit/datamatrix/DMDecodedBitStreamParserTest.cpp +++ b/test/unit/datamatrix/DMDecodedBitStreamParserTest.cpp @@ -1,19 +1,8 @@ /* * Copyright 2017 Huy Cuong Nguyen * Copyright 2008 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "ByteArray.h" #include "DecoderResult.h" @@ -23,7 +12,7 @@ namespace ZXing::DataMatrix::DecodedBitStreamParser { -DecoderResult Decode(ByteArray&& bytes, const std::string& characterSet, const bool isDMRE); +DecoderResult Decode(ByteArray&& bytes, const bool isDMRE); } @@ -32,7 +21,7 @@ using namespace ZXing; // Helper to call Decode() static DecoderResult parse(ByteArray bytes, const bool isDMRE = false) { - return DataMatrix::DecodedBitStreamParser::Decode(std::move(bytes), "", isDMRE); + return DataMatrix::DecodedBitStreamParser::Decode(std::move(bytes), isDMRE); } // Shorthand to return text @@ -65,13 +54,13 @@ TEST(DMDecodeTest, Ascii) TEST(DMDecodeTest, AsciiError) { // ASCII err on invalid code word - EXPECT_EQ(parse({66, 250, 68}).errorCode(), DecodeStatus::FormatError); + EXPECT_EQ(parse({66, 250, 68}).error(), Error::Format); // ASCII err on invalid code word at end (currently failing) - EXPECT_EQ(parse({66, 67, 68, 250}).errorCode(), DecodeStatus::FormatError); + EXPECT_EQ(parse({66, 67, 68, 250}).error(), Error::Format); // ASCII accept extra (illegal) unlatch at end - EXPECT_EQ(parse({66, 67, 68, 254}).errorCode(), DecodeStatus::NoError); + EXPECT_FALSE(parse({66, 67, 68, 254}).error()); } // Most of the following examples are taken from the DMHighLevelEncodeTest.cpp tests. diff --git a/test/unit/datamatrix/DMEncodeDecodeTest.cpp b/test/unit/datamatrix/DMEncodeDecodeTest.cpp index bb98ef01e4..10a4f7b98d 100644 --- a/test/unit/datamatrix/DMEncodeDecodeTest.cpp +++ b/test/unit/datamatrix/DMEncodeDecodeTest.cpp @@ -1,19 +1,8 @@ /* * Copyright 2017 Axel Waggershauser * Copyright 2013 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "BitMatrixIO.h" #include "DecoderResult.h" diff --git a/test/unit/datamatrix/DMHighLevelEncodeTest.cpp b/test/unit/datamatrix/DMHighLevelEncodeTest.cpp index 05e368e01e..5a8a57ef6e 100644 --- a/test/unit/datamatrix/DMHighLevelEncodeTest.cpp +++ b/test/unit/datamatrix/DMHighLevelEncodeTest.cpp @@ -1,22 +1,11 @@ /* * Copyright 2017 Huy Cuong Nguyen * Copyright 2006 Jeremias Maerki. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "ByteArray.h" -#include "ZXContainerAlgorithms.h" +#include "ZXAlgorithms.h" #include "datamatrix/DMHighLevelEncoder.h" #include "datamatrix/DMSymbolInfo.h" #include "datamatrix/DMSymbolShape.h" diff --git a/test/unit/datamatrix/DMPlacementTest.cpp b/test/unit/datamatrix/DMPlacementTest.cpp index a7ad679936..091d365fbf 100644 --- a/test/unit/datamatrix/DMPlacementTest.cpp +++ b/test/unit/datamatrix/DMPlacementTest.cpp @@ -1,19 +1,8 @@ /* * Copyright 2017 Huy Cuong Nguyen * Copyright 2006 Jeremias Maerki -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "BitMatrixIO.h" #include "ByteArray.h" diff --git a/test/unit/datamatrix/DMSymbolInfoTest.cpp b/test/unit/datamatrix/DMSymbolInfoTest.cpp index 7a5c13562a..bae53e8542 100644 --- a/test/unit/datamatrix/DMSymbolInfoTest.cpp +++ b/test/unit/datamatrix/DMSymbolInfoTest.cpp @@ -1,19 +1,8 @@ /* * Copyright 2017 Huy Cuong Nguyen * Copyright 2006 Jeremias Maerki -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "datamatrix/DMSymbolInfo.h" #include "datamatrix/DMSymbolShape.h" diff --git a/test/unit/datamatrix/DMWriterTest.cpp b/test/unit/datamatrix/DMWriterTest.cpp index b60d4818ff..4aa0738e51 100644 --- a/test/unit/datamatrix/DMWriterTest.cpp +++ b/test/unit/datamatrix/DMWriterTest.cpp @@ -1,19 +1,8 @@ /* * Copyright 2017 Huy Cuong Nguyen * Copyright 2008 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "datamatrix/DMWriter.h" #include "BitMatrixIO.h" diff --git a/test/unit/maxicode/MCDecoderTest.cpp b/test/unit/maxicode/MCDecoderTest.cpp index 150f4542ec..e811107c0f 100644 --- a/test/unit/maxicode/MCDecoderTest.cpp +++ b/test/unit/maxicode/MCDecoderTest.cpp @@ -1,18 +1,7 @@ /* * Copyright 2021 gitlost -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "ByteArray.h" #include "DecoderResult.h" @@ -22,7 +11,7 @@ namespace ZXing::MaxiCode::DecodedBitStreamParser { -DecoderResult Decode(ByteArray&& bytes, const int mode, const std::string& characterSet); +DecoderResult Decode(ByteArray&& bytes, const int mode); } @@ -52,7 +41,7 @@ static DecoderResult parse(ByteArray bytes, const int mode) } padded.insert(padded.end(), bytes.begin(), bytes.end()); pad(padded); - return MaxiCode::DecodedBitStreamParser::Decode(std::move(padded), mode, ""); + return MaxiCode::DecodedBitStreamParser::Decode(std::move(padded), mode); } // Helper to return Structured Append @@ -87,7 +76,7 @@ TEST(MCDecodeTest, StructuredAppendSymbologyIdentifier) EXPECT_EQ(info({49}, 6).index, -1); // Mode 6 EXPECT_EQ(info({49}, 6).count, -1); EXPECT_TRUE(info({49}, 6).id.empty()); - EXPECT_TRUE(parse({49}, 6).symbologyIdentifier().empty()); // Not defined for reader initialisation/programming +// EXPECT_TRUE(parse({49}, 6).symbologyIdentifier().empty()); // Not defined for reader initialisation/programming // ISO/IEC 16023:2000 4.9.1 example EXPECT_EQ(info({33, 22, 49}, 2).index, 2); // Mode 2 - 3rd position 1-based == index 2 diff --git a/test/unit/oned/ODCodaBarWriterTest.cpp b/test/unit/oned/ODCodaBarWriterTest.cpp index 5958cc13c9..9ae038db5e 100644 --- a/test/unit/oned/ODCodaBarWriterTest.cpp +++ b/test/unit/oned/ODCodaBarWriterTest.cpp @@ -1,19 +1,8 @@ /* * Copyright 2017 Huy Cuong Nguyen * Copyright 2011 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "oned/ODCodabarWriter.h" #include "BitArray.h" @@ -21,6 +10,7 @@ #include "DecodeHints.h" #include "Result.h" #include "oned/ODCodabarReader.h" +#include "TextUtfEncoding.h" #include "gtest/gtest.h" #include @@ -29,7 +19,7 @@ using namespace ZXing; using namespace ZXing::OneD; namespace { - std::string Encode(const std::wstring& input) + std::string Encode(const std::string& input) { auto result = ToString(CodabarWriter().encode(input, 0, 0), '1', '0', false); return result.substr(0, result.size() - 1); // remove the \n at the end @@ -38,7 +28,7 @@ namespace { TEST(ODCodaBarWriterTest, Encode) { - EXPECT_EQ(Encode(L"B515-3/B"), + EXPECT_EQ(Encode("B515-3/B"), "00000" "1001001011" "0110101001" "0101011001" "0110101001" "0101001101" "0110010101" "01101101011" "01001001011" @@ -47,7 +37,7 @@ TEST(ODCodaBarWriterTest, Encode) TEST(ODCodaBarWriterTest, Encode2) { - EXPECT_EQ(Encode(L"T123T"), + EXPECT_EQ(Encode("T123T"), "00000" "1011001001" "0101011001" "0101001011" "0110010101" "01011001001" "00000"); @@ -55,20 +45,21 @@ TEST(ODCodaBarWriterTest, Encode2) TEST(ODCodaBarWriterTest, AltStartEnd) { - EXPECT_EQ(Encode(L"T123456789-$T"), Encode(L"A123456789-$A")); + EXPECT_EQ(Encode("T123456789-$T"), Encode("A123456789-$A")); } TEST(ODCodaBarWriterTest, FullCircle) { - std::wstring text = L"A0123456789-$:/.+A"; + std::string text = "A0123456789-$:/.+A"; BitArray row; CodabarWriter().encode(text, 0, 0).getRow(0, row); - Result res = CodabarReader(DecodeHints().setReturnCodabarStartEnd(true)).decodeSingleRow(0, row); + auto hints = DecodeHints().setReturnCodabarStartEnd(true); + Result res = CodabarReader(hints).decodeSingleRow(0, row); EXPECT_EQ(text, res.text()); } TEST(ODCodaBarWriterTest, InvalidChars) { - EXPECT_THROW({Encode(L"AxA");}, std::invalid_argument ); - EXPECT_THROW({Encode(L"a0a");}, std::invalid_argument ); + EXPECT_THROW({Encode("AxA");}, std::invalid_argument ); + EXPECT_THROW({Encode("a0a");}, std::invalid_argument ); } diff --git a/test/unit/oned/ODCode128ReaderTest.cpp b/test/unit/oned/ODCode128ReaderTest.cpp index 87af89dbfb..7f3ad3e30d 100644 --- a/test/unit/oned/ODCode128ReaderTest.cpp +++ b/test/unit/oned/ODCode128ReaderTest.cpp @@ -1,21 +1,11 @@ /* * Copyright 2021 gitlost -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "oned/ODCode128Reader.h" +#include "DecodeHints.h" #include "Result.h" #include "gtest/gtest.h" @@ -36,7 +26,8 @@ static Result parse(const int startPattern, PatternRow row) row.insert(row.end(), { 2, 3, 3, 1, 1, 1, 2, 0 }); // Stop pattern std::unique_ptr state; - Code128Reader reader; + DecodeHints hints; + Code128Reader reader(hints); PatternView next(row); return reader.decodePattern(0, next, state); } @@ -48,7 +39,7 @@ TEST(ODCode128ReaderTest, SymbologyIdentifier) PatternRow row({ 2, 2, 1, 2, 3, 1, 2, 2, 2, 1, 2, 2, 3, 1, 1, 2, 2, 2 }); auto result = parse('C', row); EXPECT_EQ(result.symbologyIdentifier(), "]C0"); - EXPECT_EQ(result.text(), L"2001"); + EXPECT_EQ(result.text(), "2001"); } { @@ -56,7 +47,7 @@ TEST(ODCode128ReaderTest, SymbologyIdentifier) PatternRow row({ 4, 1, 1, 1, 3, 1, 2, 2, 1, 2, 3, 1, 2, 2, 2, 1, 2, 2, 1, 3, 2, 1, 3, 1 }); auto result = parse('C', row); EXPECT_EQ(result.symbologyIdentifier(), "]C1"); - EXPECT_EQ(result.text(), L"2001"); + EXPECT_EQ(result.text(), "2001"); } { @@ -64,7 +55,7 @@ TEST(ODCode128ReaderTest, SymbologyIdentifier) PatternRow row({ 1, 1, 1, 3, 2, 3, 4, 1, 1, 1, 3, 1, 1, 3, 1, 1, 2, 3, 2, 1, 2, 3, 2, 1 }); auto result = parse('B', row); EXPECT_EQ(result.symbologyIdentifier(), "]C2"); - EXPECT_EQ(result.text(), L"AB"); + EXPECT_EQ(result.text(), "AB"); } { @@ -72,7 +63,7 @@ TEST(ODCode128ReaderTest, SymbologyIdentifier) PatternRow row({ 2, 1, 4, 1, 2, 1, 4, 1, 1, 1, 3, 1, 1, 3, 1, 1, 2, 3, 4, 2, 1, 2, 1, 1 }); auto result = parse('B', row); EXPECT_EQ(result.symbologyIdentifier(), "]C2"); - EXPECT_EQ(result.text(), L"zB"); + EXPECT_EQ(result.text(), "zB"); } { @@ -80,7 +71,7 @@ TEST(ODCode128ReaderTest, SymbologyIdentifier) PatternRow row({ 1, 1, 3, 1, 4, 1, 4, 1, 1, 1, 3, 1, 1, 1, 4, 1, 3, 1, 1, 1, 1, 3, 2, 3, 1, 2, 3, 1, 2, 2 }); auto result = parse('C', row); EXPECT_EQ(result.symbologyIdentifier(), "]C2"); - EXPECT_EQ(result.text(), L"99A"); + EXPECT_EQ(result.text(), "99A"); } { @@ -88,7 +79,7 @@ TEST(ODCode128ReaderTest, SymbologyIdentifier) PatternRow row({ 2, 1, 2, 3, 2, 1, 4, 1, 1, 1, 3, 1, 1, 3, 1, 1, 2, 3, 3, 2, 2, 2, 1, 1 }); auto result = parse('B', row); EXPECT_EQ(result.symbologyIdentifier(), "]C0"); // Just ignoring, not giving FormatError - EXPECT_EQ(result.text(), L"?\u001DB"); + EXPECT_EQ(result.text(), "?\u001DB"); } } @@ -99,7 +90,7 @@ TEST(ODCode128ReaderTest, ReaderInit) PatternRow row({ 1, 1, 1, 1, 4, 3, 1, 3, 1, 1, 4, 1 }); auto result = parse('C', row); EXPECT_FALSE(result.readerInit()); - EXPECT_EQ(result.text(), L"92"); + EXPECT_EQ(result.text(), "92"); } { @@ -107,7 +98,7 @@ TEST(ODCode128ReaderTest, ReaderInit) PatternRow row({ 1, 1, 4, 3, 1, 1, 1, 1, 3, 1, 4, 1, 1, 1, 1, 1, 4, 3, 3, 3, 1, 1, 2, 1 }); auto result = parse('B', row); EXPECT_TRUE(result.readerInit()); - EXPECT_EQ(result.text(), L"92"); + EXPECT_EQ(result.text(), "92"); } { @@ -115,6 +106,6 @@ TEST(ODCode128ReaderTest, ReaderInit) PatternRow row({ 3, 2, 1, 1, 2, 2, 1, 1, 4, 3, 1, 1, 2, 2, 3, 2, 1, 1, 1, 2, 1, 4, 2, 1 }); auto result = parse('B', row); EXPECT_TRUE(result.readerInit()); - EXPECT_EQ(result.text(), L"92"); + EXPECT_EQ(result.text(), "92"); } } diff --git a/test/unit/oned/ODCode128WriterTest.cpp b/test/unit/oned/ODCode128WriterTest.cpp index 65636d64ec..bc9db158be 100644 --- a/test/unit/oned/ODCode128WriterTest.cpp +++ b/test/unit/oned/ODCode128WriterTest.cpp @@ -1,22 +1,12 @@ /* * Copyright 2017 Huy Cuong Nguyen * Copyright 2014 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "oned/ODCode128Writer.h" #include "BitMatrixIO.h" +#include "DecodeHints.h" #include "Result.h" #include "oned/ODCode128Reader.h" @@ -49,7 +39,8 @@ static ZXing::Result Decode(const BitMatrix &matrix) { BitArray row; matrix.getRow(0, row); - return Code128Reader().decodeSingleRow(0, row); + DecodeHints hints; + return Code128Reader(hints).decodeSingleRow(0, row); } TEST(ODCode128Writer, EncodeWithFunc1) @@ -103,7 +94,7 @@ TEST(ODCode128Writer, EncodeWithFncsAndNumberInCodesetA) TEST(ODCode128Writer, RoundtripGS1) { auto toEncode = L"\xf1" "10958" "\xf1" "17160526"; - auto expected = L"10958\u001D17160526"; + auto expected = "10958\u001D17160526"; auto encResult = Code128Writer().encode(toEncode, 0, 0); auto decResult = Decode(encResult); @@ -115,7 +106,7 @@ TEST(ODCode128Writer, RoundtripGS1) TEST(ODCode128Writer, RoundtripFNC1) { auto toEncode = L"1\xf1" "0958" "\xf1" "17160526"; - auto expected = L"1\u001D0958\u001D17160526"; + auto expected = "1\u001D0958\u001D17160526"; auto encResult = Code128Writer().encode(toEncode, 0, 0); auto decResult = Decode(encResult); @@ -127,7 +118,7 @@ TEST(ODCode128Writer, RoundtripFNC1) TEST(ODCode128Writer, EncodeSwitchCodesetFromAToB) { // start with A switch to B and back to A - auto toEncode = std::wstring(L"\0ABab\u0010", 6); + auto toEncode = std::string("\0ABab\u0010", 6); // "\0" "A" "B" Switch to B "a" "b" Switch to A "\u0010" check digit auto expected = QUIET_SPACE + START_CODE_A + "10100001100" + "10100011000" + "10001011000" + SWITCH_CODE_B + "10010110000" + "10010000110" + SWITCH_CODE_A + "10100111100" + "11001110100" + STOP + QUIET_SPACE; @@ -142,7 +133,7 @@ TEST(ODCode128Writer, EncodeSwitchCodesetFromAToB) TEST(ODCode128Writer, EncodeSwitchCodesetFromBToA) { // start with B switch to A and back to B - auto toEncode = std::wstring(L"ab\0ab", 5); + auto toEncode = std::string("ab\0ab", 5); // "a" "b" Switch to A "\0 "Switch to B" "a" "b" check digit auto expected = QUIET_SPACE + START_CODE_B + "10010110000" + "10010000110" + SWITCH_CODE_A + "10100001100" + SWITCH_CODE_B + "10010110000" + "10010000110" + "11010001110" + STOP + QUIET_SPACE; diff --git a/test/unit/oned/ODCode39ExtendedModeTest.cpp b/test/unit/oned/ODCode39ExtendedModeTest.cpp index dd92d53b75..d25d7a6205 100644 --- a/test/unit/oned/ODCode39ExtendedModeTest.cpp +++ b/test/unit/oned/ODCode39ExtendedModeTest.cpp @@ -1,19 +1,8 @@ /* * Copyright 2017 Huy Cuong Nguyen * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "BitArray.h" #include "BitArrayUtility.h" @@ -26,9 +15,10 @@ using namespace ZXing; using namespace ZXing::OneD; -static std::wstring Decode(std::string_view encoded) +static std::string Decode(std::string_view encoded) { - Code39Reader sut(DecodeHints().setTryCode39ExtendedMode(true)); + auto hints = DecodeHints().setTryCode39ExtendedMode(true); + Code39Reader sut(hints); BitArray row = Utility::ParseBitArray(encoded, '1'); Result result = sut.decodeSingleRow(0, row); return result.text(); @@ -48,7 +38,7 @@ TEST(ODCode39ExtendedModeTest, Decode) "10100100100101010010110101101001001001010110010110101010010010010101001101101010" "10100100100101101010010110101001001001010110100101101010010010010110110100101010" "1001001001010101100101101010010010010110101100101010010110110100000"), - std::wstring(L"\x0\x1\x2\x3\x4\x5\x6\x7\x8\x9\xa\xb\xc\xd\xe\xf\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", 0x20)); + std::string("\x0\x1\x2\x3\x4\x5\x6\x7\x8\x9\xa\xb\xc\xd\xe\xf\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f", 0x20)); EXPECT_EQ(Decode( "00000100101101101010011010110101001001010010110101001011010010010100101011010010" @@ -60,7 +50,7 @@ TEST(ODCode39ExtendedModeTest, Decode) "10101010100101101101101001011010101100101101010010010100101001101101010101001001" "00101011011001010101001001001010101001101101010010010010110101001101010100100100" "1010110100110101010010010010101011001101010010110110100000"), - L" !\"#$%&'()*+,-./0123456789:;<=>?"); + " !\"#$%&'()*+,-./0123456789:;<=>?"); EXPECT_EQ(Decode( "00001001011011010101001001001010011010101101101010010110101101001011011011010010" @@ -70,7 +60,7 @@ TEST(ODCode39ExtendedModeTest, Decode) "10101011011001101010101001011010110110010110101010011011010101010010010010110101" "01001101010010010010101101010011010100100100101101101010010101001001001010101101" "001101010010010010110101101001010010110110100000"), - L"@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"); + "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"); EXPECT_EQ(Decode( "00000100101101101010100100100101100110101010100101001001011010100101101001010010" @@ -84,5 +74,5 @@ TEST(ODCode39ExtendedModeTest, Decode) "10100101001001010010110101101001010010010110010110101010010100100101001101101010" "10100100100101011011010010101001001001010101011001101010010010010110101011001010" "1001001001010110101100101010010010010101011011001010010110110100000"), - L"`abcdefghijklmnopqrstuvwxyz{|}~"); + "`abcdefghijklmnopqrstuvwxyz{|}~"); } diff --git a/test/unit/oned/ODCode39ReaderTest.cpp b/test/unit/oned/ODCode39ReaderTest.cpp index c92d88202f..e33f587a0c 100644 --- a/test/unit/oned/ODCode39ReaderTest.cpp +++ b/test/unit/oned/ODCode39ReaderTest.cpp @@ -1,18 +1,7 @@ /* * Copyright 2022 gitlost -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "oned/ODCode39Reader.h" @@ -44,39 +33,39 @@ TEST(ODCode39ReaderTest, SymbologyIdentifier) PatternRow row({ 2, 1, 1, 1, 1, 2, 1, 1, 2 }); auto result = parse(row); EXPECT_EQ(result.symbologyIdentifier(), "]A0"); - EXPECT_EQ(result.text(), L"A"); + EXPECT_EQ(result.text(), "A"); } { // "A" with checksum PatternRow row({ 2, 1, 1, 1, 1, 2, 1, 1, 2, 0, 2, 1, 1, 1, 1, 2, 1, 1, 2 }); auto result = parse(row, DecodeHints().setValidateCode39CheckSum(true)); EXPECT_EQ(result.symbologyIdentifier(), "]A3"); - EXPECT_EQ(result.text(), L"A"); + EXPECT_EQ(result.text(), "A"); result = parse(row); EXPECT_EQ(result.symbologyIdentifier(), "]A0"); - EXPECT_EQ(result.text(), L"AA"); + EXPECT_EQ(result.text(), "AA"); } { // Extended "a" PatternRow row({ 1, 2, 1, 1, 1, 2, 1, 2, 1, 0, 2, 1, 1, 1, 1, 2, 1, 1, 2 }); auto result = parse(row, DecodeHints().setTryCode39ExtendedMode(true)); EXPECT_EQ(result.symbologyIdentifier(), "]A4"); - EXPECT_EQ(result.text(), L"a"); + EXPECT_EQ(result.text(), "a"); result = parse(row); EXPECT_EQ(result.symbologyIdentifier(), "]A0"); - EXPECT_EQ(result.text(), L"+A"); + EXPECT_EQ(result.text(), "+A"); } { // Extended "a" with checksum PatternRow row({ 1, 2, 1, 1, 1, 2, 1, 2, 1, 0, 2, 1, 1, 1, 1, 2, 1, 1, 2, 0, 2, 1, 1, 2, 1, 1, 2, 1, 1 }); auto result = parse(row, DecodeHints().setTryCode39ExtendedMode(true).setValidateCode39CheckSum(true)); EXPECT_EQ(result.symbologyIdentifier(), "]A7"); - EXPECT_EQ(result.text(), L"a"); + EXPECT_EQ(result.text(), "a"); result = parse(row); EXPECT_EQ(result.symbologyIdentifier(), "]A0"); - EXPECT_EQ(result.text(), L"+A8"); + EXPECT_EQ(result.text(), "+A8"); } } diff --git a/test/unit/oned/ODCode39WriterTest.cpp b/test/unit/oned/ODCode39WriterTest.cpp index 7ab6e8fb47..0d98c4c250 100644 --- a/test/unit/oned/ODCode39WriterTest.cpp +++ b/test/unit/oned/ODCode39WriterTest.cpp @@ -1,19 +1,8 @@ /* * Copyright 2017 Huy Cuong Nguyen * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "oned/ODCode39Writer.h" #include "BitMatrixIO.h" diff --git a/test/unit/oned/ODCode93ReaderTest.cpp b/test/unit/oned/ODCode93ReaderTest.cpp index 1fc060c6f4..93d7557e3b 100644 --- a/test/unit/oned/ODCode93ReaderTest.cpp +++ b/test/unit/oned/ODCode93ReaderTest.cpp @@ -1,23 +1,13 @@ /* * Copyright 2017 Huy Cuong Nguyen * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "oned/ODCode93Reader.h" #include "BitArray.h" #include "BitArrayUtility.h" +#include "DecodeHints.h" #include "Result.h" #include "gtest/gtest.h" @@ -25,9 +15,10 @@ using namespace ZXing; using namespace ZXing::OneD; -static std::wstring Decode(std::string_view input) +static std::string Decode(std::string_view input) { - Code93Reader sut; + DecodeHints hints; + Code93Reader sut(hints); auto row = Utility::ParseBitArray(input, '1'); auto result = sut.decodeSingleRow(0, row); return result.text(); @@ -35,7 +26,7 @@ static std::wstring Decode(std::string_view input) TEST(ODCode93ReaderTest, Decode) { - auto expected = std::wstring(L"Code93!\n$%/+ :\x1b;[{\x7f\x00@`\x7f\x7f\x7f", 25); + auto expected = std::string("Code93!\n$%/+ :\x1b;[{\x7f\x00@`\x7f\x7f\x7f", 25); auto decoded = Decode( "00000010101111011010001010011001010010110010011001011001010010011001011001001010" "00010101010000101110101101101010001001001101001101001110010101101011101011011101" diff --git a/test/unit/oned/ODCode93WriterTest.cpp b/test/unit/oned/ODCode93WriterTest.cpp index f1c560982c..beaf6965b5 100644 --- a/test/unit/oned/ODCode93WriterTest.cpp +++ b/test/unit/oned/ODCode93WriterTest.cpp @@ -1,19 +1,8 @@ /* * Copyright 2017 Huy Cuong Nguyen * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "oned/ODCode93Writer.h" #include "BitMatrixIO.h" diff --git a/test/unit/oned/rss/ODRSSExpandedBinaryDecoderTest.cpp b/test/unit/oned/ODDataBarExpandedBitDecoderTest.cpp similarity index 74% rename from test/unit/oned/rss/ODRSSExpandedBinaryDecoderTest.cpp rename to test/unit/oned/ODDataBarExpandedBitDecoderTest.cpp index 12df29d4bb..27e6902a63 100644 --- a/test/unit/oned/rss/ODRSSExpandedBinaryDecoderTest.cpp +++ b/test/unit/oned/ODDataBarExpandedBitDecoderTest.cpp @@ -1,22 +1,12 @@ /* * Copyright 2021 gitlost -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "BitArray.h" #include "BitArrayUtility.h" -#include "oned/rss/ODRSSExpandedBinaryDecoder.h" +#include "GS1.h" +#include "oned/ODDataBarExpandedBitDecoder.h" #include "gtest/gtest.h" @@ -24,10 +14,10 @@ using namespace ZXing; static std::string parse(std::string bitStr) { - return OneD::DataBar::DecodeExpandedBits(Utility::ParseBitArray(bitStr, '1')); + return HRIFromGS1(OneD::DataBar::DecodeExpandedBits(Utility::ParseBitArray(bitStr, '1'))); } -TEST(ODRSSExpandedBinaryDecoderTest, FNC1NumericLatch) +TEST(ODDataBarExpandedBitDecoderTest, FNC1NumericLatch) { std::string result; @@ -48,7 +38,7 @@ TEST(ODRSSExpandedBinaryDecoderTest, FNC1NumericLatch) EXPECT_EQ(result, "(10)12((422)123"); } -TEST(ODRSSExpandedBinaryDecoderTest, DecodeAI01392x) +TEST(ODDataBarExpandedBitDecoderTest, DecodeAI01392x) { std::string result; @@ -64,7 +54,7 @@ TEST(ODRSSExpandedBinaryDecoderTest, DecodeAI01392x) EXPECT_EQ(result, "(01)90012345678908(3929)12345678901234(20)01"); } -TEST(ODRSSExpandedBinaryDecoderTest, DecodeAI01393x) +TEST(ODDataBarExpandedBitDecoderTest, DecodeAI01393x) { std::string result; diff --git a/test/unit/oned/ODEAN13WriterTest.cpp b/test/unit/oned/ODEAN13WriterTest.cpp index 7021bfac1e..c1bd1deee4 100644 --- a/test/unit/oned/ODEAN13WriterTest.cpp +++ b/test/unit/oned/ODEAN13WriterTest.cpp @@ -1,19 +1,8 @@ /* * Copyright 2017 Huy Cuong Nguyen * Copyright 2009 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "oned/ODEAN13Writer.h" #include "BitMatrixIO.h" @@ -25,7 +14,7 @@ using namespace ZXing; using namespace ZXing::OneD; namespace { - std::string Encode(const std::wstring& input) + std::string Encode(const std::string& input) { auto result = ToString(EAN13Writer().encode(input, 0, 0), '1', '0', false); return result.substr(0, result.size() - 1); // remove the \n at the end @@ -34,19 +23,19 @@ namespace { TEST(ODEAN13WriterTest, Encode1) { - std::wstring toEncode = L"5901234123457"; + std::string toEncode = "5901234123457"; std::string expected = "00001010001011010011101100110010011011110100111010101011001101101100100001010111001001110100010010100000"; EXPECT_EQ(Encode(toEncode), expected); } TEST(ODEAN13WriterTest, AddChecksumAndEncode) { - std::wstring toEncode = L"590123412345"; + std::string toEncode = "590123412345"; std::string expected = "00001010001011010011101100110010011011110100111010101011001101101100100001010111001001110100010010100000"; EXPECT_EQ(Encode(toEncode), expected); } TEST(ODEAN13WriterTest, EncodeIllegalCharacters) { - EXPECT_THROW({ Encode(L"5901234123abc"); }, std::invalid_argument); + EXPECT_THROW({ Encode("5901234123abc"); }, std::invalid_argument); } diff --git a/test/unit/oned/ODEAN8WriterTest.cpp b/test/unit/oned/ODEAN8WriterTest.cpp index 19f77bb615..6df37af6c9 100644 --- a/test/unit/oned/ODEAN8WriterTest.cpp +++ b/test/unit/oned/ODEAN8WriterTest.cpp @@ -1,19 +1,8 @@ /* * Copyright 2017 Huy Cuong Nguyen * Copyright 2009 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "oned/ODEAN8Writer.h" #include "BitMatrixIO.h" @@ -24,7 +13,7 @@ using namespace ZXing; using namespace ZXing::OneD; namespace { - std::string Encode(const std::wstring& input) + std::string Encode(const std::string& input) { auto result = ToString(EAN8Writer().encode(input, 0, 0), '1', '0', false); return result.substr(0, result.size() - 1); // remove the \n at the end @@ -33,19 +22,19 @@ namespace { TEST(ODEAN8WriterTest, Encode1) { - std::wstring toEncode = L"96385074"; + std::string toEncode = "96385074"; std::string expected = "0000101000101101011110111101011011101010100111011100101000100101110010100000"; EXPECT_EQ(Encode(toEncode), expected); } TEST(ODEAN8WriterTest, AddChecksumAndEncode) { - std::wstring toEncode = L"9638507"; + std::string toEncode = "9638507"; std::string expected = "0000101000101101011110111101011011101010100111011100101000100101110010100000"; EXPECT_EQ(Encode(toEncode), expected); } TEST(ODEAN8WriterTest, EncodeIllegalCharacters) { - EXPECT_THROW({ Encode(L"96385abc"); }, std::invalid_argument); + EXPECT_THROW({ Encode("96385abc"); }, std::invalid_argument); } diff --git a/test/unit/oned/ODITFWriterTest.cpp b/test/unit/oned/ODITFWriterTest.cpp index 89c7ebf04c..34a9d0392a 100644 --- a/test/unit/oned/ODITFWriterTest.cpp +++ b/test/unit/oned/ODITFWriterTest.cpp @@ -1,19 +1,8 @@ /* * Copyright 2017 Huy Cuong Nguyen * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "oned/ODITFWriter.h" #include "BitMatrixIO.h" diff --git a/test/unit/oned/ODUPCAWriterTest.cpp b/test/unit/oned/ODUPCAWriterTest.cpp index 1b83a168be..66e02f3f78 100644 --- a/test/unit/oned/ODUPCAWriterTest.cpp +++ b/test/unit/oned/ODUPCAWriterTest.cpp @@ -1,19 +1,8 @@ /* * Copyright 2017 Huy Cuong Nguyen * Copyright 2010 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "oned/ODUPCAWriter.h" #include "BitMatrixIO.h" @@ -24,7 +13,7 @@ using namespace ZXing; using namespace ZXing::OneD; namespace { - std::string Encode(const std::wstring& input) + std::string Encode(const std::string& input) { auto result = ToString(UPCAWriter().encode(input, 0, 0), '1', '0', false); return result.substr(0, result.size() - 1); // remove the \n at the end @@ -33,14 +22,14 @@ namespace { TEST(ODUPCAWriterTest, Encode1) { - std::wstring toEncode = L"485963095124"; + std::string toEncode = "485963095124"; std::string expected = "00001010100011011011101100010001011010111101111010101011100101110100100111011001101101100101110010100000"; EXPECT_EQ(Encode(toEncode), expected); } TEST(ODUPCAWriterTest, AddChecksumAndEncode) { - std::wstring toEncode = L"12345678901"; + std::string toEncode = "12345678901"; std::string expected = "00001010011001001001101111010100011011000101011110101010001001001000111010011100101100110110110010100000"; EXPECT_EQ(Encode(toEncode), expected); } diff --git a/test/unit/oned/ODUPCEWriterTest.cpp b/test/unit/oned/ODUPCEWriterTest.cpp index 1d7970f3d5..271a817ced 100644 --- a/test/unit/oned/ODUPCEWriterTest.cpp +++ b/test/unit/oned/ODUPCEWriterTest.cpp @@ -1,19 +1,8 @@ /* * Copyright 2017 Huy Cuong Nguyen * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "oned/ODUPCEWriter.h" #include "BitMatrixIO.h" @@ -25,7 +14,7 @@ using namespace ZXing; using namespace ZXing::OneD; namespace { - std::string Encode(const std::wstring& input) + std::string Encode(const std::string& input) { auto result = ToString(UPCEWriter().encode(input, 0, 0), '1', '0', false); return result.substr(0, result.size() - 1); // remove the \n at the end @@ -34,26 +23,26 @@ namespace { TEST(ODUPCEWriterTest, Encode1) { - std::wstring toEncode = L"05096893"; + std::string toEncode = "05096893"; std::string expected = "000010101110010100111000101101011110110111001011101010100000"; EXPECT_EQ(Encode(toEncode), expected); } TEST(ODUPCEWriterTest, EncodeSystem1) { - std::wstring toEncode = L"12345670"; + std::string toEncode = "12345670"; std::string expected = "000010100100110111101010001101110010000101001000101010100000"; EXPECT_EQ(Encode(toEncode), expected); } TEST(ODUPCEWriterTest, AddChecksumAndEncode) { - std::wstring toEncode = L"0509689"; + std::string toEncode = "0509689"; std::string expected = "000010101110010100111000101101011110110111001011101010100000"; EXPECT_EQ(Encode(toEncode), expected); } TEST(ODUPCEWriterTest, EncodeIllegalCharacters) { - EXPECT_THROW(Encode(L"05096abc"), std::invalid_argument); + EXPECT_THROW(Encode("05096abc"), std::invalid_argument); } diff --git a/test/unit/oned/rss/ODRSSFieldParserTest.cpp b/test/unit/oned/rss/ODRSSFieldParserTest.cpp deleted file mode 100644 index dab4897508..0000000000 --- a/test/unit/oned/rss/ODRSSFieldParserTest.cpp +++ /dev/null @@ -1,431 +0,0 @@ -/* -* Copyright 2022 gitlost -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. -*/ - -#include "oned/rss/ODRSSFieldParser.h" - -#include "DecodeStatus.h" - -#include "gtest/gtest.h" - -using namespace ZXing; -using namespace ZXing::OneD::DataBar; - -TEST(ODRSSFieldParserTest, ParseFieldsInGeneralPurpose) -{ - std::string result; - - // 2-digit AIs - - // Fixed length - EXPECT_EQ(ParseFieldsInGeneralPurpose("00123456789012345678", result), DecodeStatus::NoError); - EXPECT_EQ(result, "(00)123456789012345678"); - // Incorrect lengths - EXPECT_EQ(ParseFieldsInGeneralPurpose("0012345678901234567", result), DecodeStatus::NotFound); - EXPECT_EQ(ParseFieldsInGeneralPurpose("001234567890123456789", result), DecodeStatus::NotFound); - - // Fixed length - EXPECT_EQ(ParseFieldsInGeneralPurpose("16123456", result), DecodeStatus::NoError); - EXPECT_EQ(result, "(16)123456"); - // Incorrect lengths - EXPECT_EQ(ParseFieldsInGeneralPurpose("1612345", result), DecodeStatus::NotFound); - EXPECT_EQ(ParseFieldsInGeneralPurpose("161234567", result), DecodeStatus::NotFound); - - // Max length - EXPECT_EQ(ParseFieldsInGeneralPurpose("2212345678901234567890", result), DecodeStatus::NoError); - EXPECT_EQ(result, "(22)12345678901234567890"); - EXPECT_EQ(ParseFieldsInGeneralPurpose("221234567890123456789", result), DecodeStatus::NoError); - EXPECT_EQ(result, "(22)1234567890123456789"); - // Too long - EXPECT_EQ(ParseFieldsInGeneralPurpose("22123456789012345678901", result), DecodeStatus::NotFound); - - // Max length - EXPECT_EQ(ParseFieldsInGeneralPurpose("9112345678901234567890123456789012345678901234567890" - "1234567890123456789012345678901234567890", result), DecodeStatus::NoError); - EXPECT_EQ(result, "(91)123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"); - EXPECT_EQ(ParseFieldsInGeneralPurpose("9112345678901234567890123456789012345678901234567890" - "123456789012345678901234567890123456789", result), DecodeStatus::NoError); - EXPECT_EQ(result, "(91)12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"); - // Too long - EXPECT_EQ(ParseFieldsInGeneralPurpose("9112345678901234567890123456789012345678901234567890" - "12345678901234567890123456789012345678901", result), DecodeStatus::NotFound); - - // Max length - EXPECT_EQ(ParseFieldsInGeneralPurpose("9912345678901234567890123456789012345678901234567890" - "1234567890123456789012345678901234567890", result), DecodeStatus::NoError); - EXPECT_EQ(result, "(99)123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890"); - EXPECT_EQ(ParseFieldsInGeneralPurpose("9912345678901234567890123456789012345678901234567890" - "123456789012345678901234567890123456789", result), DecodeStatus::NoError); - EXPECT_EQ(result, "(99)12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789"); - // Too long - EXPECT_EQ(ParseFieldsInGeneralPurpose("9912345678901234567890123456789012345678901234567890" - "12345678901234567890123456789012345678901", result), DecodeStatus::NotFound); - - // 3-digit AIs - - // Max length - EXPECT_EQ(ParseFieldsInGeneralPurpose("2351234567890123456789012345678", result), DecodeStatus::NoError); - EXPECT_EQ(result, "(235)1234567890123456789012345678"); - EXPECT_EQ(ParseFieldsInGeneralPurpose("235123456789012345678901234567", result), DecodeStatus::NoError); - EXPECT_EQ(result, "(235)123456789012345678901234567"); - // Too long - EXPECT_EQ(ParseFieldsInGeneralPurpose("23512345678901234567890123456789", result), DecodeStatus::NotFound); - - // Max length - EXPECT_EQ(ParseFieldsInGeneralPurpose("24312345678901234567890", result), DecodeStatus::NoError); - EXPECT_EQ(result, "(243)12345678901234567890"); - EXPECT_EQ(ParseFieldsInGeneralPurpose("2431234567890123456789", result), DecodeStatus::NoError); - EXPECT_EQ(result, "(243)1234567890123456789"); - // Too long - EXPECT_EQ(ParseFieldsInGeneralPurpose("243123456789012345678901", result), DecodeStatus::NotFound); - - // Max length - EXPECT_EQ(ParseFieldsInGeneralPurpose("253123456789012345678901234567890", result), DecodeStatus::NoError); - EXPECT_EQ(result, "(253)123456789012345678901234567890"); - EXPECT_EQ(ParseFieldsInGeneralPurpose("25312345678901234567890123456789", result), DecodeStatus::NoError); - EXPECT_EQ(result, "(253)12345678901234567890123456789"); - // Too long - EXPECT_EQ(ParseFieldsInGeneralPurpose("2531234567890123456789012345678901", result), DecodeStatus::NotFound); - - // Max length - EXPECT_EQ(ParseFieldsInGeneralPurpose("2551234567890123456789012345", result), DecodeStatus::NoError); - EXPECT_EQ(result, "(255)1234567890123456789012345"); - EXPECT_EQ(ParseFieldsInGeneralPurpose("255123456789012345678901234", result), DecodeStatus::NoError); - EXPECT_EQ(result, "(255)123456789012345678901234"); - // Too long - EXPECT_EQ(ParseFieldsInGeneralPurpose("25512345678901234567890123456", result), DecodeStatus::NotFound); - - // Fixed length - EXPECT_EQ(ParseFieldsInGeneralPurpose("4151234567890123", result), DecodeStatus::NoError); - EXPECT_EQ(result, "(415)1234567890123"); - // Incorrect lengths - EXPECT_EQ(ParseFieldsInGeneralPurpose("415123456789012", result), DecodeStatus::NotFound); - EXPECT_EQ(ParseFieldsInGeneralPurpose("41512345678901234", result), DecodeStatus::NotFound); - - // Fixed length - EXPECT_EQ(ParseFieldsInGeneralPurpose("4171234567890123", result), DecodeStatus::NoError); - EXPECT_EQ(result, "(417)1234567890123"); - // Incorrect lengths - EXPECT_EQ(ParseFieldsInGeneralPurpose("417123456789012", result), DecodeStatus::NotFound); - EXPECT_EQ(ParseFieldsInGeneralPurpose("41712345678901234", result), DecodeStatus::NotFound); - - // Max length - EXPECT_EQ(ParseFieldsInGeneralPurpose("421123456789012", result), DecodeStatus::NoError); - EXPECT_EQ(result, "(421)123456789012"); - EXPECT_EQ(ParseFieldsInGeneralPurpose("42112345678901", result), DecodeStatus::NoError); - EXPECT_EQ(result, "(421)12345678901"); - // Too long - EXPECT_EQ(ParseFieldsInGeneralPurpose("4211234567890123", result), DecodeStatus::NotFound); - - // Max length - EXPECT_EQ(ParseFieldsInGeneralPurpose("425123456789012345", result), DecodeStatus::NoError); - EXPECT_EQ(result, "(425)123456789012345"); - EXPECT_EQ(ParseFieldsInGeneralPurpose("42512345678901234", result), DecodeStatus::NoError); - EXPECT_EQ(result, "(425)12345678901234"); - // Too long - EXPECT_EQ(ParseFieldsInGeneralPurpose("4251234567890123456", result), DecodeStatus::NotFound); - - // Max length - EXPECT_EQ(ParseFieldsInGeneralPurpose("427123", result), DecodeStatus::NoError); - EXPECT_EQ(result, "(427)123"); - EXPECT_EQ(ParseFieldsInGeneralPurpose("42712", result), DecodeStatus::NoError); - EXPECT_EQ(result, "(427)12"); - // Too long - EXPECT_EQ(ParseFieldsInGeneralPurpose("4271234", result), DecodeStatus::NotFound); - - // Max length - EXPECT_EQ(ParseFieldsInGeneralPurpose("71012345678901234567890", result), DecodeStatus::NoError); - EXPECT_EQ(result, "(710)12345678901234567890"); - EXPECT_EQ(ParseFieldsInGeneralPurpose("7101234567890123456789", result), DecodeStatus::NoError); - EXPECT_EQ(result, "(710)1234567890123456789"); - // Too long - EXPECT_EQ(ParseFieldsInGeneralPurpose("710123456789012345678901", result), DecodeStatus::NotFound); - - // Max length - EXPECT_EQ(ParseFieldsInGeneralPurpose("71512345678901234567890", result), DecodeStatus::NoError); - EXPECT_EQ(result, "(715)12345678901234567890"); - EXPECT_EQ(ParseFieldsInGeneralPurpose("7151234567890123456789", result), DecodeStatus::NoError); - EXPECT_EQ(result, "(715)1234567890123456789"); - // Too long - EXPECT_EQ(ParseFieldsInGeneralPurpose("715123456789012345678901", result), DecodeStatus::NotFound); - - // 4-digit variable 4th - - // Fixed length - EXPECT_EQ(ParseFieldsInGeneralPurpose("3370123456", result), DecodeStatus::NoError); - EXPECT_EQ(result, "(3370)123456"); - // Incorrect lengths - EXPECT_EQ(ParseFieldsInGeneralPurpose("337012345", result), DecodeStatus::NotFound); - EXPECT_EQ(ParseFieldsInGeneralPurpose("33701234567", result), DecodeStatus::NotFound); - - // Fixed length - EXPECT_EQ(ParseFieldsInGeneralPurpose("3375123456", result), DecodeStatus::NoError); - EXPECT_EQ(result, "(3375)123456"); - // Incorrect lengths - EXPECT_EQ(ParseFieldsInGeneralPurpose("33751234567", result), DecodeStatus::NotFound); - EXPECT_EQ(ParseFieldsInGeneralPurpose("337512345", result), DecodeStatus::NotFound); - - EXPECT_EQ(ParseFieldsInGeneralPurpose("3376123456", result), DecodeStatus::NoError); // Allow although > max 3375 - - // Fixed length - EXPECT_EQ(ParseFieldsInGeneralPurpose("39401234", result), DecodeStatus::NoError); - EXPECT_EQ(result, "(3940)1234"); - // Incorrect lengths - EXPECT_EQ(ParseFieldsInGeneralPurpose("394012345", result), DecodeStatus::NotFound); - EXPECT_EQ(ParseFieldsInGeneralPurpose("3940123", result), DecodeStatus::NotFound); - - // Fixed length - EXPECT_EQ(ParseFieldsInGeneralPurpose("39431234", result), DecodeStatus::NoError); - EXPECT_EQ(result, "(3943)1234"); - // Incorrect lengths - EXPECT_EQ(ParseFieldsInGeneralPurpose("394312345", result), DecodeStatus::NotFound); - EXPECT_EQ(ParseFieldsInGeneralPurpose("3943123", result), DecodeStatus::NotFound); - - EXPECT_EQ(ParseFieldsInGeneralPurpose("39441234", result), DecodeStatus::NoError); // Allow although > max 3943 - - // Fixed length - EXPECT_EQ(ParseFieldsInGeneralPurpose("3950123456", result), DecodeStatus::NoError); - EXPECT_EQ(result, "(3950)123456"); - // Incorrect lengths - EXPECT_EQ(ParseFieldsInGeneralPurpose("39501234567", result), DecodeStatus::NotFound); - EXPECT_EQ(ParseFieldsInGeneralPurpose("395012345", result), DecodeStatus::NotFound); - - // Fixed length - EXPECT_EQ(ParseFieldsInGeneralPurpose("3955123456", result), DecodeStatus::NoError); - EXPECT_EQ(result, "(3955)123456"); - // Incorrect lengths - EXPECT_EQ(ParseFieldsInGeneralPurpose("39551234567", result), DecodeStatus::NotFound); - EXPECT_EQ(ParseFieldsInGeneralPurpose("395512345", result), DecodeStatus::NotFound); - - EXPECT_EQ(ParseFieldsInGeneralPurpose("3956123456", result), DecodeStatus::NoError); // Allow although > max 3955 - - // Max length - EXPECT_EQ(ParseFieldsInGeneralPurpose("7230123456789012345678901234567890", result), DecodeStatus::NoError); - EXPECT_EQ(result, "(7230)123456789012345678901234567890"); - EXPECT_EQ(ParseFieldsInGeneralPurpose("723012345678901234567890123456789", result), DecodeStatus::NoError); - EXPECT_EQ(result, "(7230)12345678901234567890123456789"); - // Too long - EXPECT_EQ(ParseFieldsInGeneralPurpose("72301234567890123456789012345678901", result), DecodeStatus::NotFound); - - // Max length - EXPECT_EQ(ParseFieldsInGeneralPurpose("7239123456789012345678901234567890", result), DecodeStatus::NoError); - EXPECT_EQ(result, "(7239)123456789012345678901234567890"); - EXPECT_EQ(ParseFieldsInGeneralPurpose("723912345678901234567890123456789", result), DecodeStatus::NoError); - EXPECT_EQ(result, "(7239)12345678901234567890123456789"); - // Too long - EXPECT_EQ(ParseFieldsInGeneralPurpose("72391234567890123456789012345678901", result), DecodeStatus::NotFound); - - // 4-digit AIs - - // Max length - EXPECT_EQ(ParseFieldsInGeneralPurpose("430012345678901234567890123456789012345", result), DecodeStatus::NoError); - EXPECT_EQ(result, "(4300)12345678901234567890123456789012345"); - EXPECT_EQ(ParseFieldsInGeneralPurpose("43001234567890123456789012345678901234", result), DecodeStatus::NoError); - EXPECT_EQ(result, "(4300)1234567890123456789012345678901234"); - // Too long - EXPECT_EQ(ParseFieldsInGeneralPurpose("4300123456789012345678901234567890123456", result), DecodeStatus::NotFound); - - // Fixed length - EXPECT_EQ(ParseFieldsInGeneralPurpose("430712", result), DecodeStatus::NoError); - EXPECT_EQ(result, "(4307)12"); - // Incorrect lengths - EXPECT_EQ(ParseFieldsInGeneralPurpose("4307123", result), DecodeStatus::NotFound); - EXPECT_EQ(ParseFieldsInGeneralPurpose("43071", result), DecodeStatus::NotFound); - - // Max length - EXPECT_EQ(ParseFieldsInGeneralPurpose("4308123456789012345678901234567890", result), DecodeStatus::NoError); - EXPECT_EQ(result, "(4308)123456789012345678901234567890"); - EXPECT_EQ(ParseFieldsInGeneralPurpose("430812345678901234567890123456789", result), DecodeStatus::NoError); - EXPECT_EQ(result, "(4308)12345678901234567890123456789"); - // Too long - EXPECT_EQ(ParseFieldsInGeneralPurpose("43081234567890123456789012345678901", result), DecodeStatus::NotFound); - - // Fixed length - EXPECT_EQ(ParseFieldsInGeneralPurpose("431712", result), DecodeStatus::NoError); - EXPECT_EQ(result, "(4317)12"); - // Incorrect lengths - EXPECT_EQ(ParseFieldsInGeneralPurpose("4317123", result), DecodeStatus::NotFound); - EXPECT_EQ(ParseFieldsInGeneralPurpose("43171", result), DecodeStatus::NotFound); - - // Max length - EXPECT_EQ(ParseFieldsInGeneralPurpose("431812345678901234567890", result), DecodeStatus::NoError); - EXPECT_EQ(result, "(4318)12345678901234567890"); - EXPECT_EQ(ParseFieldsInGeneralPurpose("43181234567890123456789", result), DecodeStatus::NoError); - EXPECT_EQ(result, "(4318)1234567890123456789"); - // Too long - EXPECT_EQ(ParseFieldsInGeneralPurpose("4318123456789012345678901", result), DecodeStatus::NotFound); - - // Fixed length - EXPECT_EQ(ParseFieldsInGeneralPurpose("43211", result), DecodeStatus::NoError); - EXPECT_EQ(result, "(4321)1"); - // Incorrect lengths - EXPECT_EQ(ParseFieldsInGeneralPurpose("432112", result), DecodeStatus::NotFound); - EXPECT_EQ(ParseFieldsInGeneralPurpose("4321", result), DecodeStatus::NotFound); - - // Fixed length - EXPECT_EQ(ParseFieldsInGeneralPurpose("4326123456", result), DecodeStatus::NoError); - EXPECT_EQ(result, "(4326)123456"); - // Incorrect lengths - EXPECT_EQ(ParseFieldsInGeneralPurpose("43261234567", result), DecodeStatus::NotFound); - EXPECT_EQ(ParseFieldsInGeneralPurpose("432612345", result), DecodeStatus::NotFound); - - // Max length - EXPECT_EQ(ParseFieldsInGeneralPurpose("70041234", result), DecodeStatus::NoError); - EXPECT_EQ(result, "(7004)1234"); - EXPECT_EQ(ParseFieldsInGeneralPurpose("7004123", result), DecodeStatus::NoError); - EXPECT_EQ(result, "(7004)123"); - // Too long - EXPECT_EQ(ParseFieldsInGeneralPurpose("700412345", result), DecodeStatus::NotFound); - - // Fixed length - EXPECT_EQ(ParseFieldsInGeneralPurpose("7006123456", result), DecodeStatus::NoError); - EXPECT_EQ(result, "(7006)123456"); - // Incorrect lengths - EXPECT_EQ(ParseFieldsInGeneralPurpose("70061234567", result), DecodeStatus::NotFound); - EXPECT_EQ(ParseFieldsInGeneralPurpose("700612345", result), DecodeStatus::NotFound); - - // Max length - EXPECT_EQ(ParseFieldsInGeneralPurpose("701012", result), DecodeStatus::NoError); - EXPECT_EQ(result, "(7010)12"); - EXPECT_EQ(ParseFieldsInGeneralPurpose("70101", result), DecodeStatus::NoError); - EXPECT_EQ(result, "(7010)1"); - // Too long - EXPECT_EQ(ParseFieldsInGeneralPurpose("7010123", result), DecodeStatus::NotFound); - - // Max length - EXPECT_EQ(ParseFieldsInGeneralPurpose("702012345678901234567890", result), DecodeStatus::NoError); - EXPECT_EQ(result, "(7020)12345678901234567890"); - EXPECT_EQ(ParseFieldsInGeneralPurpose("70201234567890123456789", result), DecodeStatus::NoError); - EXPECT_EQ(result, "(7020)1234567890123456789"); - // Too long - EXPECT_EQ(ParseFieldsInGeneralPurpose("7020123456789012345678901", result), DecodeStatus::NotFound); - - // Max length - EXPECT_EQ(ParseFieldsInGeneralPurpose("7023123456789012345678901234567890", result), DecodeStatus::NoError); - EXPECT_EQ(result, "(7023)123456789012345678901234567890"); - EXPECT_EQ(ParseFieldsInGeneralPurpose("702312345678901234567890123456789", result), DecodeStatus::NoError); - EXPECT_EQ(result, "(7023)12345678901234567890123456789"); - // Too long - EXPECT_EQ(ParseFieldsInGeneralPurpose("70231234567890123456789012345678901", result), DecodeStatus::NotFound); - - // Max length - EXPECT_EQ(ParseFieldsInGeneralPurpose("70401234", result), DecodeStatus::NoError); - EXPECT_EQ(result, "(7040)1234"); - EXPECT_EQ(ParseFieldsInGeneralPurpose("704012345", result), DecodeStatus::NotFound); - // Too long - EXPECT_EQ(ParseFieldsInGeneralPurpose("7040123", result), DecodeStatus::NotFound); - - // Max length - EXPECT_EQ(ParseFieldsInGeneralPurpose("724012345678901234567890", result), DecodeStatus::NoError); - EXPECT_EQ(result, "(7240)12345678901234567890"); - EXPECT_EQ(ParseFieldsInGeneralPurpose("72401234567890123456789", result), DecodeStatus::NoError); - EXPECT_EQ(result, "(7240)1234567890123456789"); - // Too long - EXPECT_EQ(ParseFieldsInGeneralPurpose("7240123456789012345678901", result), DecodeStatus::NotFound); - - // Max length - EXPECT_EQ(ParseFieldsInGeneralPurpose("80071234567890123456789012345678901234", result), DecodeStatus::NoError); - EXPECT_EQ(result, "(8007)1234567890123456789012345678901234"); - EXPECT_EQ(ParseFieldsInGeneralPurpose("8007123456789012345678901234567890123", result), DecodeStatus::NoError); - EXPECT_EQ(result, "(8007)123456789012345678901234567890123"); - // Too long - EXPECT_EQ(ParseFieldsInGeneralPurpose("800712345678901234567890123456789012345", result), DecodeStatus::NotFound); - - // Max length - EXPECT_EQ(ParseFieldsInGeneralPurpose("800912345678901234567890123456789012345678901234567890", result), - DecodeStatus::NoError); - EXPECT_EQ(result, "(8009)12345678901234567890123456789012345678901234567890"); - EXPECT_EQ(ParseFieldsInGeneralPurpose("80091234567890123456789012345678901234567890123456789", result), - DecodeStatus::NoError); - EXPECT_EQ(result, "(8009)1234567890123456789012345678901234567890123456789"); - // Too long - EXPECT_EQ(ParseFieldsInGeneralPurpose("8009123456789012345678901234567890123456789012345678901", result), - DecodeStatus::NotFound); - - // Max length - EXPECT_EQ(ParseFieldsInGeneralPurpose("80131234567890123456789012345", result), DecodeStatus::NoError); - EXPECT_EQ(result, "(8013)1234567890123456789012345"); - EXPECT_EQ(ParseFieldsInGeneralPurpose("8013123456789012345678901234", result), DecodeStatus::NoError); - EXPECT_EQ(result, "(8013)123456789012345678901234"); - // Too long - EXPECT_EQ(ParseFieldsInGeneralPurpose("801312345678901234567890123456", result), DecodeStatus::NotFound); - - // Fixed length - EXPECT_EQ(ParseFieldsInGeneralPurpose("8017123456789012345678", result), DecodeStatus::NoError); - EXPECT_EQ(result, "(8017)123456789012345678"); - // Incorrect lengths - EXPECT_EQ(ParseFieldsInGeneralPurpose("80171234567890123456789", result), DecodeStatus::NotFound); - EXPECT_EQ(ParseFieldsInGeneralPurpose("801712345678901234567", result), DecodeStatus::NotFound); - - // Max length - EXPECT_EQ(ParseFieldsInGeneralPurpose("80191234567890", result), DecodeStatus::NoError); - EXPECT_EQ(result, "(8019)1234567890"); - EXPECT_EQ(ParseFieldsInGeneralPurpose("8019123456789", result), DecodeStatus::NoError); - EXPECT_EQ(result, "(8019)123456789"); - // Too long - EXPECT_EQ(ParseFieldsInGeneralPurpose("801912345678901", result), DecodeStatus::NotFound); - - // Fixed length - EXPECT_EQ(ParseFieldsInGeneralPurpose("8026123456789012345678", result), DecodeStatus::NoError); - EXPECT_EQ(result, "(8026)123456789012345678"); - // Incorrect lengths - EXPECT_EQ(ParseFieldsInGeneralPurpose("80261234567890123456789", result), DecodeStatus::NotFound); - EXPECT_EQ(ParseFieldsInGeneralPurpose("802612345678901234567", result), DecodeStatus::NotFound); - - // Non-existing - EXPECT_EQ(ParseFieldsInGeneralPurpose("8100123456", result), DecodeStatus::NotFound); - EXPECT_EQ(ParseFieldsInGeneralPurpose("81011234567890", result), DecodeStatus::NotFound); - EXPECT_EQ(ParseFieldsInGeneralPurpose("810212", result), DecodeStatus::NotFound); - - // Max length - EXPECT_EQ(ParseFieldsInGeneralPurpose("811012345678901234567890123456789012345678901234567890" - "12345678901234567890", result), DecodeStatus::NoError); - EXPECT_EQ(result, "(8110)1234567890123456789012345678901234567890123456789012345678901234567890"); - EXPECT_EQ(ParseFieldsInGeneralPurpose("811012345678901234567890123456789012345678901234567890" - "1234567890123456789", result), DecodeStatus::NoError); - EXPECT_EQ(result, "(8110)123456789012345678901234567890123456789012345678901234567890123456789"); - // Too long - EXPECT_EQ(ParseFieldsInGeneralPurpose("811012345678901234567890123456789012345678901234567890" - "123456789012345678901", result), DecodeStatus::NotFound); - - // Fixed length - EXPECT_EQ(ParseFieldsInGeneralPurpose("81111234", result), DecodeStatus::NoError); - EXPECT_EQ(result, "(8111)1234"); - // Incorrect lengths - EXPECT_EQ(ParseFieldsInGeneralPurpose("811112345", result), DecodeStatus::NotFound); - EXPECT_EQ(ParseFieldsInGeneralPurpose("8111123", result), DecodeStatus::NotFound); - - // Max length - EXPECT_EQ(ParseFieldsInGeneralPurpose("811212345678901234567890123456789012345678901234567890" - "12345678901234567890", result), DecodeStatus::NoError); - EXPECT_EQ(result, "(8112)1234567890123456789012345678901234567890123456789012345678901234567890"); - EXPECT_EQ(ParseFieldsInGeneralPurpose("811212345678901234567890123456789012345678901234567890" - "1234567890123456789", result), DecodeStatus::NoError); - EXPECT_EQ(result, "(8112)123456789012345678901234567890123456789012345678901234567890123456789"); - // Too long - EXPECT_EQ(ParseFieldsInGeneralPurpose("811212345678901234567890123456789012345678901234567890" - "123456789012345678901", result), DecodeStatus::NotFound); - - // Max length - EXPECT_EQ(ParseFieldsInGeneralPurpose("820012345678901234567890123456789012345678901234567890" - "12345678901234567890", result), DecodeStatus::NoError); - EXPECT_EQ(result, "(8200)1234567890123456789012345678901234567890123456789012345678901234567890"); - EXPECT_EQ(ParseFieldsInGeneralPurpose("820012345678901234567890123456789012345678901234567890" - "1234567890123456789", result), DecodeStatus::NoError); - EXPECT_EQ(result, "(8200)123456789012345678901234567890123456789012345678901234567890123456789"); - // Too long - EXPECT_EQ(ParseFieldsInGeneralPurpose("820012345678901234567890123456789012345678901234567890" - "123456789012345678901", result), DecodeStatus::NotFound); -} diff --git a/test/unit/pdf417/PDF417DecoderTest.cpp b/test/unit/pdf417/PDF417DecoderTest.cpp index 34055006fd..c08f83ab0a 100644 --- a/test/unit/pdf417/PDF417DecoderTest.cpp +++ b/test/unit/pdf417/PDF417DecoderTest.cpp @@ -1,19 +1,8 @@ /* * Copyright 2017 Huy Cuong Nguyen * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "DecoderResult.h" #include "DecodeStatus.h" @@ -22,17 +11,21 @@ #include "gtest/gtest.h" -namespace ZXing { namespace Pdf417 { - DecodeStatus DecodeMacroBlock(const std::vector& codewords, int codeIndex, DecoderResultExtra& resultMetadata, int& next); -}} +namespace ZXing::Pdf417 { +int DecodeMacroBlock(const std::vector& codewords, int codeIndex, DecoderResultExtra& resultMetadata); +} using namespace ZXing; using namespace ZXing::Pdf417; // Shorthand for Decode() -static DecoderResult parse(const std::vector& codewords, int ecLevel = 0, const std::string& characterSet = "") +static DecoderResult parse(const std::vector& codewords, int ecLevel = 0) { - return DecodedBitStreamParser::Decode(codewords, ecLevel, characterSet); + try { + return DecodedBitStreamParser::Decode(codewords, ecLevel); + } catch (Error e) { + return e; + } } /** @@ -44,10 +37,8 @@ TEST(PDF417DecoderTest, StandardSample1) // we should never reach these 1000, 1000, 1000 }; - int next = 0; DecoderResultExtra resultMetadata; - auto status = DecodeMacroBlock(sampleCodes, 2, resultMetadata, next); - EXPECT_EQ(status, DecodeStatus::NoError); + DecodeMacroBlock(sampleCodes, 2, resultMetadata); EXPECT_EQ(0, resultMetadata.segmentIndex()); EXPECT_EQ("017053", resultMetadata.fileId()); @@ -76,10 +67,8 @@ TEST(PDF417DecoderTest, StandardSample2) // we should never reach these 1000, 1000, 1000 }; - int next = 0; DecoderResultExtra resultMetadata; - auto status = DecodeMacroBlock(sampleCodes, 2, resultMetadata, next); - EXPECT_EQ(status, DecodeStatus::NoError); + DecodeMacroBlock(sampleCodes, 2, resultMetadata); EXPECT_EQ(3, resultMetadata.segmentIndex()); EXPECT_EQ("017053", resultMetadata.fileId()); @@ -106,10 +95,8 @@ TEST(PDF417DecoderTest, StandardSample3) { std::vector sampleCodes = { 7, 928, 111, 100, 100, 200, 300 }; - int next = 0; DecoderResultExtra resultMetadata; - auto status = DecodeMacroBlock(sampleCodes, 2, resultMetadata, next); - EXPECT_EQ(status, DecodeStatus::NoError); + DecodeMacroBlock(sampleCodes, 2, resultMetadata); EXPECT_EQ(0, resultMetadata.segmentIndex()); EXPECT_EQ("100200300", resultMetadata.fileId()); @@ -128,10 +115,8 @@ TEST(PDF417DecoderTest, SampleWithFilename) 599, 923, 1, 111, 102, 98, 311, 355, 522, 920, 779, 40, 628, 33, 749, 267, 506, 213, 928, 465, 248, 493, 72, 780, 699, 780, 493, 755, 84, 198, 628, 368, 156, 198, 809, 19, 113 }; - int next = 0; DecoderResultExtra resultMetadata; - auto status = DecodeMacroBlock(sampleCodes, 3, resultMetadata, next); - EXPECT_EQ(status, DecodeStatus::NoError); + DecodeMacroBlock(sampleCodes, 3, resultMetadata); EXPECT_EQ(0, resultMetadata.segmentIndex()); EXPECT_EQ("000252021086", resultMetadata.fileId()); @@ -153,10 +138,8 @@ TEST(PDF417DecoderTest, SampleWithNumericValues) std::vector sampleCodes = { 25, 477, 928, 111, 100, 0, 252, 21, 86, 923, 2, 2, 0, 1, 0, 0, 0, 923, 5, 130, 923, 6, 1, 500, 13 }; - int next = 0; DecoderResultExtra resultMetadata; - auto status = DecodeMacroBlock(sampleCodes, 3, resultMetadata, next); - EXPECT_EQ(status, DecodeStatus::NoError); + DecodeMacroBlock(sampleCodes, 3, resultMetadata); EXPECT_EQ(0, resultMetadata.segmentIndex()); EXPECT_EQ("000252021086", resultMetadata.fileId()); @@ -178,10 +161,8 @@ TEST(PDF417DecoderTest, SampleWithMacroTerminatorOnly) { std::vector sampleCodes = { 7, 477, 928, 222, 198, 0, 922 }; - int next = 0; DecoderResultExtra resultMetadata; - auto status = DecodeMacroBlock(sampleCodes, 3, resultMetadata, next); - EXPECT_EQ(status, DecodeStatus::NoError); + DecodeMacroBlock(sampleCodes, 3, resultMetadata); EXPECT_EQ(99998, resultMetadata.segmentIndex()); EXPECT_EQ("000", resultMetadata.fileId()); @@ -519,7 +500,8 @@ TEST(PDF417DecoderTest, ECIMultipleNumeric) TEST(PDF417DecoderTest, ECIInvalid) { - EXPECT_EQ(decode({ 4, 927, 901, 0 }), L"AA"); // Invalid Character Set ECI (> 899) silently ignored + EXPECT_EQ(decode({ 4, 927, 901, 0 }), L""); // non-charset ECI > 899 -> empty text result + EXPECT_EQ(parse({4, 927, 901, 0}).content().bytes, ByteArray("AA")); // non-charset ECI > 899 -> ignored in binary result EXPECT_EQ(decode({ 3, 0, 927 }), L"AA"); // Malformed ECI at end silently ignored } @@ -532,10 +514,8 @@ TEST(PDF417DecoderTest, ECIMacroOptionalNumeric) std::vector sampleCodes = { 19, 477, 928, 111, 100, 0, 252, 21, 86, 923, 5, 15, 369, 753, 190, 927, 25, 124, 745 }; - int next = 0; DecoderResultExtra resultMetadata; - auto status = DecodeMacroBlock(sampleCodes, 3, resultMetadata, next); - EXPECT_EQ(status, DecodeStatus::NoError); + DecodeMacroBlock(sampleCodes, 3, resultMetadata); EXPECT_EQ(0, resultMetadata.segmentIndex()); EXPECT_EQ("000252021086", resultMetadata.fileId()); diff --git a/test/unit/pdf417/PDF417ErrorCorrectionTest.cpp b/test/unit/pdf417/PDF417ErrorCorrectionTest.cpp index 3b8bd94eee..b7def50056 100644 --- a/test/unit/pdf417/PDF417ErrorCorrectionTest.cpp +++ b/test/unit/pdf417/PDF417ErrorCorrectionTest.cpp @@ -1,22 +1,11 @@ /* * Copyright 2017 Huy Cuong Nguyen * Copyright 2012 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "PseudoRandom.h" -#include "ZXContainerAlgorithms.h" +#include "ZXAlgorithms.h" #include "gtest/gtest.h" diff --git a/test/unit/pdf417/PDF417HighLevelEncoderTest.cpp b/test/unit/pdf417/PDF417HighLevelEncoderTest.cpp index 412f6e2586..bbcc492d03 100644 --- a/test/unit/pdf417/PDF417HighLevelEncoderTest.cpp +++ b/test/unit/pdf417/PDF417HighLevelEncoderTest.cpp @@ -1,19 +1,8 @@ /* * Copyright 2017 Huy Cuong Nguyen * Copyright (C) 2014 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "CharacterSet.h" #include "pdf417/PDFCompaction.h" diff --git a/test/unit/pdf417/PDF417WriterTest.cpp b/test/unit/pdf417/PDF417WriterTest.cpp index c88b732490..747d2c5524 100644 --- a/test/unit/pdf417/PDF417WriterTest.cpp +++ b/test/unit/pdf417/PDF417WriterTest.cpp @@ -1,19 +1,8 @@ /* * Copyright 2017 Huy Cuong Nguyen * Copyright 2016 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "BitMatrixIO.h" #include "pdf417/PDFWriter.h" diff --git a/test/unit/qrcode/MQRDecoderTest.cpp b/test/unit/qrcode/MQRDecoderTest.cpp new file mode 100644 index 0000000000..25e7f700de --- /dev/null +++ b/test/unit/qrcode/MQRDecoderTest.cpp @@ -0,0 +1,124 @@ +/* + * Copyright 2017 Huy Cuong Nguyen + * Copyright 2008 ZXing authors +*/ +// SPDX-License-Identifier: Apache-2.0 + +#include "qrcode/QRDecoder.h" + +#include "BitMatrix.h" +#include "BitMatrixIO.h" +#include "DecoderResult.h" + +#include "gtest/gtest.h" + +using namespace ZXing; +using namespace ZXing::QRCode; + +TEST(MQRDecoderTest, MQRCodeM3L) +{ + const auto bitMatrix = ParseBitMatrix("XXXXXXX X X X X\n" + "X X X X \n" + "X XXX X XXXXXXX\n" + "X XXX X X X XX\n" + "X XXX X X XX\n" + "X X X X X X\n" + "XXXXXXX X XX \n" + " X X X\n" + "XXXXXX X X X\n" + " X XX XXX\n" + "XXX XX XXXX XXX\n" + " X X XXX X \n" + "X XXXXX XXX X X\n" + " X X X XXX \n" + "XXX XX X X XXXX\n", + 88, false); + + const auto result = Decode(bitMatrix); + EXPECT_TRUE(result.isValid()); +} + +TEST(MQRDecoderTest, MQRCodeM3M) +{ + const auto bitMatrix = ParseBitMatrix("XXXXXXX X X X X\n" + "X X XX\n" + "X XXX X X XX XX\n" + "X XXX X X X \n" + "X XXX X XX XXXX\n" + "X X XX \n" + "XXXXXXX X XXXX\n" + " X XXX \n" + "X XX XX X X\n" + " X X XX \n" + "XX XX XXXXXXX\n" + " X X X\n" + "XX X X X \n" + " X X X \n" + "X X XXXX XXX\n", + 88, false); + + const auto result = Decode(bitMatrix); + EXPECT_TRUE(result.isValid()); +} + +TEST(MQRDecoderTest, MQRCodeM1) +{ + const auto bitMatrix = ParseBitMatrix("XXXXXXX X X\n" + "X X \n" + "X XXX X XXX\n" + "X XXX X XX\n" + "X XXX X X\n" + "X X XX \n" + "XXXXXXX X \n" + " X \n" + "XX X \n" + " X XXXXX X\n" + "X XXXXXX X\n", + 88, false); + const auto result = Decode(bitMatrix); + EXPECT_TRUE(result.isValid()); + EXPECT_EQ(L"123", result.text()); +} + +TEST(MQRDecoderTest, MQRCodeM1Error4Bits) +{ + const auto bitMatrix = ParseBitMatrix("XXXXXXX X X\n" + "X X XX\n" + "X XXX X X \n" + "X XXX X XX\n" + "X XXX X X\n" + "X X XX \n" + "XXXXXXX X \n" + " X \n" + "XX X \n" + " X XXXXXX \n" + "X XXXXXXX \n", + 88, false); + const auto result = Decode(bitMatrix); + EXPECT_EQ(Error::Checksum, result.error()); + EXPECT_TRUE(result.text().empty()); +} + +TEST(MQRDecoderTest, MQRCodeM4) +{ + const auto bitMatrix = ParseBitMatrix("XXXXXXX X X X X X\n" + "X X XX X XX\n" + "X XXX X X X XX\n" + "X XXX X XX XX XX\n" + "X XXX X X XXXXX\n" + "X X XX X\n" + "XXXXXXX XX X XX\n" + " X XX XX\n" + "X X XXX X XXX\n" + " XX X XX XX X \n" + "XX XXXX X XX XX\n" + " XX XX X XX XX\n" + "XXX XXX XXX XX XX\n" + " X X X XX X\n" + "X X XX XXXXX \n" + " X X X X X \n" + "X XXXXXXX X X X\n", + 88, false); + const auto result = Decode(bitMatrix); + EXPECT_TRUE(result.isValid()); +} diff --git a/test/unit/qrcode/QRBitMatrixParserTest.cpp b/test/unit/qrcode/QRBitMatrixParserTest.cpp new file mode 100644 index 0000000000..f8c5a93a0d --- /dev/null +++ b/test/unit/qrcode/QRBitMatrixParserTest.cpp @@ -0,0 +1,73 @@ +/* + * Copyright 2017 Huy Cuong Nguyen + * Copyright 2008 ZXing authors +*/ +// SPDX-License-Identifier: Apache-2.0 + +#include "BitMatrix.h" +#include "BitMatrixIO.h" +#include "ByteArray.h" +#include "qrcode/QRBitMatrixParser.h" +#include "qrcode/QRFormatInformation.h" +#include "qrcode/QRVersion.h" + +#include "gtest/gtest.h" + +using namespace ZXing; +using namespace ZXing::QRCode; + +TEST(QRBitMatrixParserTest, MQRCodeM3L) +{ + const auto bitMatrix = ParseBitMatrix("XXXXXXX X X X X\n" + "X X X X \n" + "X XXX X XXXXXXX\n" + "X XXX X X X XX\n" + "X XXX X X XX\n" + "X X X X X X\n" + "XXXXXXX X XX \n" + " X X X\n" + "XXXXXX X X X\n" + " X XX XXX\n" + "XXX XX XXXX XXX\n" + " X X XXX X \n" + "X XXXXX XXX X X\n" + " X X X XXX \n" + "XXX XX X X XXXX\n", + 88, false); + + const auto version = ReadVersion(bitMatrix); + EXPECT_EQ(3, version->versionNumber()); + const auto format = ReadFormatInformation(bitMatrix, true); + const auto codewords = ReadCodewords(bitMatrix, *version, format); + EXPECT_EQ(17, codewords.size()); + EXPECT_EQ(0x0, codewords[10]); + EXPECT_EQ(0xd1, codewords[11]); +} + +TEST(QRBitMatrixParserTest, MQRCodeM3M) +{ + const auto bitMatrix = ParseBitMatrix("XXXXXXX X X X X\n" + "X X XX\n" + "X XXX X X XX XX\n" + "X XXX X X X \n" + "X XXX X XX XXXX\n" + "X X XX \n" + "XXXXXXX X XXXX\n" + " X XXX \n" + "X XX XX X X\n" + " X X XX \n" + "XX XX XXXXXXX\n" + " X X X\n" + "XX X X X \n" + " X X X \n" + "X X XXXX XXX\n", + 88, false); + + const auto version = ReadVersion(bitMatrix); + EXPECT_EQ(3, version->versionNumber()); + const auto format = ReadFormatInformation(bitMatrix, true); + const auto codewords = ReadCodewords(bitMatrix, *version, format); + EXPECT_EQ(17, codewords.size()); + EXPECT_EQ(0x0, codewords[8]); + EXPECT_EQ(0x89, codewords[9]); +} diff --git a/test/unit/qrcode/QRDataMaskTest.cpp b/test/unit/qrcode/QRDataMaskTest.cpp index 4f55545f7f..24baa4a417 100644 --- a/test/unit/qrcode/QRDataMaskTest.cpp +++ b/test/unit/qrcode/QRDataMaskTest.cpp @@ -1,19 +1,8 @@ /* * Copyright 2017 Huy Cuong Nguyen * Copyright 2007 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "qrcode/QRDataMask.h" #include "BitMatrix.h" @@ -26,17 +15,28 @@ using namespace ZXing::QRCode; namespace { - void TestMaskAcrossDimensions(int maskIndex, std::function condition) { - for (int version = 1; version <= 40; version++) { - int dimension = 17 + 4 * version; + void TestMaskAcrossDimensionsImpl(int maskIndex, bool isMicro, const int versionMax, const int dimensionStart, const int dimensionStep, std::function condition) + { + for (int version = 1; version <= versionMax; version++) { + int dimension = dimensionStart + dimensionStep * version; BitMatrix bits(dimension); for (int i = 0; i < dimension; i++) for (int j = 0; j < dimension; j++) - EXPECT_EQ(GetMaskedBit(bits, j, i, maskIndex), condition(i, j)) << "(" << i << ',' << j << ')'; + EXPECT_EQ(GetMaskedBit(bits, j, i, maskIndex, isMicro), condition(i, j)) << "(" << i << ',' << j << ')'; } } + void TestMaskAcrossDimensions(int maskIndex, std::function condition) + { + TestMaskAcrossDimensionsImpl(maskIndex, false, 40, 17, 4, condition); + } + + void TestMicroMaskAcrossDimensions(int maskIndex, std::function condition) + { + TestMaskAcrossDimensionsImpl(maskIndex, true, 4, 9, 2, condition); + } + } TEST(QRDataMaskTest, Mask0) @@ -78,3 +78,23 @@ TEST(QRDataMaskTest, Mask7) { TestMaskAcrossDimensions(7, [](int i, int j) { return ((i + j) % 2 + (i * j) % 3) % 2 == 0; }); } + +TEST(QRDataMaskTest, MicroMask0) +{ + TestMicroMaskAcrossDimensions(0, [](int i, int) { return i % 2 == 0; }); +} + +TEST(QRDataMaskTest, MicroMask1) +{ + TestMicroMaskAcrossDimensions(1, [](int i, int j) { return (i / 2 + j / 3) % 2 == 0; }); +} + +TEST(QRDataMaskTest, MicroMask2) +{ + TestMicroMaskAcrossDimensions(2, [](int i, int j) { return ((i * j) % 2 + (i * j) % 3) % 2 == 0; }); +} + +TEST(QRDataMaskTest, MicroMask3) +{ + TestMicroMaskAcrossDimensions(3, [](int i, int j) { return ((i + j) % 2 + (i * j) % 3) % 2 == 0; }); +} diff --git a/test/unit/qrcode/QRDecodedBitStreamParserTest.cpp b/test/unit/qrcode/QRDecodedBitStreamParserTest.cpp index 4888138a10..0d8c1b0def 100644 --- a/test/unit/qrcode/QRDecodedBitStreamParserTest.cpp +++ b/test/unit/qrcode/QRDecodedBitStreamParserTest.cpp @@ -1,19 +1,8 @@ /* * Copyright 2017 Huy Cuong Nguyen * Copyright 2008 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "BitArray.h" #include "ByteArray.h" @@ -27,7 +16,7 @@ namespace ZXing { namespace QRCode { - DecoderResult DecodeBitStream(ByteArray&& bytes, const Version& version, ErrorCorrectionLevel ecLevel, const std::string& hintedCharset); + DecoderResult DecodeBitStream(ByteArray&& bytes, const Version& version, ErrorCorrectionLevel ecLevel); } } @@ -42,7 +31,7 @@ TEST(QRDecodedBitStreamParserTest, SimpleByteMode) ba.appendBits(0xF1, 8); ba.appendBits(0xF2, 8); ba.appendBits(0xF3, 8); - auto result = DecodeBitStream(ba.toBytes(), *Version::VersionForNumber(1), ErrorCorrectionLevel::Medium, "").text(); + auto result = DecodeBitStream(ba.toBytes(), *Version::VersionForNumber(1), ErrorCorrectionLevel::Medium).text(); EXPECT_EQ(L"\xF1\xF2\xF3", result); } @@ -55,7 +44,7 @@ TEST(QRDecodedBitStreamParserTest, SimpleSJIS) ba.appendBits(0xA2, 8); ba.appendBits(0xA3, 8); ba.appendBits(0xD0, 8); - auto result = DecodeBitStream(ba.toBytes(), *Version::VersionForNumber(1), ErrorCorrectionLevel::Medium, "").text(); + auto result = DecodeBitStream(ba.toBytes(), *Version::VersionForNumber(1), ErrorCorrectionLevel::Medium).text(); EXPECT_EQ(L"\uff61\uff62\uff63\uff90", result); } @@ -69,7 +58,7 @@ TEST(QRDecodedBitStreamParserTest, ECI) ba.appendBits(0xA1, 8); ba.appendBits(0xA2, 8); ba.appendBits(0xA3, 8); - auto result = DecodeBitStream(ba.toBytes(), *Version::VersionForNumber(1), ErrorCorrectionLevel::Medium, "").text(); + auto result = DecodeBitStream(ba.toBytes(), *Version::VersionForNumber(1), ErrorCorrectionLevel::Medium).text(); EXPECT_EQ(L"\xED\xF3\xFA", result); } @@ -80,7 +69,7 @@ TEST(QRDecodedBitStreamParserTest, Hanzi) ba.appendBits(0x01, 4); // Subset 1 = GB2312 encoding ba.appendBits(0x01, 8); // 1 characters ba.appendBits(0x03C1, 13); - auto result = DecodeBitStream(ba.toBytes(), *Version::VersionForNumber(1), ErrorCorrectionLevel::Medium, "").text(); + auto result = DecodeBitStream(ba.toBytes(), *Version::VersionForNumber(1), ErrorCorrectionLevel::Medium).text(); EXPECT_EQ(L"\u963f", result); } @@ -93,7 +82,7 @@ TEST(QRDecodedBitStreamParserTest, HanziLevel1) // A5A2 (U+30A2) => A5A2 - A1A1 = 401, 4*60 + 01 = 0181 ba.appendBits(0x0181, 13); - auto result = DecodeBitStream(ba.toBytes(), *Version::VersionForNumber(1), ErrorCorrectionLevel::Medium, "").text(); + auto result = DecodeBitStream(ba.toBytes(), *Version::VersionForNumber(1), ErrorCorrectionLevel::Medium).text(); EXPECT_EQ(L"\u30a2", result); } @@ -104,41 +93,42 @@ TEST(QRDecodedBitStreamParserTest, SymbologyIdentifier) DecoderResult result; // Plain "ANUM(1) A" - result = DecodeBitStream({0x20, 0x09, 0x40}, version, ecLevel, ""); + result = DecodeBitStream({0x20, 0x09, 0x40}, version, ecLevel); EXPECT_EQ(result.symbologyIdentifier(), "]Q1"); EXPECT_EQ(result.text(), L"A"); // GS1 "FNC1(1st) NUM(4) 2001" - result = DecodeBitStream({0x51, 0x01, 0x0C, 0x81, 0x00}, version, ecLevel, ""); + result = DecodeBitStream({0x51, 0x01, 0x0C, 0x81, 0x00}, version, ecLevel); EXPECT_EQ(result.symbologyIdentifier(), "]Q3"); EXPECT_EQ(result.text(), L"2001"); // "(20)01" - // GS1 "NUM(4) 2001 FNC1(1st) 301" - FNC1(1st) can occur anywhere - result = DecodeBitStream({0x10, 0x10, 0xC8, 0x15, 0x10, 0x0D, 0x2D, 0x00}, version, ecLevel, ""); + // GS1 "NUM(4) 2001 FNC1(1st) 301" - FNC1(1st) can occur anywhere (this actually violates the specification) + result = DecodeBitStream({0x10, 0x10, 0xC8, 0x15, 0x10, 0x0D, 0x2D, 0x00}, version, ecLevel); EXPECT_EQ(result.symbologyIdentifier(), "]Q3"); EXPECT_EQ(result.text(), L"2001301"); // "(20)01(30)1" // AIM "FNC1(2nd) 99 (0x63) ANUM(1) A" - result = DecodeBitStream({0x96, 0x32, 0x00, 0x94, 0x00}, version, ecLevel, ""); + result = DecodeBitStream({0x96, 0x32, 0x00, 0x94, 0x00}, version, ecLevel); EXPECT_EQ(result.symbologyIdentifier(), "]Q5"); EXPECT_EQ(result.text(), L"99A"); // AIM "BYTE(1) A FNC1(2nd) 99 (0x63) BYTE(1) B" - FNC1(2nd) can occur anywhere - result = DecodeBitStream({0x40, 0x14, 0x19, 0x63, 0x40, 0x14, 0x20, 0x00}, version, ecLevel, ""); - EXPECT_EQ(result.symbologyIdentifier(), "]Q5"); - EXPECT_EQ(result.text(), L"99AB"); // Application Indicator prefixed to data + // Disabled this test, since this violates the specification and the code does support it anymore +// result = DecodeBitStream({0x40, 0x14, 0x19, 0x63, 0x40, 0x14, 0x20, 0x00}, version, ecLevel, ""); +// EXPECT_EQ(result.symbologyIdentifier(), "]Q5"); +// EXPECT_EQ(result.text(), L"99AB"); // Application Indicator prefixed to data // AIM "FNC1(2nd) A (100 + 61 = 0xA5) ANUM(1) B" - result = DecodeBitStream({0x9A, 0x52, 0x00, 0x96, 0x00}, version, ecLevel, ""); + result = DecodeBitStream({0x9A, 0x52, 0x00, 0x96, 0x00}, version, ecLevel); EXPECT_EQ(result.symbologyIdentifier(), "]Q5"); EXPECT_EQ(result.text(), L"AB"); // AIM "FNC1(2nd) a (100 + 97 = 0xC5) ANUM(1) B" - result = DecodeBitStream({0x9C, 0x52, 0x00, 0x96, 0x00}, version, ecLevel, ""); + result = DecodeBitStream({0x9C, 0x52, 0x00, 0x96, 0x00}, version, ecLevel); EXPECT_EQ(result.symbologyIdentifier(), "]Q5"); EXPECT_EQ(result.text(), L"aB"); // Bad AIM Application Indicator "FNC1(2nd) @ (0xA4) ANUM(1) B" - result = DecodeBitStream({0x9A, 0x42, 0x00, 0x96, 0x00}, version, ecLevel, ""); + result = DecodeBitStream({0x9A, 0x42, 0x00, 0x96, 0x00}, version, ecLevel); EXPECT_FALSE(result.isValid()); } diff --git a/test/unit/qrcode/QREncoderTest.cpp b/test/unit/qrcode/QREncoderTest.cpp index ccd9807fdc..78e2715fc8 100644 --- a/test/unit/qrcode/QREncoderTest.cpp +++ b/test/unit/qrcode/QREncoderTest.cpp @@ -1,18 +1,7 @@ /* * Copyright 2008 ZXing authors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +*/ +// SPDX-License-Identifier: Apache-2.0 #include "BitArray.h" #include "BitArrayUtility.h" diff --git a/test/unit/qrcode/QRErrorCorrectionLevelTest.cpp b/test/unit/qrcode/QRErrorCorrectionLevelTest.cpp index 35f8b870fc..77c103023e 100644 --- a/test/unit/qrcode/QRErrorCorrectionLevelTest.cpp +++ b/test/unit/qrcode/QRErrorCorrectionLevelTest.cpp @@ -1,19 +1,8 @@ /* * Copyright 2017 Huy Cuong Nguyen * Copyright 2008 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "qrcode/QRErrorCorrectionLevel.h" @@ -29,3 +18,28 @@ TEST(QRErrorCorrectionLevelTest, ForBits) EXPECT_EQ(ErrorCorrectionLevel::High, ECLevelFromBits(2)); EXPECT_EQ(ErrorCorrectionLevel::Quality, ECLevelFromBits(3)); } + +TEST(QRErrorCorrectionLevelTest, ForMicroBits) +{ + EXPECT_EQ(ErrorCorrectionLevel::Low, ECLevelFromBits(0, true)); + EXPECT_EQ(ErrorCorrectionLevel::Low, ECLevelFromBits(1, true)); + EXPECT_EQ(ErrorCorrectionLevel::Medium, ECLevelFromBits(2, true)); + EXPECT_EQ(ErrorCorrectionLevel::Low, ECLevelFromBits(3, true)); + EXPECT_EQ(ErrorCorrectionLevel::Medium, ECLevelFromBits(4, true)); + EXPECT_EQ(ErrorCorrectionLevel::Low, ECLevelFromBits(5, true)); + EXPECT_EQ(ErrorCorrectionLevel::Medium, ECLevelFromBits(6, true)); + EXPECT_EQ(ErrorCorrectionLevel::Quality, ECLevelFromBits(7, true)); + + EXPECT_EQ(ErrorCorrectionLevel::Quality, ECLevelFromBits(-1, true)); + EXPECT_EQ(ErrorCorrectionLevel::Low, ECLevelFromBits(8, true)); +} + +TEST(QRErrorCorrectionLevelTest, ToString) +{ + using namespace std::literals; + + EXPECT_EQ("L"s, ToString(ErrorCorrectionLevel::Low)); + EXPECT_EQ("M"s, ToString(ErrorCorrectionLevel::Medium)); + EXPECT_EQ("Q"s, ToString(ErrorCorrectionLevel::Quality)); + EXPECT_EQ("H"s, ToString(ErrorCorrectionLevel::High)); +} diff --git a/test/unit/qrcode/QRFormatInformationTest.cpp b/test/unit/qrcode/QRFormatInformationTest.cpp index 62df090171..0dffa5ea27 100644 --- a/test/unit/qrcode/QRFormatInformationTest.cpp +++ b/test/unit/qrcode/QRFormatInformationTest.cpp @@ -1,19 +1,8 @@ /* * Copyright 2017 Huy Cuong Nguyen * Copyright 2007 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "qrcode/QRFormatInformation.h" @@ -22,33 +11,78 @@ using namespace ZXing; using namespace ZXing::QRCode; - static const int MASKED_TEST_FORMAT_INFO = 0x2BED; static const int UNMASKED_TEST_FORMAT_INFO = MASKED_TEST_FORMAT_INFO ^ 0x5412; +static const int MICRO_MASKED_TEST_FORMAT_INFO = 0x3BBA; +static const int MICRO_UNMASKED_TEST_FORMAT_INFO = MICRO_MASKED_TEST_FORMAT_INFO ^ 0x4445; + +static void DoFormatInformationTest(const int formatInfo, const uint8_t expectedMask, const ErrorCorrectionLevel& expectedECL) +{ + FormatInformation parsedFormat = FormatInformation::DecodeMQR(formatInfo); + EXPECT_TRUE(parsedFormat.isValid()); + EXPECT_EQ(expectedMask, parsedFormat.dataMask); + EXPECT_EQ(expectedECL, parsedFormat.ecLevel); +} TEST(QRFormatInformationTest, Decode) { // Normal case - FormatInformation expected = FormatInformation::DecodeFormatInformation(MASKED_TEST_FORMAT_INFO, MASKED_TEST_FORMAT_INFO); + FormatInformation expected = FormatInformation::DecodeQR(MASKED_TEST_FORMAT_INFO, MASKED_TEST_FORMAT_INFO); EXPECT_TRUE(expected.isValid()); - EXPECT_EQ(0x07, expected.dataMask()); - EXPECT_EQ(ErrorCorrectionLevel::Quality, expected.errorCorrectionLevel()); + EXPECT_EQ(0x07, expected.dataMask); + EXPECT_EQ(ErrorCorrectionLevel::Quality, expected.ecLevel); // where the code forgot the mask! - EXPECT_EQ(expected, FormatInformation::DecodeFormatInformation(UNMASKED_TEST_FORMAT_INFO, MASKED_TEST_FORMAT_INFO)); + EXPECT_EQ(expected, FormatInformation::DecodeQR(UNMASKED_TEST_FORMAT_INFO, MASKED_TEST_FORMAT_INFO)); } TEST(QRFormatInformationTest, DecodeWithBitDifference) { - FormatInformation expected = FormatInformation::DecodeFormatInformation(MASKED_TEST_FORMAT_INFO, MASKED_TEST_FORMAT_INFO); + FormatInformation expected = FormatInformation::DecodeQR(MASKED_TEST_FORMAT_INFO, MASKED_TEST_FORMAT_INFO); // 1,2,3,4 bits difference - EXPECT_EQ(expected, FormatInformation::DecodeFormatInformation(MASKED_TEST_FORMAT_INFO ^ 0x01, MASKED_TEST_FORMAT_INFO ^ 0x01)); - EXPECT_EQ(expected, FormatInformation::DecodeFormatInformation(MASKED_TEST_FORMAT_INFO ^ 0x03, MASKED_TEST_FORMAT_INFO ^ 0x03)); - EXPECT_EQ(expected, FormatInformation::DecodeFormatInformation(MASKED_TEST_FORMAT_INFO ^ 0x07, MASKED_TEST_FORMAT_INFO ^ 0x07)); - EXPECT_TRUE(!FormatInformation::DecodeFormatInformation(MASKED_TEST_FORMAT_INFO ^ 0x0F, MASKED_TEST_FORMAT_INFO ^ 0x0F).isValid()); + EXPECT_EQ(expected, FormatInformation::DecodeQR(MASKED_TEST_FORMAT_INFO ^ 0x01, MASKED_TEST_FORMAT_INFO ^ 0x01)); + EXPECT_EQ(expected, FormatInformation::DecodeQR(MASKED_TEST_FORMAT_INFO ^ 0x03, MASKED_TEST_FORMAT_INFO ^ 0x03)); + EXPECT_EQ(expected, FormatInformation::DecodeQR(MASKED_TEST_FORMAT_INFO ^ 0x07, MASKED_TEST_FORMAT_INFO ^ 0x07)); + EXPECT_TRUE(!FormatInformation::DecodeQR(MASKED_TEST_FORMAT_INFO ^ 0x0F, MASKED_TEST_FORMAT_INFO ^ 0x0F).isValid()); } TEST(QRFormatInformationTest, DecodeWithMisread) { - FormatInformation expected = FormatInformation::DecodeFormatInformation(MASKED_TEST_FORMAT_INFO, MASKED_TEST_FORMAT_INFO); - EXPECT_EQ(expected, FormatInformation::DecodeFormatInformation(MASKED_TEST_FORMAT_INFO ^ 0x03, MASKED_TEST_FORMAT_INFO ^ 0x0F)); + FormatInformation expected = FormatInformation::DecodeQR(MASKED_TEST_FORMAT_INFO, MASKED_TEST_FORMAT_INFO); + EXPECT_EQ(expected, FormatInformation::DecodeQR(MASKED_TEST_FORMAT_INFO ^ 0x03, MASKED_TEST_FORMAT_INFO ^ 0x0F)); +} + +TEST(QRFormatInformationTest, DecodeMicro) +{ + // Normal cases. + DoFormatInformationTest(0x4445, 0x0, ErrorCorrectionLevel::Low); + DoFormatInformationTest(0x4172, 0x1, ErrorCorrectionLevel::Low); + DoFormatInformationTest(0x5fc0, 0x2, ErrorCorrectionLevel::Low); + DoFormatInformationTest(0x5af7, 0x3, ErrorCorrectionLevel::Low); + DoFormatInformationTest(0x6793, 0x0, ErrorCorrectionLevel::Medium); + DoFormatInformationTest(0x62a4, 0x1, ErrorCorrectionLevel::Medium); + DoFormatInformationTest(0x3e8d, 0x2, ErrorCorrectionLevel::Quality); + DoFormatInformationTest(MICRO_MASKED_TEST_FORMAT_INFO, 0x3, ErrorCorrectionLevel::Quality); + + // where the code forgot the mask! +// DoFormatInformationTest(MICRO_UNMASKED_TEST_FORMAT_INFO, 0x3, ErrorCorrectionLevel::Quality); +} + +// This doesn't work as expected because the implementation of the decode tries with +// and without the mask (0x4445). This effectively adds a tolerance of 5 bits to the Hamming +// distance calculation. +TEST(QRFormatInformationTest, DecodeMicroWithBitDifference) +{ + FormatInformation expected = FormatInformation::DecodeMQR(MICRO_MASKED_TEST_FORMAT_INFO); + + // 1,2,3 bits difference + EXPECT_EQ(expected, FormatInformation::DecodeMQR(MICRO_MASKED_TEST_FORMAT_INFO ^ 0x01)); + EXPECT_EQ(expected, FormatInformation::DecodeMQR(MICRO_MASKED_TEST_FORMAT_INFO ^ 0x03)); + EXPECT_EQ(expected, FormatInformation::DecodeMQR(MICRO_MASKED_TEST_FORMAT_INFO ^ 0x07)); + + // Bigger bit differences can return valid FormatInformation objects but the data mask and error + // correction levels do not match. +// EXPECT_TRUE(FormatInformation::DecodeFormatInformation(MICRO_MASKED_TEST_FORMAT_INFO ^ 0x3f).isValid()); +// EXPECT_NE(expected.dataMask(), FormatInformation::DecodeFormatInformation(MICRO_MASKED_TEST_FORMAT_INFO ^ 0x3f).dataMask()); +// EXPECT_NE(expected.errorCorrectionLevel(), +// FormatInformation::DecodeFormatInformation(MICRO_MASKED_TEST_FORMAT_INFO ^ 0x3f).errorCorrectionLevel()); } diff --git a/test/unit/qrcode/QRModeTest.cpp b/test/unit/qrcode/QRModeTest.cpp index 368ce1b07b..94ab70243f 100644 --- a/test/unit/qrcode/QRModeTest.cpp +++ b/test/unit/qrcode/QRModeTest.cpp @@ -1,19 +1,8 @@ /* * Copyright 2017 Huy Cuong Nguyen * Copyright 2008 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "qrcode/QRCodecMode.h" #include "qrcode/QRVersion.h" @@ -43,3 +32,35 @@ TEST(QRModeTest, CharacterCount) ASSERT_EQ(8, CharacterCountBits(CodecMode::BYTE, *Version::VersionForNumber(7))); ASSERT_EQ(8, CharacterCountBits(CodecMode::KANJI, *Version::VersionForNumber(8))); } + +TEST(QRModeTest, MicroForBits) +{ + // M1 + ASSERT_EQ(CodecMode::NUMERIC, CodecModeForBits(0x00, true)); + // M2 + ASSERT_EQ(CodecMode::NUMERIC, CodecModeForBits(0x00, true)); + ASSERT_EQ(CodecMode::ALPHANUMERIC, CodecModeForBits(0x01, true)); + // M3 + ASSERT_EQ(CodecMode::NUMERIC, CodecModeForBits(0x00, true)); + ASSERT_EQ(CodecMode::ALPHANUMERIC, CodecModeForBits(0x01, true)); + ASSERT_EQ(CodecMode::BYTE, CodecModeForBits(0x02, true)); + ASSERT_EQ(CodecMode::KANJI, CodecModeForBits(0x03, true)); + // M4 + ASSERT_EQ(CodecMode::NUMERIC, CodecModeForBits(0x00, true)); + ASSERT_EQ(CodecMode::ALPHANUMERIC, CodecModeForBits(0x01, true)); + ASSERT_EQ(CodecMode::BYTE, CodecModeForBits(0x02, true)); + ASSERT_EQ(CodecMode::KANJI, CodecModeForBits(0x03, true)); + + ASSERT_THROW(CodecModeForBits(0x04, true), std::invalid_argument); +} + +TEST(QRModeTest, MicroCharacterCount) +{ + // Spot check a few values + ASSERT_EQ(3, CharacterCountBits(CodecMode::NUMERIC, *Version::VersionForNumber(1, true))); + ASSERT_EQ(4, CharacterCountBits(CodecMode::NUMERIC, *Version::VersionForNumber(2, true))); + ASSERT_EQ(6, CharacterCountBits(CodecMode::NUMERIC, *Version::VersionForNumber(4, true))); + ASSERT_EQ(3, CharacterCountBits(CodecMode::ALPHANUMERIC, *Version::VersionForNumber(2, true))); + ASSERT_EQ(4, CharacterCountBits(CodecMode::BYTE, *Version::VersionForNumber(3, true))); + ASSERT_EQ(4, CharacterCountBits(CodecMode::KANJI, *Version::VersionForNumber(4, true))); +} diff --git a/test/unit/qrcode/QRVersionTest.cpp b/test/unit/qrcode/QRVersionTest.cpp index 5f8e821382..bf4fbe377b 100644 --- a/test/unit/qrcode/QRVersionTest.cpp +++ b/test/unit/qrcode/QRVersionTest.cpp @@ -1,22 +1,13 @@ /* * Copyright 2017 Huy Cuong Nguyen * Copyright 2008 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "qrcode/QRVersion.h" +#include "BitMatrix.h" + #include "gtest/gtest.h" using namespace ZXing; @@ -27,7 +18,7 @@ namespace { void CheckVersion(const Version* version, int number, int dimension) { ASSERT_NE(version, nullptr); EXPECT_EQ(number, version->versionNumber()); - if (number > 1) { + if (number > 1 && !version->isMicroQRCode()) { EXPECT_FALSE(version->alignmentPatternCenters().empty()); } EXPECT_EQ(dimension, version->dimensionForVersion()); @@ -38,6 +29,7 @@ namespace { ASSERT_NE(version, nullptr); EXPECT_EQ(expectedVersion, version->versionNumber()); } + } TEST(QRVersionTest, VersionForNumber) @@ -71,3 +63,42 @@ TEST(QRVersionTest, DecodeVersionInformation) DoTestVersion(32, 0x209D5); } +TEST(QRVersionTest, MicroVersionForNumber) +{ + auto version = Version::VersionForNumber(0, true); + EXPECT_EQ(version, nullptr) << "There is version with number 0"; + + for (int i = 1; i <= 4; i++) { + CheckVersion(Version::VersionForNumber(i, true), i, 2 * i + 9); + } +} + +TEST(QRVersionTest, GetProvisionalMicroVersionForDimension) +{ + for (int i = 1; i <= 4; i++) { + auto prov = Version::ProvisionalVersionForDimension(2 * i + 9, true); + ASSERT_NE(prov, nullptr); + EXPECT_EQ(i, prov->versionNumber()); + } +} + +TEST(QRVersionTest, FunctionPattern) +{ + auto testFinderPatternRegion = [](const BitMatrix& bitMatrix) { + for (int row = 0; row < 9; row++) + for (int col = 0; col < 9; col++) + EXPECT_TRUE(bitMatrix.get(col, row)); + }; + for (int i = 1; i <= 4; i++) { + const auto version = Version::VersionForNumber(i, true); + const auto functionPattern = version->buildFunctionPattern(); + testFinderPatternRegion(functionPattern); + + // Check timing pattern areas. + const auto dimension = version->dimensionForVersion(); + for (int row = dimension; row < functionPattern.height(); row++) + EXPECT_TRUE(functionPattern.get(0, row)); + for (int col = dimension; col < functionPattern.width(); col++) + EXPECT_TRUE(functionPattern.get(col, 0)); + } +} diff --git a/test/unit/qrcode/QRWriterTest.cpp b/test/unit/qrcode/QRWriterTest.cpp index 869d66a94e..bcb63f4443 100644 --- a/test/unit/qrcode/QRWriterTest.cpp +++ b/test/unit/qrcode/QRWriterTest.cpp @@ -1,19 +1,8 @@ /* * Copyright 2017 Huy Cuong Nguyen * Copyright 2008 ZXing authors -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "BitMatrixIO.h" #include "qrcode/QRWriter.h" diff --git a/wrappers/android/app/src/main/java/com/example/zxingcppdemo/MainActivity.kt b/wrappers/android/app/src/main/java/com/example/zxingcppdemo/MainActivity.kt index d023a70676..82cf02fd9e 100644 --- a/wrappers/android/app/src/main/java/com/example/zxingcppdemo/MainActivity.kt +++ b/wrappers/android/app/src/main/java/com/example/zxingcppdemo/MainActivity.kt @@ -166,7 +166,9 @@ class MainActivity : AppCompatActivity() { p.toPointF() } } - (result?.let { "${it.format}: ${it.text}" } ?: "") + (result?.let { "${it.format} (${it.contentType}):" + + "${if (it.contentType != BarcodeReader.ContentType.BINARY) it.text else it.bytes!!.joinToString(separator = "") { v -> "%02x".format(v) }}" } + ?: "") } catch (e: Throwable) { e.message ?: "Error" } diff --git a/wrappers/android/zxingcpp/src/main/cpp/BarcodeReader.cpp b/wrappers/android/zxingcpp/src/main/cpp/BarcodeReader.cpp index 965ed6e2a1..8afd7a3d51 100644 --- a/wrappers/android/zxingcpp/src/main/cpp/BarcodeReader.cpp +++ b/wrappers/android/zxingcpp/src/main/cpp/BarcodeReader.cpp @@ -1,18 +1,7 @@ /* * Copyright 2021 Axel Waggershauser -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "JNIUtils.h" #include "ReadBarcode.h" @@ -41,6 +30,7 @@ static const char* JavaBarcodeFormatName(BarcodeFormat format) case BarcodeFormat::MaxiCode: return "MAXICODE"; case BarcodeFormat::PDF417: return "PDF_417"; case BarcodeFormat::QRCode: return "QR_CODE"; + case BarcodeFormat::MicroQRCode: return "MICRO_QR_CODE"; case BarcodeFormat::DataBar: return "DATA_BAR"; case BarcodeFormat::DataBarExpanded: return "DATA_BAR_EXPANDED"; case BarcodeFormat::UPCA: return "UPC_A"; @@ -49,6 +39,20 @@ static const char* JavaBarcodeFormatName(BarcodeFormat format) } } +static const char* JavaContentTypeName(ContentType contentType) +{ + // These have to be the names of the enum constants in the kotlin code. + switch (contentType) { + case ContentType::Text: return "TEXT"; + case ContentType::Binary: return "BINARY"; + case ContentType::Mixed: return "MIXED"; + case ContentType::GS1: return "GS1"; + case ContentType::ISO15434: return "ISO15434"; + case ContentType::UnknownECI: return "UNKNOWN_ECI"; + default: throw std::invalid_argument("Invalid contentType"); + } +} + static jstring ThrowJavaException(JNIEnv* env, const char* message) { // if (env->ExceptionCheck()) @@ -58,6 +62,13 @@ static jstring ThrowJavaException(JNIEnv* env, const char* message) return nullptr; } +static jobject CreateContentType(JNIEnv* env, ContentType contentType) +{ + jclass cls = env->FindClass("com/zxingcpp/BarcodeReader$ContentType"); + jfieldID fidCT = env->GetStaticFieldID(cls , JavaContentTypeName(contentType), "Lcom/zxingcpp/BarcodeReader$ContentType;"); + return env->GetStaticObjectField(cls, fidCT); +} + static jobject CreateAndroidPoint(JNIEnv* env, const PointT& point) { jclass cls = env->FindClass("android/graphics/Point"); @@ -93,12 +104,10 @@ jstring Read(JNIEnv *env, ImageView image, jstring formats, jboolean tryHarder, .setTryHarder(tryHarder) .setTryRotate( tryRotate ) .setTryDownscale(tryDownscale) - .setMaxNumberOfSymbols(1); // see ReadBarcode implementation - -// return C2JString(env, ToString(DecodeStatus::NotFound)); + .setMaxNumberOfSymbols(1); auto startTime = std::chrono::high_resolution_clock::now(); - auto res = ReadBarcode(image, hints); + auto results = ReadBarcodes(image, hints); auto duration = std::chrono::high_resolution_clock::now() - startTime; // LOGD("time: %4d ms\n", (int)std::chrono::duration_cast(duration).count()); @@ -108,10 +117,19 @@ jstring Read(JNIEnv *env, ImageView image, jstring formats, jboolean tryHarder, auto time = std::to_wstring(std::chrono::duration_cast(duration).count()); env->SetObjectField(result, fidTime, C2JString(env, time)); - if (res.isValid()) { + if (!results.empty()) { + auto& res = results.front(); + jbyteArray jByteArray = env->NewByteArray(res.bytes().size()); + env->SetByteArrayRegion(jByteArray, 0, res.bytes().size(), (jbyte*)res.bytes().data()); + jfieldID fidBytes = env->GetFieldID(clResult, "bytes", "[B"); + env->SetObjectField(result, fidBytes, jByteArray); + jfieldID fidText = env->GetFieldID(clResult, "text", "Ljava/lang/String;"); env->SetObjectField(result, fidText, C2JString(env, res.text())); + jfieldID fidContentType = env->GetFieldID(clResult , "contentType", "Lcom/zxingcpp/BarcodeReader$ContentType;"); + env->SetObjectField(result, fidContentType, CreateContentType(env, res.contentType())); + jfieldID fidPosition = env->GetFieldID(clResult, "position", "Lcom/zxingcpp/BarcodeReader$Position;"); env->SetObjectField(result, fidPosition, CreatePosition(env, res.position())); @@ -126,7 +144,7 @@ jstring Read(JNIEnv *env, ImageView image, jstring formats, jboolean tryHarder, return C2JString(env, JavaBarcodeFormatName(res.format())); } else - return C2JString(env, ToString(res.status())); + return C2JString(env, "NotFound"); } catch (const std::exception& e) { return ThrowJavaException(env, e.what()); } catch (...) { diff --git a/wrappers/android/zxingcpp/src/main/cpp/CMakeLists.txt b/wrappers/android/zxingcpp/src/main/cpp/CMakeLists.txt index e49d0b61e5..8d28b221a2 100644 --- a/wrappers/android/zxingcpp/src/main/cpp/CMakeLists.txt +++ b/wrappers/android/zxingcpp/src/main/cpp/CMakeLists.txt @@ -12,5 +12,6 @@ add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../../../../../../core ZXing EXCLUD add_library(zxing_android SHARED BarcodeReader.cpp JNIUtils.cpp) +target_compile_definitions(zxing_android PRIVATE -DZX_USE_UTF8) target_link_libraries(zxing_android PRIVATE ZXing::ZXing log jnigraphics) diff --git a/wrappers/android/zxingcpp/src/main/cpp/JNIUtils.cpp b/wrappers/android/zxingcpp/src/main/cpp/JNIUtils.cpp index 85dc3827c7..85d1717f92 100644 --- a/wrappers/android/zxingcpp/src/main/cpp/JNIUtils.cpp +++ b/wrappers/android/zxingcpp/src/main/cpp/JNIUtils.cpp @@ -1,20 +1,11 @@ /* * Copyright 2016 Nu-book Inc. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "JNIUtils.h" +#include "TextUtfEncoding.h" + #include #include @@ -64,7 +55,7 @@ jstring C2JString(JNIEnv* env, const std::wstring& str) jstring C2JString(JNIEnv* env, const std::string& str) { - return C2JString(env, std::wstring(str.begin(), str.end())); + return C2JString(env, ZXing::TextUtfEncoding::FromUtf8(str)); } std::string J2CString(JNIEnv* env, jstring str) diff --git a/wrappers/android/zxingcpp/src/main/cpp/JNIUtils.h b/wrappers/android/zxingcpp/src/main/cpp/JNIUtils.h index 6400a41289..ed1391e022 100644 --- a/wrappers/android/zxingcpp/src/main/cpp/JNIUtils.h +++ b/wrappers/android/zxingcpp/src/main/cpp/JNIUtils.h @@ -1,19 +1,9 @@ -#pragma once /* * Copyright 2016 Nu-book Inc. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include #include diff --git a/wrappers/android/zxingcpp/src/main/java/com/zxingcpp/BarcodeReader.kt b/wrappers/android/zxingcpp/src/main/java/com/zxingcpp/BarcodeReader.kt index 52e4b3b380..8f5745976d 100644 --- a/wrappers/android/zxingcpp/src/main/java/com/zxingcpp/BarcodeReader.kt +++ b/wrappers/android/zxingcpp/src/main/java/com/zxingcpp/BarcodeReader.kt @@ -30,7 +30,10 @@ class BarcodeReader { // Note that this has to be kept synchronized with native (C++/JNI) side. enum class Format { NONE, AZTEC, CODABAR, CODE_39, CODE_93, CODE_128, DATA_BAR, DATA_BAR_EXPANDED, - DATA_MATRIX, EAN_8, EAN_13, ITF, MAXICODE, PDF_417, QR_CODE, UPC_A, UPC_E, + DATA_MATRIX, EAN_8, EAN_13, ITF, MAXICODE, PDF_417, QR_CODE, MICRO_QR_CODE, UPC_A, UPC_E + } + enum class ContentType { + TEXT, BINARY, MIXED, GS1, ISO15434, UNKNOWN_ECI } data class Options( @@ -50,8 +53,10 @@ class BarcodeReader { data class Result( val format: Format = Format.NONE, + val bytes: ByteArray? = null, val text: String? = null, val time: String? = null, // for development/debug purposes only + val contentType: ContentType = ContentType.TEXT, val position: Position? = null, val orientation: Int = 0, val ecLevel: String? = null, diff --git a/wrappers/python/demo_reader.py b/wrappers/python/demo_reader.py index d8e95cb9ef..c2a3ad9468 100644 --- a/wrappers/python/demo_reader.py +++ b/wrappers/python/demo_reader.py @@ -4,7 +4,7 @@ img = Image.open(sys.argv[1]) results = zxingcpp.read_barcodes(img) for result in results: - print("Found barcode:\n Text: '{}'\n Format: {}\n Position: {}" - .format(result.text, result.format, result.position)) + print("Found barcode:\n Text: '{}'\n Format: {}\n Content: {}\n Position: {}" + .format(result.text, result.format, result.content_type, result.position)) if len(results) == 0: print("Could not find any barcode.") diff --git a/wrappers/python/pyproject.toml b/wrappers/python/pyproject.toml index d4b45410cf..dbeaae43ca 100644 --- a/wrappers/python/pyproject.toml +++ b/wrappers/python/pyproject.toml @@ -3,7 +3,6 @@ requires = [ "setuptools>=42", "setuptools_scm", "wheel", - "pip>=21", "cmake>=3.14", ] build-backend = "setuptools.build_meta" diff --git a/wrappers/python/setup.py b/wrappers/python/setup.py index 873767a51d..eb47198d46 100644 --- a/wrappers/python/setup.py +++ b/wrappers/python/setup.py @@ -59,7 +59,7 @@ def build_extension(self, ext): # "local_scheme": "no-local-version", # "tag_regex": "v?([0-9]+.[0-9]+.[0-9]+)", # }, - version='1.3.0', + version='1.4.0', description='Python bindings for the zxing-cpp barcode library', long_description=long_description, long_description_content_type="text/markdown", diff --git a/wrappers/python/test.py b/wrappers/python/test.py index 350d08cd0e..ea979f9ee7 100644 --- a/wrappers/python/test.py +++ b/wrappers/python/test.py @@ -23,6 +23,7 @@ def check_res(self, res, format, text): self.assertTrue(res.valid) self.assertEqual(res.format, format) self.assertEqual(res.text, text) + self.assertEqual(res.bytes, bytes(text, 'utf-8')) self.assertEqual(res.orientation, 0) def test_write_read_cycle(self): @@ -65,9 +66,7 @@ def test_failed_read(self): np.zeros((100, 100), np.uint8), formats=BF.EAN8 | BF.Aztec, binarizer=zxingcpp.Binarizer.BoolCast ) - self.assertFalse(res.valid) - self.assertEqual(res.format, BF.NONE) - self.assertEqual(res.text, '') + self.assertEqual(res, None) @unittest.skipIf(not has_pil, "need PIL for read/write tests") def test_write_read_cycle_pil(self): diff --git a/wrappers/python/zxing.cpp b/wrappers/python/zxing.cpp index e7fdfa1425..1685777336 100644 --- a/wrappers/python/zxing.cpp +++ b/wrappers/python/zxing.cpp @@ -1,7 +1,17 @@ +/* + * Copyright 2019 Tim Rae + * Copyright 2021 Antoine Humbert + * Copyright 2021 Axel Waggershauser + */ +// SPDX-License-Identifier: Apache-2.0 + #include "BarcodeFormat.h" +#define ZX_USE_UTF8 1 // see Result.h + // Reader #include "ReadBarcode.h" +#include "ZXAlgorithms.h" // Writer #include "BitMatrix.h" @@ -11,6 +21,7 @@ #include #include #include +#include #include #include @@ -20,12 +31,6 @@ namespace py = pybind11; // Numpy array wrapper class for images (either BGR or GRAYSCALE) using Image = py::array_t; -template -OUT narrow(IN in) -{ - return static_cast(in); -} - std::ostream& operator<<(std::ostream& os, const Position& points) { for (const auto& p : points) os << p.x << "x" << p.y << " "; @@ -34,10 +39,8 @@ std::ostream& operator<<(std::ostream& os, const Position& points) { return os; } -template -auto read_barcode_impl(FUNC func, py::object _image, const BarcodeFormats& formats, bool try_rotate, bool try_downscale, - Binarizer binarizer, bool is_pure, EanAddOnSymbol ean_add_on_symbol, - uint8_t max_number_of_symbols = 0xff) +auto read_barcodes_impl(py::object _image, const BarcodeFormats& formats, bool try_rotate, bool try_downscale, Binarizer binarizer, + bool is_pure, EanAddOnSymbol ean_add_on_symbol, uint8_t max_number_of_symbols = 0xff) { const auto hints = DecodeHints() .setFormats(formats) @@ -55,9 +58,9 @@ auto read_barcode_impl(FUNC func, py::object _image, const BarcodeFormats& forma catch(...) { throw py::type_error("Unsupported type " + _type + ". Expect a PIL Image or numpy array"); } - const auto height = narrow(image.shape(0)); - const auto width = narrow(image.shape(1)); - auto channels = image.ndim() == 2 ? 1 : narrow(image.shape(2)); + const auto height = narrow_cast(image.shape(0)); + const auto width = narrow_cast(image.shape(1)); + auto channels = image.ndim() == 2 ? 1 : narrow_cast(image.shape(2)); ImageFormat imgfmt; if (_type.find("PIL.") != std::string::npos) { const auto mode = _image.attr("mode").cast(); @@ -84,21 +87,20 @@ auto read_barcode_impl(FUNC func, py::object _image, const BarcodeFormats& forma } const auto bytes = image.data(); - return func({bytes, width, height, imgfmt, width * channels, channels}, hints); + return ReadBarcodes({bytes, width, height, imgfmt, width * channels, channels}, hints); } -Result read_barcode(py::object _image, const BarcodeFormats& formats, bool try_rotate, bool try_downscale, - Binarizer binarizer, bool is_pure, EanAddOnSymbol ean_add_on_symbol) +std::optional read_barcode(py::object _image, const BarcodeFormats& formats, bool try_rotate, bool try_downscale, + Binarizer binarizer, bool is_pure, EanAddOnSymbol ean_add_on_symbol) { - return read_barcode_impl(ReadBarcode, _image, formats, try_rotate, try_downscale, binarizer, is_pure, - ean_add_on_symbol, 1); + auto res = read_barcodes_impl(_image, formats, try_rotate, try_downscale, binarizer, is_pure, ean_add_on_symbol, 1); + return res.empty() ? std::nullopt : std::optional(res.front()); } Results read_barcodes(py::object _image, const BarcodeFormats& formats, bool try_rotate, bool try_downscale, Binarizer binarizer, bool is_pure, EanAddOnSymbol ean_add_on_symbol) { - return read_barcode_impl(ReadBarcodes, _image, formats, try_rotate, try_downscale, binarizer, is_pure, - ean_add_on_symbol); + return read_barcodes_impl(_image, formats, try_rotate, try_downscale, binarizer, is_pure, ean_add_on_symbol); } Image write_barcode(BarcodeFormat format, std::string text, int width, int height, int quiet_zone, int ec_level) @@ -110,7 +112,7 @@ Image write_barcode(BarcodeFormat format, std::string text, int width, int heigh auto r = result.mutable_unchecked<2>(); for (py::ssize_t y = 0; y < r.shape(0); y++) for (py::ssize_t x = 0; x < r.shape(1); x++) - r(y, x) = bitmap.get(narrow(x), narrow(y)) ? 0 : 255; + r(y, x) = bitmap.get(narrow_cast(x), narrow_cast(y)) ? 0 : 255; return result; } @@ -136,14 +138,17 @@ PYBIND11_MODULE(zxingcpp, m) .value("MaxiCode", BarcodeFormat::MaxiCode) .value("PDF417", BarcodeFormat::PDF417) .value("QRCode", BarcodeFormat::QRCode) + .value("MircoQRCode", BarcodeFormat::MicroQRCode) .value("DataBar", BarcodeFormat::DataBar) .value("DataBarExpanded", BarcodeFormat::DataBarExpanded) .value("UPCA", BarcodeFormat::UPCA) .value("UPCE", BarcodeFormat::UPCE) // use upper case 'NONE' because 'None' is a reserved identifier in python .value("NONE", BarcodeFormat::None) - .value("OneDCodes", BarcodeFormat::OneDCodes) - .value("TwoDCodes", BarcodeFormat::TwoDCodes) + .value("OneDCodes", BarcodeFormat::LinearCodes) // deprecated, will be removed + .value("TwoDCodes", BarcodeFormat::MatrixCodes) // deprecated, will be removed + .value("LinearCodes", BarcodeFormat::LinearCodes) + .value("MatrixCodes", BarcodeFormat::MatrixCodes) .export_values() // see https://github.com/pybind/pybind11/issues/2221 .def("__or__", [](BarcodeFormat f1, BarcodeFormat f2){ return f1 | f2; }); @@ -165,6 +170,14 @@ PYBIND11_MODULE(zxingcpp, m) .value("Read", EanAddOnSymbol::Read) .value("Require", EanAddOnSymbol::Require) .export_values(); + py::enum_(m, "ContentType", "Enumeration of content types") + .value("Text", ContentType::Text) + .value("Binary", ContentType::Binary) + .value("Mixed", ContentType::Mixed) + .value("GS1", ContentType::GS1) + .value("ISO15434", ContentType::ISO15434) + .value("UnknownECI", ContentType::UnknownECI) + .export_values(); py::class_(m, "Point", "Represents the coordinates of a point in an image") .def_readonly("x", &PointI::x, ":return: horizontal coordinate of the point\n" @@ -197,12 +210,18 @@ PYBIND11_MODULE(zxingcpp, m) .def_property_readonly("text", &Result::text, ":return: text of the decoded symbol\n" ":rtype: str") + .def_property_readonly("bytes", [](const Result& res) { return py::bytes(res.bytes().asString()); }, + ":return: uninterpreted bytes of the decoded symbol\n" + ":rtype: bytes") .def_property_readonly("format", &Result::format, ":return: decoded symbol format\n" ":rtype: zxing.BarcodeFormat") .def_property_readonly("symbology_identifier", &Result::symbologyIdentifier, ":return: decoded symbology idendifier\n" ":rtype: str") + .def_property_readonly("content_type", &Result::contentType, + ":return: content type of symbol\n" + ":rtype: zxing.ContentType") .def_property_readonly("position", &Result::position, ":return: position of the decoded symbol\n" ":rtype: zxing.Position") @@ -254,7 +273,7 @@ PYBIND11_MODULE(zxingcpp, m) ":param ean_add_on_symbol: Specify whether to Ignore, Read or Require EAN-2/5 add-on symbols while scanning \n" " EAN/UPC codes. Default is ``Ignore``.\n" ":rtype: zxing.Result\n" - ":return: a zxing result containing decoded symbol if found." + ":return: a zxing result containing decoded symbol if found, None otherwise" ); m.def("read_barcodes", &read_barcodes, py::arg("image"), diff --git a/wrappers/wasm/BarcodeReader.cpp b/wrappers/wasm/BarcodeReader.cpp index 5dd2dab2bf..2b9c0b46a0 100644 --- a/wrappers/wasm/BarcodeReader.cpp +++ b/wrappers/wasm/BarcodeReader.cpp @@ -1,18 +1,9 @@ /* * Copyright 2016 Nu-book Inc. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#define ZX_USE_UTF8 1 // see Result.h #include "ReadBarcode.h" @@ -27,12 +18,12 @@ struct ReadResult { std::string format; - std::wstring text; + std::string text; std::string error; ZXing::Position position; }; -ReadResult readBarcodeFromImage(int bufferPtr, int bufferLength, bool tryHarder, std::string format) +ReadResult readBarcodeFromImageView(ZXing::ImageView iv, bool tryHarder, const std::string& format) { using namespace ZXing; try { @@ -41,54 +32,42 @@ ReadResult readBarcodeFromImage(int bufferPtr, int bufferLength, bool tryHarder, hints.setTryRotate(tryHarder); hints.setTryDownscale(tryHarder); hints.setFormats(BarcodeFormatsFromString(format)); + hints.setMaxNumberOfSymbols(1); - int width, height, channels; - std::unique_ptr buffer( - stbi_load_from_memory(reinterpret_cast(bufferPtr), bufferLength, &width, &height, - &channels, 4), - stbi_image_free); - if (buffer == nullptr) { - return { "", L"", "Error loading image" }; - } - - auto result = ReadBarcode({buffer.get(), width, height, ImageFormat::RGBX}, hints); - if (result.isValid()) { + auto results = ReadBarcodes(iv, hints); + if (!results.empty()) { + auto& result = results.front(); return { ToString(result.format()), result.text(), "", result.position() }; } } catch (const std::exception& e) { - return { "", L"", e.what() }; + return { "", "", e.what() }; } catch (...) { - return { "", L"", "Unknown error" }; + return { "", "", "Unknown error" }; } return {}; } -ReadResult readBarcodeFromPixmap(int bufferPtr, int imgWidth, int imgHeight, bool tryHarder, std::string format) +ReadResult readBarcodeFromImage(int bufferPtr, int bufferLength, bool tryHarder, std::string format) { using namespace ZXing; - try { - DecodeHints hints; - hints.setTryHarder(tryHarder); - hints.setTryRotate(tryHarder); - hints.setTryDownscale(tryHarder); - hints.setFormats(BarcodeFormatsFromString(format)); - - auto result = - ReadBarcode({reinterpret_cast(bufferPtr), imgWidth, imgHeight, ImageFormat::RGBX}, hints); - if (result.isValid()) { - return { ToString(result.format()), result.text(), "", result.position() }; - } - } - catch (const std::exception& e) { - return { "", L"", e.what() }; + int width, height, channels; + std::unique_ptr buffer( + stbi_load_from_memory(reinterpret_cast(bufferPtr), bufferLength, &width, &height, &channels, 4), + stbi_image_free); + if (buffer == nullptr) { + return {"", "", "Error loading image"}; } - catch (...) { - return { "", L"", "Unknown error" }; - } - return {}; + + return readBarcodeFromImageView({buffer.get(), width, height, ImageFormat::RGBX}, tryHarder, format); +} + +ReadResult readBarcodeFromPixmap(int bufferPtr, int imgWidth, int imgHeight, bool tryHarder, std::string format) +{ + using namespace ZXing; + return readBarcodeFromImageView({reinterpret_cast(bufferPtr), imgWidth, imgHeight, ImageFormat::RGBX}, tryHarder, format); } EMSCRIPTEN_BINDINGS(BarcodeReader) @@ -117,7 +96,7 @@ EMSCRIPTEN_BINDINGS(BarcodeReader) function("readBarcodeFromImage", &readBarcodeFromImage); function("readBarcodeFromPixmap", &readBarcodeFromPixmap); - // obsoletes + // obsoletes [[deprecated]] function("readBarcode", &readBarcodeFromImage); function("readBarcodeFromPng", &readBarcodeFromImage); } diff --git a/wrappers/wasm/BarcodeWriter.cpp b/wrappers/wasm/BarcodeWriter.cpp index 4b6e23c350..ed2a2b1663 100644 --- a/wrappers/wasm/BarcodeWriter.cpp +++ b/wrappers/wasm/BarcodeWriter.cpp @@ -1,23 +1,12 @@ /* * Copyright 2016 Nu-book Inc. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #include "BarcodeFormat.h" #include "MultiFormatWriter.h" #include "BitMatrix.h" -#include "CharacterSetECI.h" +#include "CharacterSet.h" #include #include @@ -70,7 +59,7 @@ WriteResult generateBarcode(std::wstring text, std::string format, std::string e if (margin >= 0) writer.setMargin(margin); - CharacterSet charset = CharacterSetECI::CharsetFromName(encoding.c_str()); + CharacterSet charset = CharacterSetFromString(encoding); if (charset != CharacterSet::Unknown) writer.setEncoding(charset); diff --git a/wrappers/winrt/BarcodeReader.cpp b/wrappers/winrt/BarcodeReader.cpp index 2a57e48df3..84303c6a64 100644 --- a/wrappers/winrt/BarcodeReader.cpp +++ b/wrappers/winrt/BarcodeReader.cpp @@ -1,18 +1,7 @@ /* * Copyright 2016 Nu-book Inc. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 #if (_MSC_VER >= 1915) #define no_init_all deprecated @@ -21,6 +10,8 @@ #include "BarcodeReader.h" +#define ZX_USE_UTF8 1 // silence deprecation warning in Result.h + #include "BarcodeFormat.h" #include "DecodeHints.h" #include "ReadBarcode.h" @@ -77,37 +68,39 @@ BarcodeFormat BarcodeReader::ConvertRuntimeToNative(BarcodeType type) { switch (type) { case BarcodeType::AZTEC: - return BarcodeFormat::AZTEC; + return BarcodeFormat::Aztec; case BarcodeType::CODABAR: - return BarcodeFormat::CODABAR; + return BarcodeFormat::Codabar; case BarcodeType::CODE_128: - return BarcodeFormat::CODE_128; + return BarcodeFormat::Code128; case BarcodeType::CODE_39: - return BarcodeFormat::CODE_39; + return BarcodeFormat::Code39; case BarcodeType::CODE_93: - return BarcodeFormat::CODE_93; + return BarcodeFormat::Code93; case BarcodeType::DATA_MATRIX: - return BarcodeFormat::DATA_MATRIX; + return BarcodeFormat::DataMatrix; case BarcodeType::EAN_13: - return BarcodeFormat::EAN_13; + return BarcodeFormat::EAN13; case BarcodeType::EAN_8: - return BarcodeFormat::EAN_8; + return BarcodeFormat::EAN8; case BarcodeType::ITF: return BarcodeFormat::ITF; case BarcodeType::MAXICODE: - return BarcodeFormat::MAXICODE; + return BarcodeFormat::MaxiCode; case BarcodeType::PDF_417: - return BarcodeFormat::PDF_417; + return BarcodeFormat::PDF417; case BarcodeType::QR_CODE: - return BarcodeFormat::QR_CODE; + return BarcodeFormat::QRCode; + case BarcodeType::MICRO_QR_CODE: + return BarcodeFormat::MicroQRCode; case BarcodeType::RSS_14: - return BarcodeFormat::RSS_14; + return BarcodeFormat::DataBar; case BarcodeType::RSS_EXPANDED: - return BarcodeFormat::RSS_EXPANDED; + return BarcodeFormat::DataBarExpanded; case BarcodeType::UPC_A: - return BarcodeFormat::UPC_A; + return BarcodeFormat::UPCA; case BarcodeType::UPC_E: - return BarcodeFormat::UPC_E; + return BarcodeFormat::UPCE; default: std::wstring typeAsString = type.ToString()->Begin(); throw std::invalid_argument("Unknown Barcode Type: " + TextUtfEncoding::ToUtf8(typeAsString)); @@ -117,52 +110,49 @@ BarcodeFormat BarcodeReader::ConvertRuntimeToNative(BarcodeType type) BarcodeType BarcodeReader::ConvertNativeToRuntime(BarcodeFormat format) { switch (format) { - case BarcodeFormat::AZTEC: + case BarcodeFormat::Aztec: return BarcodeType::AZTEC; - case BarcodeFormat::CODABAR: + case BarcodeFormat::Codabar: return BarcodeType::CODABAR; - case BarcodeFormat::CODE_128: + case BarcodeFormat::Code128: return BarcodeType::CODE_128; - case BarcodeFormat::CODE_39: + case BarcodeFormat::Code39: return BarcodeType::CODE_39; - case BarcodeFormat::CODE_93: + case BarcodeFormat::Code93: return BarcodeType::CODE_93; - case BarcodeFormat::DATA_MATRIX: + case BarcodeFormat::DataMatrix: return BarcodeType::DATA_MATRIX; - case BarcodeFormat::EAN_13: + case BarcodeFormat::EAN13: return BarcodeType::EAN_13; - case BarcodeFormat::EAN_8: + case BarcodeFormat::EAN8: return BarcodeType::EAN_8; case BarcodeFormat::ITF: return BarcodeType::ITF; - case BarcodeFormat::MAXICODE: + case BarcodeFormat::MaxiCode: return BarcodeType::MAXICODE; - case BarcodeFormat::PDF_417: + case BarcodeFormat::PDF417: return BarcodeType::PDF_417; - case BarcodeFormat::QR_CODE: + case BarcodeFormat::QRCode: return BarcodeType::QR_CODE; - case BarcodeFormat::RSS_14: + case BarcodeFormat::MicroQRCode: + return BarcodeType::MICRO_QR_CODE; + case BarcodeFormat::DataBar: return BarcodeType::RSS_14; - case BarcodeFormat::RSS_EXPANDED: + case BarcodeFormat::DataBarExpanded: return BarcodeType::RSS_EXPANDED; - case BarcodeFormat::UPC_A: + case BarcodeFormat::UPCA: return BarcodeType::UPC_A; - case BarcodeFormat::UPC_E: + case BarcodeFormat::UPCE: return BarcodeType::UPC_E; default: throw std::invalid_argument("Unknown Barcode Format "); } } -static Platform::String^ ToPlatformString(const std::wstring& str) -{ - return ref new Platform::String(str.c_str(), (unsigned)str.length()); -} - static Platform::String^ ToPlatformString(const std::string& str) { - auto ptr = (const uint8_t*)str.data(); - return ToPlatformString(std::wstring(ptr, ptr + str.length())); + std::wstring wstr = TextUtfEncoding::FromUtf8(str); + return ref new Platform::String(wstr.c_str(), (unsigned)wstr.length()); } ReadResult^ diff --git a/wrappers/winrt/BarcodeReader.h b/wrappers/winrt/BarcodeReader.h index 6b5dd8c83c..e68383e0e7 100644 --- a/wrappers/winrt/BarcodeReader.h +++ b/wrappers/winrt/BarcodeReader.h @@ -1,19 +1,9 @@ -#pragma once /* * Copyright 2016 Nu-book Inc. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once #include "BarcodeFormat.h" @@ -34,6 +24,7 @@ public enum class BarcodeType : int { MAXICODE, PDF_417, QR_CODE, + MICRO_QR_CODE, RSS_14, RSS_EXPANDED, UPC_A, diff --git a/wrappers/winrt/ReadResult.h b/wrappers/winrt/ReadResult.h index 65e8251afe..9361441605 100644 --- a/wrappers/winrt/ReadResult.h +++ b/wrappers/winrt/ReadResult.h @@ -1,19 +1,9 @@ -#pragma once /* * Copyright 2016 Nu-book Inc. -* -* Licensed under the Apache License, Version 2.0 (the "License"); -* you may not use this file except in compliance with the License. -* You may obtain a copy of the License at -* -* http://www.apache.org/licenses/LICENSE-2.0 -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific language governing permissions and -* limitations under the License. */ +// SPDX-License-Identifier: Apache-2.0 + +#pragma once namespace ZXing {