diff --git a/CMakeLists.txt b/CMakeLists.txt index cb222d9..1d66d3b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,122 +1,117 @@ cmake_minimum_required(VERSION 3.5) set(PIM_VERSION "5.12.3") project(KItinerary VERSION ${PIM_VERSION}) set(CMAKE_CXX_STANDARD 14) set(KF5_MIN_VERSION "5.60.0") find_package(ECM ${KF5_MIN_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.11.0") find_package(Qt5 ${QT_REQUIRED_VERSION} REQUIRED COMPONENTS Test Gui Qml) find_package(KF5 ${KF5_MIN_VERSION} REQUIRED COMPONENTS I18n) set(KMIME_VERSION "5.12.2") set(KCALENDARCORE_LIB_VERSION "5.12.2") set(KCONTACTS_LIB_VERSION "5.12.2") 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/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") find_package(PhoneNumber OPTIONAL_COMPONENTS PhoneNumber QUIET) set_package_properties("PhoneNumber" PROPERTIES PURPOSE "Parsing and geo-coding of phone numbers.") 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() - set(CMAKE_REQUIRED_LIBRARIES Poppler::Core Qt5::Core) - check_cxx_source_compiles(" - #include - #include - int main() - { - GooString s; - QString val = QString::fromUtf8(s.c_str()); - return 0; - } - " HAVE_POPPLER_0_72) + if (${Poppler_VERSION} VERSION_GREATER 0.71) + set(HAVE_POPPLER_0_72 ON) + endif() + if (${Poppler_VERSION} VERSION_GREATER 0.81) + set(HAVE_POPPLER_0_82 ON) + endif() endif() if (TARGET ZXing::Core) set(HAVE_ZXING ON) endif() if (TARGET KF5::CalendarCore) set(HAVE_KCAL ON) endif() if (LIBXML2_FOUND) set(HAVE_LIBXML2 ON) endif() if (TARGET PhoneNumber::PhoneNumber) set(HAVE_PHONENUMBER ON) endif() add_definitions(-DTRANSLATION_DOMAIN=\"kitinerary\") add_definitions(-DQT_DISABLE_DEPRECATED_BEFORE=0x060000) add_definitions(-DQT_NO_FOREACH) 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_LOGGINGCATEGORIESDIR}) diff --git a/src/config-kitinerary.h.cmake b/src/config-kitinerary.h.cmake index b0bda20..6d3b156 100644 --- a/src/config-kitinerary.h.cmake +++ b/src/config-kitinerary.h.cmake @@ -1,34 +1,35 @@ /* 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_POPPLER_0_72 +#cmakedefine HAVE_POPPLER_0_82 #cmakedefine HAVE_ZXING #cmakedefine HAVE_KCAL #cmakedefine HAVE_LIBXML2 #cmakedefine HAVE_PHONENUMBER #endif diff --git a/src/pdf/pdfextractoroutputdevice.cpp b/src/pdf/pdfextractoroutputdevice.cpp index 2a06c82..0027cad 100644 --- a/src/pdf/pdfextractoroutputdevice.cpp +++ b/src/pdf/pdfextractoroutputdevice.cpp @@ -1,217 +1,217 @@ /* Copyright (C) 2019 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 "pdfextractoroutputdevice_p.h" #include "pdfimage.h" #include "pdfimage_p.h" #include "popplerutils_p.h" #include using namespace KItinerary; #ifdef HAVE_POPPLER PdfExtractorOutputDevice::PdfExtractorOutputDevice() : TextOutputDev(nullptr, false, 0, false, false) { } -void PdfExtractorOutputDevice::drawImage(GfxState* state, Object* ref, Stream* str, int width, int height, GfxImageColorMap* colorMap, bool interpolate, int* maskColors, bool inlineImg) +void PdfExtractorOutputDevice::drawImage(GfxState* state, Object* ref, Stream* str, int width, int height, GfxImageColorMap* colorMap, bool interpolate, PopplerMaskColors* maskColors, bool inlineImg) { Q_UNUSED(str); Q_UNUSED(interpolate); Q_UNUSED(maskColors); Q_UNUSED(inlineImg); if (!colorMap || !colorMap->isOk() || !ref || !ref->isRef()) { return; } QImage::Format format; if (colorMap->getColorSpace()->getMode() == csIndexed) { format = QImage::Format_RGB888; } else if (colorMap->getNumPixelComps() == 1 && (colorMap->getBits() >= 1 && colorMap->getBits() <= 8)) { format = QImage::Format_Grayscale8; } else if (colorMap->getNumPixelComps() == 3 && colorMap->getBits() == 8) { format = QImage::Format_RGB888; } else { return; } PdfImage pdfImg; pdfImg.d->m_refNum = ref->getRef().num; pdfImg.d->m_refGen = ref->getRef().gen; #ifdef HAVE_POPPLER_0_69 pdfImg.d->m_colorMap.reset(colorMap->copy()); #endif pdfImg.d->m_sourceHeight = height; pdfImg.d->m_sourceWidth = width; pdfImg.d->m_width = width; pdfImg.d->m_height = height; // deal with aspect-ratio changing scaling const auto sourceAspectRatio = (double)width / (double)height; const auto targetAspectRatio = state->getCTM()[0] / -state->getCTM()[3]; if (!qFuzzyCompare(sourceAspectRatio, targetAspectRatio) && qFuzzyIsNull(state->getCTM()[1]) && qFuzzyIsNull(state->getCTM()[2])) { if (targetAspectRatio > sourceAspectRatio) { pdfImg.d->m_width = width * targetAspectRatio / sourceAspectRatio; } else { pdfImg.d->m_height = height * sourceAspectRatio / targetAspectRatio; } } pdfImg.d->m_transform = PopplerUtils::currentTransform(state); pdfImg.d->m_format = format; m_images.push_back(pdfImg); } void PdfExtractorOutputDevice::saveState(GfxState *state) { Q_UNUSED(state); m_vectorOps.push_back(VectorOp{VectorOp::PushState, {}, {}}); } void PdfExtractorOutputDevice::restoreState(GfxState *state) { Q_UNUSED(state); if (m_vectorOps.empty()) { return; } const auto &lastOp = *(m_vectorOps.end() -1); if (lastOp.type == VectorOp::PushState) { m_vectorOps.resize(m_vectorOps.size() - 1); } else { m_vectorOps.push_back(VectorOp{VectorOp::PopState, {}, {}}); } } static bool isRelevantStroke(const QPen &pen) { return !qFuzzyCompare(pen.widthF(), 0.0) && pen.color() == Qt::black; } void PdfExtractorOutputDevice::stroke(GfxState *state) { const auto pen = PopplerUtils::currentPen(state); if (!isRelevantStroke(pen)) { return; } const auto path = PopplerUtils::convertPath(state->getPath(), Qt::WindingFill); const auto t = PopplerUtils::currentTransform(state); m_vectorOps.push_back(VectorOp{VectorOp::Path, t, {path, pen, QBrush()}}); } static bool isRelevantFill(const QBrush &brush) { return brush.color() == Qt::black; } void PdfExtractorOutputDevice::fill(GfxState *state) { const auto brush = PopplerUtils::currentBrush(state); if (!isRelevantFill(brush)) { return; } const auto path = PopplerUtils::convertPath(state->getPath(), Qt::WindingFill); const auto b = path.boundingRect(); if (b.width() == 0 || b.height() == 0) { return; } const auto t = PopplerUtils::currentTransform(state); m_vectorOps.push_back(VectorOp{VectorOp::Path, t, {path, QPen(), brush}}); } void PdfExtractorOutputDevice::eoFill(GfxState *state) { const auto brush = PopplerUtils::currentBrush(state); if (!isRelevantFill(brush)) { return; } const auto path = PopplerUtils::convertPath(state->getPath(), Qt::OddEvenFill); const auto b = path.boundingRect(); if (b.width() == 0 || b.height() == 0) { return; } const auto t = PopplerUtils::currentTransform(state); m_vectorOps.push_back(VectorOp{VectorOp::Path, t, {path, QPen(), brush}}); } void PdfExtractorOutputDevice::finalize() { // remove single state groups, then try to merge adjacents paths std::vector mergedOps; mergedOps.reserve(m_vectorOps.size()); for (auto it = m_vectorOps.begin(); it != m_vectorOps.end(); ++it) { if ((*it).type == VectorOp::PushState && std::distance(it, m_vectorOps.end()) >= 2 && (*(it + 1)).type == VectorOp::Path && (*(it + 2)).type == VectorOp::PopState) { ++it; mergedOps.push_back(*it); ++it; } else { mergedOps.push_back(*it); } } qDebug() << m_vectorOps.size() << mergedOps.size(); std::vector strokes; QTransform t; for (const auto &op : mergedOps) { if (op.type == VectorOp::Path) { if (t.isIdentity()) { t = op.transform; } if (t != op.transform) { qDebug() << "diffent transforms for strokes, not supported yet"; continue; } strokes.push_back(op.stroke); } else if (!strokes.empty()) { PdfVectorPicture pic; pic.setStrokes(std::move(strokes)); pic.setTransform(t); addVectorImage(pic); t = QTransform(); } } if (!strokes.empty()) { PdfVectorPicture pic; pic.setStrokes(std::move(strokes)); pic.setTransform(t); addVectorImage(pic); } } void PdfExtractorOutputDevice::addVectorImage(const PdfVectorPicture &pic) { if (pic.pathElementsCount() < 400) { // not complex enough for a barcode return; } PdfImage img; img.d->m_height = pic.height(); img.d->m_width = pic.width(); img.d->m_sourceHeight = pic.sourceHeight(); img.d->m_sourceWidth = pic.sourceWidth(); img.d->m_transform = pic.transform(); img.d->m_vectorPicture = pic; m_images.push_back(img); } #endif diff --git a/src/pdf/pdfextractoroutputdevice_p.h b/src/pdf/pdfextractoroutputdevice_p.h index 9241f9f..5d448d3 100644 --- a/src/pdf/pdfextractoroutputdevice_p.h +++ b/src/pdf/pdfextractoroutputdevice_p.h @@ -1,73 +1,74 @@ /* Copyright (C) 2019 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_PDFEXTRACTOROUTPUTDEVICE_P_H #define KITINERARY_PDFEXTRACTOROUTPUTDEVICE_P_H #include #include "pdfvectorpicture_p.h" +#include "popplertypes_p.h" #ifdef HAVE_POPPLER #include #endif #include namespace KItinerary { class PdfImage; class PdfVectorPicture; #ifdef HAVE_POPPLER class PdfExtractorOutputDevice : public TextOutputDev { public: explicit PdfExtractorOutputDevice(); // call once displaying has been completed void finalize(); bool needNonText() override { return true; } - void drawImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, bool interpolate, int *maskColors, bool inlineImg) override; + void drawImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, bool interpolate, PopplerMaskColors *maskColors, bool inlineImg) override; // operations used to detect vector barcodes void saveState(GfxState *state) override; void restoreState(GfxState *state) override; void stroke(GfxState *state) override; void fill(GfxState *state) override; void eoFill(GfxState *state) override; void addVectorImage(const PdfVectorPicture &pic); // extracted images std::vector m_images; // intermediate vector state struct VectorOp { enum { Path, PushState, PopState } type; QTransform transform; PdfVectorPicture::PathStroke stroke; }; std::vector m_vectorOps; }; #endif } #endif // KITINERARY_PDFEXTRACTOROUTPUTDEVICE_H diff --git a/src/pdf/popplertypes_p.h b/src/pdf/popplertypes_p.h new file mode 100644 index 0000000..f9d844a --- /dev/null +++ b/src/pdf/popplertypes_p.h @@ -0,0 +1,30 @@ +/* + Copyright (C) 2019 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_POPPLERTYPES_P_H +#define KITINERARY_POPPLERTYPES_P_H + +#include + +#ifdef HAVE_POPPLER_0_82 +using PopplerMaskColors = const int; +#else +using PopplerMaskColors = int; +#endif + +#endif // KITINERARY_POPPLERTYPES_P_H +