diff --git a/CMakeLists.txt b/CMakeLists.txt index 3dba4bf..e9b384a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,103 +1,108 @@ cmake_minimum_required(VERSION 3.0) set(PIM_VERSION "5.9.49") project(KItinerary VERSION ${PIM_VERSION}) set(CMAKE_CXX_STANDARD 14) set(KF5_VERSION "5.50.0") find_package(ECM ${KF5_VERSION} REQUIRED NO_MODULE) set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH} ${ECM_KDE_MODULE_DIR} ${CMAKE_SOURCE_DIR}/cmake) include(KDEFrameworkCompilerSettings NO_POLICY_SCOPE) include(ECMAddTests) include(ECMGenerateHeaders) include(ECMQtDeclareLoggingCategory) include(ECMSetupVersion) include(FeatureSummary) include(KDEInstallDirs) include(KDECMakeSettings) include(GenerateExportHeader) ecm_setup_version(PROJECT VARIABLE_PREFIX KITINERARY VERSION_HEADER kitinerary_version.h PACKAGE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/KPimItineraryConfigVersion.cmake" ) set(QT_REQUIRED_VERSION "5.9.0") find_package(Qt5 ${QT_REQUIRED_VERSION} REQUIRED COMPONENTS Test Gui Qml) find_package(KF5 ${KF5_VERSION} REQUIRED COMPONENTS I18n) set(KMIME_VERSION "5.9.40") set(KCALENDARCORE_LIB_VERSION "5.9.41") set(KCONTACTS_LIB_VERSION "5.9.40") find_package(KF5Mime ${KMIME_VERSION} CONFIG REQUIRED) find_package(KF5CalendarCore ${KCALENDARCORE_LIB_VERSION} CONFIG) find_package(KF5Contacts ${KCONTACTS_LIB_VERSION} CONFIG REQUIRED) find_package(KPimPkPass CONFIG REQUIRED) find_package(Poppler COMPONENTS Core) set_package_properties("Poppler" PROPERTIES TYPE OPTIONAL PURPOSE "Support for extraction from PDF booking confirmations.") -find_package(zxing CONFIG) -set_package_properties("zxing" PROPERTIES TYPE OPTIONAL PURPOSE "Support for barcode decoding." URL "https://github.com/glassechidna/zxing-cpp") +find_package(ZXing CONFIG) +set_package_properties("ZXing" PROPERTIES TYPE OPTIONAL PURPOSE "Support for barcode decoding." URL "https://github.com/nu-book/zxing-cpp") find_package(ZLIB REQUIRED) set_package_properties("ZLIB" PROPERTIES PURPOSE "Support for decoding UIC 918-3 train tickets.") find_package(LibXml2 MODULE) set_package_properties("LibXml2" PROPERTIES PURPOSE "Support for extraction from HTML booking confirmations." URL "http://libxml.org") if (NOT ANDROID) set_package_properties(KF5CalendarCore PROPERTIES TYPE REQUIRED) set_package_properties(LibXml2 PROPERTIES TYPE REQUIRED) endif() if(TARGET Poppler::Core) set(HAVE_POPPLER ON) if (${Poppler_VERSION} VERSION_GREATER 0.57) set(HAVE_POPPLER_0_58 ON) endif() if (${Poppler_VERSION} VERSION_GREATER 0.68) set(HAVE_POPPLER_0_69 ON) endif() endif() -if (TARGET zxing::libzxing) + +if (TARGET ZXing::Core) set(HAVE_ZXING ON) +elseif (TARGET zxing::libzxing) + message(WARNING "Old zxing-cpp variant from https://github.com/glassechidna/zxing-cpp found - support for this will be removed eventually!") + set(HAVE_ZXING_OLD ON) endif() + if (TARGET KF5::CalendarCore) set(HAVE_KCAL ON) endif() if (LIBXML2_FOUND) set(HAVE_LIBXML2 ON) endif() add_definitions(-DTRANSLATION_DOMAIN=\"kitinerary\") add_definitions(-DQT_NO_NARROWING_CONVERSIONS_IN_CONNECT) add_definitions(-DQT_DISABLE_DEPRECATED_BEFORE=0x060000) add_subdirectory(src) if(BUILD_TESTING) add_subdirectory(autotests) endif() feature_summary(WHAT ALL INCLUDE_QUIET_PACKAGES FATAL_ON_MISSING_REQUIRED_PACKAGES) set(CMAKECONFIG_INSTALL_DIR "${CMAKECONFIG_INSTALL_PREFIX}/KPimItinerary") configure_package_config_file( "${CMAKE_CURRENT_SOURCE_DIR}/KPimItineraryConfig.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/KPimItineraryConfig.cmake" INSTALL_DESTINATION "${CMAKECONFIG_INSTALL_DIR}" ) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/KPimItineraryConfig.cmake" "${CMAKE_CURRENT_BINARY_DIR}/KPimItineraryConfigVersion.cmake" DESTINATION "${CMAKECONFIG_INSTALL_DIR}" COMPONENT Devel) install(EXPORT KPimItineraryTargets DESTINATION "${CMAKECONFIG_INSTALL_DIR}" FILE KPimItineraryTargets.cmake NAMESPACE KPim:: ) install(FILES org_kde_kitinerary.categories DESTINATION ${KDE_INSTALL_CONFDIR}) diff --git a/KPimItineraryConfig.cmake.in b/KPimItineraryConfig.cmake.in index 6834a95..4781c19 100644 --- a/KPimItineraryConfig.cmake.in +++ b/KPimItineraryConfig.cmake.in @@ -1,26 +1,29 @@ @PACKAGE_INIT@ include(CMakeFindDependencyMacro) find_dependency(Qt5Gui) find_dependency(KF5Mime) if (@HAVE_KCAL@) find_dependency(KF5CalendarCore) endif() find_dependency(KF5Contacts) find_dependency(KPimPkPass) if (NOT @BUILD_SHARED_LIBS@) find_dependency(ZLIB) if (@HAVE_POPPLER@) find_dependency(Poppler) endif() if (@HAVE_ZXING@) + find_dependency(ZXing) + endif() + if (@HAVE_ZXING_OLD@) find_dependency(zxing) endif() if (@HAVE_LIBXML2@) find_dependency(LibXml2) endif() endif() include("${CMAKE_CURRENT_LIST_DIR}/KPimItineraryTargets.cmake") @PACKAGE_INCLUDE_QCHTARGETS@ diff --git a/autotests/barcodedecodertest.cpp b/autotests/barcodedecodertest.cpp index b9f1517..0678804 100644 --- a/autotests/barcodedecodertest.cpp +++ b/autotests/barcodedecodertest.cpp @@ -1,102 +1,102 @@ /* Copyright (C) 2018 Volker Krause This program is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include #include #include #include #include #include using namespace KItinerary; class BarcodeDecoderTest : public QObject { Q_OBJECT private Q_SLOTS: void testPDF417_data() { QTest::addColumn("fileName"); QTest::newRow("1bit") << QStringLiteral("pdf417_1bit.png"); QTest::newRow("8bit") << QStringLiteral("pdf417_8bit.png"); QTest::newRow("24bit") << QStringLiteral("pdf417_24bit.png"); QTest::newRow("32bit") << QStringLiteral("pdf417_32bit.png"); QTest::newRow("cropped") << QStringLiteral("pdf417_cropped.png"); QTest::newRow("rot90") << QStringLiteral("pdf417_rot90.png"); QTest::newRow("rot180") << QStringLiteral("pdf417_rot180.png"); QTest::newRow("rot270") << QStringLiteral("pdf417_rot270.png"); QTest::newRow("flipped") << QStringLiteral("pdf417_flipped.png"); } void testPDF417() { QFETCH(QString, fileName); QImage img(QStringLiteral(SOURCE_DIR "/barcodes/") + fileName); QVERIFY(!img.isNull()); -#ifdef HAVE_ZXING +#ifdef HAVE_ZXING_ANY QCOMPARE(BarcodeDecoder::decodePdf417(img), QStringLiteral("PDF417 is a stacked linear barcode symbol format used in a variety of applications, primarily transport, identification cards, and inventory management.")); #endif } void testAztec() { QImage img(QStringLiteral(SOURCE_DIR "/barcodes/aztec.png")); QVERIFY(!img.isNull()); -#ifdef HAVE_ZXING +#ifdef HAVE_ZXING_ANY QCOMPARE(BarcodeDecoder::decodeAztec(img), QStringLiteral("This is an example Aztec symbol for Wikipedia.")); #endif img.load(QStringLiteral(SOURCE_DIR "/barcodes/uic918-3star.png")); QVERIFY(!img.isNull()); -#ifdef HAVE_ZXING +#ifdef HAVE_ZXING_ANY const auto b = BarcodeDecoder::decodeAztecBinary(img); QCOMPARE(b.size(), 351); QVERIFY(b.startsWith("OTI010080000020")); #endif } void testQRCode_data() { QTest::addColumn("fileName"); QTest::addColumn("result"); QTest::newRow("1") << QStringLiteral("qrcode1.png") << QStringLiteral("M$K0YGV0G"); QTest::newRow("2") << QStringLiteral("qrcode2.png") << QStringLiteral("KZEXO4HRE"); } void testQRCode() { QFETCH(QString, fileName); QFETCH(QString, result); QImage img(QStringLiteral(SOURCE_DIR "/barcodes/") + fileName); QVERIFY(!img.isNull()); -#ifdef HAVE_ZXING +#ifdef HAVE_ZXING_ANY QCOMPARE(BarcodeDecoder::decodeQRCode(img), result); #endif } }; QTEST_APPLESS_MAIN(BarcodeDecoderTest) #include "barcodedecodertest.moc" diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 69f2232..56b60e9 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,155 +1,160 @@ set(KDE_INSTALL_INCLUDEDIR_PIM ${KDE_INSTALL_INCLUDEDIR}/KPim) add_subdirectory(knowledgedb-generator) configure_file(config-kitinerary.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config-kitinerary.h) set(kitinerary_lib_srcs datatypes/action.cpp datatypes/brand.cpp datatypes/bustrip.cpp datatypes/event.cpp datatypes/flight.cpp datatypes/organization.cpp datatypes/person.cpp datatypes/place.cpp datatypes/reservation.cpp datatypes/taxi.cpp datatypes/ticket.cpp datatypes/traintrip.cpp datatypes/rentalcar.cpp datatypes/visit.cpp jsapi/barcode.cpp jsapi/context.cpp jsapi/jsonld.cpp knowledgedb/airportdb.cpp knowledgedb/countrydb.cpp knowledgedb/knowledgedb.cpp knowledgedb/timezonedb.cpp knowledgedb/trainstationdb.cpp barcodedecoder.cpp calendarhandler.cpp extractor.cpp extractorengine.cpp extractorfilter.cpp extractorpostprocessor.cpp extractorrepository.cpp genericpdfextractor.cpp htmldocument.cpp iatabcbpparser.cpp jsonlddocument.cpp jsonldimportfilter.cpp mergeutil.cpp pdfdocument.cpp qimageluminancesource.cpp + qimagepurebinarizer.cpp sortutil.cpp stringutil.cpp structureddataextractor.cpp uic9183parser.cpp ) qt5_add_resources(kitinerary_lib_srcs extractors/extractors.qrc) ecm_qt_declare_logging_category(kitinerary_lib_srcs HEADER logging.h IDENTIFIER KItinerary::Log CATEGORY_NAME org.kde.kitinerary) kde_source_files_enable_exceptions(barcodedecoder.cpp) add_library(KPimItinerary ${kitinerary_lib_srcs}) add_library(KPim::Itinerary ALIAS KPimItinerary) generate_export_header(KPimItinerary BASE_NAME KItinerary) set_target_properties(KPimItinerary PROPERTIES VERSION ${KITINERARY_VERSION_STRING} SOVERSION ${KITINERARY_SOVERSION} EXPORT_NAME Itinerary ) target_include_directories(KPimItinerary INTERFACE "$") target_include_directories(KPimItinerary PUBLIC "$") target_link_libraries(KPimItinerary PUBLIC Qt5::Core KF5::Mime PRIVATE Qt5::Qml KF5::I18n KF5::Contacts KPim::PkPass ${ZLIB_LIBRARIES} ) if (HAVE_POPPLER) target_link_libraries(KPimItinerary PRIVATE Poppler::Core) endif() + if (HAVE_ZXING) + target_link_libraries(KPimItinerary PRIVATE ZXing::Core) +elseif (HAVE_ZXING_OLD) target_link_libraries(KPimItinerary PRIVATE zxing::libzxing) endif() + if (HAVE_KCAL) target_link_libraries(KPimItinerary PUBLIC KF5::CalendarCore) endif() if (HAVE_LIBXML2) target_compile_definitions(KPimItinerary PRIVATE ${LIBXML2_DEFINITIONS}) target_include_directories(KPimItinerary PRIVATE ${LIBXML2_INCLUDE_DIR}) target_link_libraries(KPimItinerary PRIVATE ${LIBXML2_LIBRARIES}) endif() ecm_generate_headers(KItinerary_FORWARDING_HEADERS HEADER_NAMES BarcodeDecoder CalendarHandler Extractor ExtractorEngine ExtractorPostprocessor HtmlDocument IataBcbpParser JsonLdDocument MergeUtil PdfDocument SortUtil Uic9183Parser PREFIX KItinerary REQUIRED_HEADERS KItinerary_HEADERS ) ecm_generate_headers(KItinerary_KnowledgeDb_FORWARDING_HEADERS HEADER_NAMES AirportDb CountryDb KnowledgeDb TrainStationDb PREFIX KItinerary REQUIRED_HEADERS KItinerary_KnowledgeDb_HEADERS RELATIVE knowledgedb ) ecm_generate_headers(KItinerary_Datatypes_FORWARDING_HEADERS HEADER_NAMES Action Brand BusTrip Datatypes Event Flight Organization Reservation RentalCar Person Place Taxi Ticket TrainTrip Visit PREFIX KItinerary REQUIRED_HEADERS KItinerary_Datatypes_HEADERS RELATIVE datatypes ) install(TARGETS KPimItinerary EXPORT KPimItineraryTargets ${INSTALL_TARGETS_DEFAULT_ARGS}) install(FILES ${KItinerary_FORWARDING_HEADERS} ${KItinerary_KnowledgeDb_FORWARDING_HEADERS} ${KItinerary_Datatypes_FORWARDING_HEADERS} DESTINATION ${KDE_INSTALL_INCLUDEDIR_PIM}/KItinerary ) install(FILES ${KItinerary_HEADERS} ${KItinerary_AirportDb_HEADERS} ${KItinerary_Datatypes_HEADERS} ${KItinerary_KnowledgeDb_HEADERS} ${CMAKE_CURRENT_BINARY_DIR}/kitinerary_export.h DESTINATION ${KDE_INSTALL_INCLUDEDIR_PIM}/kitinerary ) diff --git a/src/barcodedecoder.cpp b/src/barcodedecoder.cpp index b764a41..121fcd6 100644 --- a/src/barcodedecoder.cpp +++ b/src/barcodedecoder.cpp @@ -1,126 +1,165 @@ /* Copyright (C) 2018 Volker Krause This program is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "config-kitinerary.h" #include "barcodedecoder.h" #include "logging.h" #include "qimageluminancesource.h" +#include "qimagepurebinarizer.h" #include #include #include #ifdef HAVE_ZXING +#include +#include +#include +#elif defined(HAVE_ZXING_OLD) #include #include #include #include #include #endif #include using namespace KItinerary; #ifdef HAVE_ZXING +using ZXing::BarcodeFormat; + +static QString decodeString(const QImage &img, ZXing::BarcodeFormat format) +{ + QImagePureBinarizer binarizer(img); + ZXing::DecodeHints hints; + hints.setPossibleFormats({format}); + ZXing::MultiFormatReader reader(hints); + const auto result = reader.read(binarizer); + if (result.isValid()) { + return QString::fromStdWString(result.text()); + } + return {}; +} + +static QByteArray decodeBinary(const QImage &img, ZXing::BarcodeFormat format) +{ + QImagePureBinarizer binarizer(img); + ZXing::DecodeHints hints; + hints.setPossibleFormats({format}); + ZXing::MultiFormatReader reader(hints); + auto result = reader.read(binarizer); + if (result.isValid()) { + QByteArray b; + b.resize(result.text().size()); + std::copy(result.text().begin(), result.text().end(), b.begin()); + return b; + } + return {}; +} + +#elif defined(HAVE_ZXING_OLD) +using zxing::BarcodeFormat; + static QString decodeString(const QImage &img, zxing::BarcodeFormat format) { try { const zxing::Ref source(new QImageLuminanceSource(img)); const zxing::Ref binarizer(new zxing::HybridBinarizer(source)); const zxing::Ref binary(new zxing::BinaryBitmap(binarizer)); const zxing::DecodeHints hints(1 << format); zxing::MultiFormatReader reader; const auto result = reader.decode(binary, hints); return QString::fromStdString(result->getText()->getText()); } catch (const std::exception &e) { //qCDebug(Log) << e.what(); } return {}; } static QByteArray decodeBinary(const QImage &img, zxing::BarcodeFormat format) { try { const zxing::Ref source(new QImageLuminanceSource(img)); const zxing::Ref binarizer(new zxing::HybridBinarizer(source)); const zxing::Ref binary(new zxing::BinaryBitmap(binarizer)); const zxing::DecodeHints hints(1 << format); zxing::MultiFormatReader reader; const auto result = reader.decode(binary, hints); return QByteArray(result->getText()->getText().c_str(), result->getText()->getText().size()); } catch (const std::exception &e) { //qCDebug(Log) << e.what(); } return {}; } #endif QString BarcodeDecoder::decodePdf417(const QImage &img) { -#ifdef HAVE_ZXING +#ifdef HAVE_ZXING_ANY auto normalizedImg = img; if (normalizedImg.width() < normalizedImg.height()) { QTransform tf; tf.rotate(-90); normalizedImg = normalizedImg.transformed(tf); } - const auto result = decodeString(normalizedImg, zxing::BarcodeFormat::PDF_417); + const auto result = decodeString(normalizedImg, BarcodeFormat::PDF_417); if (!result.isEmpty()) { return result; } // try flipped around the x axis, zxing doesn't detect that, but it's e.g. encountered in SAS passes - return decodeString(normalizedImg.transformed(QTransform{1, 0, 0, -1, 0, 0}), zxing::BarcodeFormat::PDF_417); + return decodeString(normalizedImg.transformed(QTransform{1, 0, 0, -1, 0, 0}), BarcodeFormat::PDF_417); #else Q_UNUSED(img); return {}; #endif } QString BarcodeDecoder::decodeAztec(const QImage &img) { -#ifdef HAVE_ZXING - return decodeString(img, zxing::BarcodeFormat::AZTEC); +#ifdef HAVE_ZXING_ANY + return decodeString(img, BarcodeFormat::AZTEC); #else Q_UNUSED(img); return {}; #endif } QByteArray BarcodeDecoder::decodeAztecBinary(const QImage &img) { -#ifdef HAVE_ZXING - return decodeBinary(img, zxing::BarcodeFormat::AZTEC); +#ifdef HAVE_ZXING_ANY + return decodeBinary(img, BarcodeFormat::AZTEC); #else Q_UNUSED(img); #endif return {}; } QString BarcodeDecoder::decodeQRCode(const QImage &img) { -#ifdef HAVE_ZXING - return decodeString(img, zxing::BarcodeFormat::QR_CODE); +#ifdef HAVE_ZXING_ANY + return decodeString(img, BarcodeFormat::QR_CODE); #else Q_UNUSED(img); return {}; #endif } diff --git a/src/config-kitinerary.h.cmake b/src/config-kitinerary.h.cmake index 250f7ab..4352758 100644 --- a/src/config-kitinerary.h.cmake +++ b/src/config-kitinerary.h.cmake @@ -1,30 +1,36 @@ /* Copyright (c) 2017 Volker Krause This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef CONFIG_KITINERARY_H #define CONFIG_KITINERARY_H #cmakedefine HAVE_POPPLER #cmakedefine HAVE_POPPLER_0_58 #cmakedefine HAVE_POPPLER_0_69 + #cmakedefine HAVE_ZXING +#cmakedefine HAVE_ZXING_OLD +#if defined(HAVE_ZXING) || defined(HAVE_ZXING_OLD) +#define HAVE_ZXING_ANY +#endif + #cmakedefine HAVE_KCAL #cmakedefine HAVE_LIBXML2 #endif diff --git a/src/qimageluminancesource.cpp b/src/qimageluminancesource.cpp index 1593362..4940b8d 100644 --- a/src/qimageluminancesource.cpp +++ b/src/qimageluminancesource.cpp @@ -1,73 +1,73 @@ /* Copyright (C) 2018 Volker Krause This program is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #include "qimageluminancesource.h" -#ifdef HAVE_ZXING +#ifdef HAVE_ZXING_OLD using namespace KItinerary; QImageLuminanceSource::QImageLuminanceSource(const QImage &img) : zxing::LuminanceSource(img.width() + 2, img.height() + 2) , m_img(img) { } QImageLuminanceSource::~QImageLuminanceSource() = default; zxing::ArrayRef QImageLuminanceSource::getRow(int y, zxing::ArrayRef row) const { if (!row) { row = zxing::ArrayRef(getWidth()); } if (y == 0 || y == getHeight() - 1) { memset(&row[0], 0xff, getWidth()); return row; } row[0] = (char)0xff; for (int i = 1; i < getWidth() - 1; ++i) { row[i] = luminance(i - 1, y); } row[getWidth() - 1] = (char)0xff; return row; } zxing::ArrayRef QImageLuminanceSource::getMatrix() const { zxing::ArrayRef matrix(getWidth() * getHeight()); memset(&matrix[0], 0xff, getWidth()); for (int i = 1; i < getHeight() - 1; ++i) { matrix[i * getWidth()] = (char)0xff; for (int j = 1; j < getWidth() - 1; ++j) { matrix[i * getWidth() + j] = luminance(j - 1, i - 1); } matrix[(i + 1) * getWidth() - 1] = (char)0xff; } memset(&matrix[(getHeight() - 1) * getWidth()], 0xff, getWidth()); return matrix; } char QImageLuminanceSource::luminance(int x, int y) const { return qGray(m_img.pixel(x, y)); } #endif diff --git a/src/qimageluminancesource.h b/src/qimageluminancesource.h index 55c8c55..2cc7c71 100644 --- a/src/qimageluminancesource.h +++ b/src/qimageluminancesource.h @@ -1,52 +1,52 @@ /* Copyright (C) 2018 Volker Krause This program is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . */ #ifndef KITINERARY_QIMAGELUMINANCESOURCE_H #define KITINERARY_QIMAGELUMINANCESOURCE_H #include "config-kitinerary.h" -#ifdef HAVE_ZXING +#ifdef HAVE_ZXING_OLD #include #include namespace KItinerary { /** QImage-based LuminanceSource. * This automatically adds a 1px quiet zone around the content. */ class QImageLuminanceSource : public zxing::LuminanceSource { public: explicit QImageLuminanceSource(const QImage &img); ~QImageLuminanceSource(); zxing::ArrayRef getRow(int y, zxing::ArrayRef row) const override; zxing::ArrayRef getMatrix() const override; private: char luminance(int x, int y) const; QImage m_img; }; } #endif #endif // KITINERARY_QIMAGELUMINANCESOURCE_H diff --git a/src/qimagepurebinarizer.cpp b/src/qimagepurebinarizer.cpp new file mode 100644 index 0000000..bf340e6 --- /dev/null +++ b/src/qimagepurebinarizer.cpp @@ -0,0 +1,116 @@ +/* + Copyright (C) 2018 Volker Krause + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public + License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#include "qimagepurebinarizer.h" +#ifdef HAVE_ZXING + +#include + +using namespace KItinerary; + +QImagePureBinarizer::QImagePureBinarizer(const QImage &img) + : m_img(img) +{ +} + +QImagePureBinarizer::~QImagePureBinarizer() = default; + +int QImagePureBinarizer::height() const +{ + return m_img.height() + 2; +} + +int QImagePureBinarizer::width() const +{ + return m_img.width() + 2; +} + +bool QImagePureBinarizer::isPureBarcode() const +{ + return true; +} + +bool QImagePureBinarizer::getBlackRow(int y, ZXing::BitArray &row) const +{ + using namespace ZXing; + + const auto w = width(); + if (row.size() != w) { + row = BitArray(w); + } else { + row.clearBits(); + } + + if (y == 0 || y == height() - 1) { + return true; + } + + for (auto i = 1; i < w - 1; ++i) { + if (qGray(m_img.pixel(i - 1, y - 1)) < 127) + row.set(i); + } + return true; +} + +std::shared_ptr QImagePureBinarizer::getBlackMatrix() const +{ + using namespace ZXing; + + if (!m_bitmap) { + const auto w = width(); + const auto h = height(); + + auto bitmap = std::make_shared(w, h); + for (int x = 1; x < w - 1; ++x) { + for (int y = 1; y < h - 1; ++y) { + if (qGray(m_img.pixel(x - 1, y - 1)) < 127) + bitmap->set(x, y); + } + } + + m_bitmap = std::move(bitmap); + } + + return m_bitmap; +} + +bool QImagePureBinarizer::canCrop() const +{ + return false; // unused by ZXing +} + +std::shared_ptr QImagePureBinarizer::cropped(int left, int top, int width, int height) const +{ + Q_UNUSED(left); + Q_UNUSED(top); + Q_UNUSED(width); + Q_UNUSED(height); + return {}; +} + +bool QImagePureBinarizer::canRotate() const +{ + return false; +} + +std::shared_ptr QImagePureBinarizer::rotated(int degreeCW) const +{ + Q_UNUSED(degreeCW); + return {}; +} + +#endif diff --git a/src/qimagepurebinarizer.h b/src/qimagepurebinarizer.h new file mode 100644 index 0000000..9c2043e --- /dev/null +++ b/src/qimagepurebinarizer.h @@ -0,0 +1,62 @@ +/* + Copyright (C) 2018 Volker Krause + + This program is free software; you can redistribute it and/or modify it + under the terms of the GNU Library General Public License as published by + the Free Software Foundation; either version 2 of the License, or (at your + option) any later version. + + This program is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public + License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifndef KITINERARY_QIMAGEPUREBINARIZER_H +#define KITINERARY_QIMAGEPUREBINARIZER_H + +#include "config-kitinerary.h" +#ifdef HAVE_ZXING + +#include + +#include +#include + +namespace KItinerary { + +/** Binarizer of pure black/white barcode images. + * This bypasses the usually applied LuminanceSource and HybridBinarizer steps + * for input data from PDFs that don't need this. + */ +class QImagePureBinarizer : public ZXing::BinaryBitmap +{ +public: + explicit QImagePureBinarizer(const QImage &img); + ~QImagePureBinarizer(); + + int height() const override; + int width() const override; + bool isPureBarcode() const override; + + bool getBlackRow(int y, ZXing::BitArray &row) const override; + std::shared_ptr getBlackMatrix() const override; + + bool canCrop() const override; + bool canRotate() const override; + std::shared_ptr cropped(int left, int top, int width, int height) const override; + std::shared_ptr rotated(int degreeCW) const override; + +private: + QImage m_img; + mutable std::shared_ptr m_bitmap; +}; + +} + +#endif + +#endif // KITINERARY_QIMAGEPUREBINARIZER_H