diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 34272af..1719240 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,218 +1,219 @@ set(KDE_INSTALL_INCLUDEDIR_PIM ${KDE_INSTALL_INCLUDEDIR}/KPim) add_subdirectory(cli) 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/creativework.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 generic/genericpdfextractor.cpp generic/genericpkpassextractor.cpp generic/genericuic918extractor.cpp generic/structureddataextractor.cpp jsapi/barcode.cpp jsapi/bitarray.cpp jsapi/context.cpp jsapi/jsonld.cpp knowledgedb/alphaid.cpp knowledgedb/airportdb.cpp knowledgedb/countrydb.cpp knowledgedb/iatacode.cpp knowledgedb/knowledgedb.cpp knowledgedb/timezonedb.cpp knowledgedb/trainstationdb.cpp pdf/pdfdocument.cpp pdf/pdfextractoroutputdevice.cpp pdf/pdfimage.cpp pdf/pdfvectorpicture.cpp + pdf/popplerglobalparams.cpp pdf/popplerutils.cpp uic9183/rct2ticket.cpp uic9183/uic9183block.cpp uic9183/uic9183parser.cpp uic9183/uic9183ticketlayout.cpp uic9183/vendor0080block.cpp barcodedecoder.cpp calendarhandler.cpp documentutil.cpp extractor.cpp extractorengine.cpp extractorfilter.cpp extractorinput.cpp extractorpostprocessor.cpp extractorrepository.cpp extractorutil.cpp extractorvalidator.cpp file.cpp flightpostprocessor.cpp htmldocument.cpp iatabcbpparser.cpp jsonlddocument.cpp jsonldimportfilter.cpp locationutil.cpp mergeutil.cpp qimagepurebinarizer.cpp sortutil.cpp stringutil.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) ecm_qt_declare_logging_category(kitinerary_lib_srcs HEADER compare-logging.h IDENTIFIER KItinerary::CompareLog CATEGORY_NAME org.kde.kitinerary.comparator) ecm_qt_declare_logging_category(kitinerary_lib_srcs HEADER validator-logging.h IDENTIFIER KItinerary::ValidatorLog CATEGORY_NAME org.kde.kitinerary.extractorValidator) 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::Archive 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) 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() if (HAVE_PHONENUMBER) target_link_libraries(KPimItinerary PRIVATE PhoneNumber::PhoneNumber) endif() ecm_generate_headers(KItinerary_FORWARDING_HEADERS HEADER_NAMES BarcodeDecoder CalendarHandler DocumentUtil Extractor ExtractorEngine ExtractorFilter ExtractorInput ExtractorPostprocessor ExtractorRepository File HtmlDocument IataBcbpParser JsonLdDocument LocationUtil MergeUtil SortUtil PREFIX KItinerary REQUIRED_HEADERS KItinerary_HEADERS ) ecm_generate_headers(KItinerary_KnowledgeDb_FORWARDING_HEADERS HEADER_NAMES AlphaId CountryDb KnowledgeDb PREFIX KItinerary REQUIRED_HEADERS KItinerary_KnowledgeDb_HEADERS RELATIVE knowledgedb ) ecm_generate_headers(KItinerary_Datatypes_FORWARDING_HEADERS HEADER_NAMES Action Brand BusTrip CreativeWork Datatypes Event Flight Organization Reservation RentalCar Person Place Taxi Ticket TrainTrip Visit PREFIX KItinerary REQUIRED_HEADERS KItinerary_Datatypes_HEADERS RELATIVE datatypes ) ecm_generate_headers(KItinerary_Pdf_FORWARDING_HEADERS HEADER_NAMES PdfDocument PdfImage PREFIX KItinerary REQUIRED_HEADERS KItinerary_Pdf_HEADERS RELATIVE pdf ) ecm_generate_headers(KItinerary_Uic9183_FORWARDING_HEADERS HEADER_NAMES Rct2Ticket Uic9183Block Uic9183Parser Uic9183TicketLayout Vendor0080Block PREFIX KItinerary REQUIRED_HEADERS KItinerary_Uic9183_HEADERS RELATIVE uic9183 ) install(TARGETS KPimItinerary EXPORT KPimItineraryTargets ${INSTALL_TARGETS_DEFAULT_ARGS}) install(FILES ${KItinerary_FORWARDING_HEADERS} ${KItinerary_KnowledgeDb_FORWARDING_HEADERS} ${KItinerary_Datatypes_FORWARDING_HEADERS} ${KItinerary_Pdf_FORWARDING_HEADERS} ${KItinerary_Uic9183_FORWARDING_HEADERS} DESTINATION ${KDE_INSTALL_INCLUDEDIR_PIM}/KItinerary ) install(FILES ${KItinerary_HEADERS} ${KItinerary_AirportDb_HEADERS} ${KItinerary_Datatypes_HEADERS} ${KItinerary_KnowledgeDb_HEADERS} ${KItinerary_Pdf_HEADERS} ${KItinerary_Uic9183_HEADERS} ${CMAKE_CURRENT_BINARY_DIR}/kitinerary_export.h DESTINATION ${KDE_INSTALL_INCLUDEDIR_PIM}/kitinerary ) if (NOT ANDROID) install(FILES application-vnd-kde-itinerary.xml DESTINATION ${XDG_MIME_INSTALL_DIR}) update_xdg_mimetypes(${XDG_MIME_INSTALL_DIR}) endif() diff --git a/src/pdf/pdfdocument.cpp b/src/pdf/pdfdocument.cpp index 6a2481f..39cdb8c 100644 --- a/src/pdf/pdfdocument.cpp +++ b/src/pdf/pdfdocument.cpp @@ -1,288 +1,288 @@ /* 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 "pdfdocument.h" #include "pdfdocument_p.h" #include "pdfextractoroutputdevice_p.h" #include "pdfimage_p.h" +#include "popplerglobalparams_p.h" #include "popplerutils_p.h" #include "logging.h" #include #include #include #ifdef HAVE_POPPLER -#include #include #include #include #endif #include using namespace KItinerary; void PdfPagePrivate::load() { if (m_loaded) { return; } #ifdef HAVE_POPPLER - QScopedValueRollback globalParamResetter(globalParams, PopplerUtils::globalParams()); + PopplerGlobalParams gp; PdfExtractorOutputDevice device; m_doc->m_popplerDoc->displayPageSlice(&device, m_pageNum + 1, 72, 72, 0, false, true, false, -1, -1, -1, -1); device.finalize(); const auto pageRect = m_doc->m_popplerDoc->getPage(m_pageNum + 1)->getCropBox(); std::unique_ptr s(device.getText(pageRect->x1, pageRect->y1, pageRect->x2, pageRect->y2)); #if KPOPPLER_VERSION >= QT_VERSION_CHECK(0, 72, 0) m_text = QString::fromUtf8(s->c_str()); #else m_text = QString::fromUtf8(s->getCString()); #endif m_images = std::move(device.m_images); for (auto it = m_images.begin(); it != m_images.end(); ++it) { (*it).d->m_page = this; } #endif m_loaded = true; } PdfPage::PdfPage() : d(new PdfPagePrivate) { } PdfPage::PdfPage(const PdfPage&) = default; PdfPage::~PdfPage() = default; PdfPage& PdfPage::operator=(const PdfPage&) = default; QString PdfPage::text() const { d->load(); return d->m_text; } #ifdef HAVE_POPPLER static double ratio(double begin, double end, double ratio) { return begin + (end - begin) * ratio; } #endif QString PdfPage::textInRect(double left, double top, double right, double bottom) const { #ifdef HAVE_POPPLER - QScopedValueRollback globalParamResetter(globalParams, PopplerUtils::globalParams()); + PopplerGlobalParams gp; TextOutputDev device(nullptr, false, 0, false, false); d->m_doc->m_popplerDoc->displayPageSlice(&device, d->m_pageNum + 1, 72, 72, 0, false, true, false, -1, -1, -1, -1); const auto pageRect = d->m_doc->m_popplerDoc->getPage(d->m_pageNum + 1)->getCropBox(); std::unique_ptr s(device.getText(ratio(pageRect->x1, pageRect->x2, left), ratio(pageRect->y1, pageRect->y2, top), ratio(pageRect->x1, pageRect->x2, right), ratio(pageRect->y1, pageRect->y2, bottom))); #if KPOPPLER_VERSION >= QT_VERSION_CHECK(0, 72, 0) return QString::fromUtf8(s->c_str()); #else return QString::fromUtf8(s->getCString()); #endif #else Q_UNUSED(left); Q_UNUSED(top); Q_UNUSED(right); Q_UNUSED(bottom); return {}; #endif } int PdfPage::imageCount() const { d->load(); return d->m_images.size(); } PdfImage PdfPage::image(int index) const { d->load(); return d->m_images[index]; } QVariantList PdfPage::imagesVariant() const { d->load(); QVariantList l; l.reserve(imageCount()); std::for_each(d->m_images.begin(), d->m_images.end(), [&l](const PdfImage& img) { l.push_back(QVariant::fromValue(img)); }); return l; } QVariantList PdfPage::imagesInRect(double left, double top, double right, double bottom) const { d->load(); QVariantList l; #ifdef HAVE_POPPLER - QScopedValueRollback globalParamResetter(globalParams, PopplerUtils::globalParams()); + PopplerGlobalParams gp; const auto pageRect = d->m_doc->m_popplerDoc->getPage(d->m_pageNum + 1)->getCropBox(); for (const auto &img : d->m_images) { if ((img.d->m_transform.dx() >= ratio(pageRect->x1, pageRect->x2, left) && img.d->m_transform.dx() <= ratio(pageRect->x1, pageRect->x2, right)) && (img.d->m_transform.dy() >= ratio(pageRect->y1, pageRect->y2, top) && img.d->m_transform.dy() <= ratio(pageRect->y1, pageRect->y2, bottom))) { l.push_back(QVariant::fromValue(img)); } } #else Q_UNUSED(left); Q_UNUSED(top); Q_UNUSED(right); Q_UNUSED(bottom); #endif return l; } PdfDocument::PdfDocument(QObject *parent) : QObject(parent) , d(new PdfDocumentPrivate) { } PdfDocument::~PdfDocument() = default; QString PdfDocument::text() const { QString text; std::for_each(d->m_pages.begin(), d->m_pages.end(), [&text](const PdfPage &p) { text += p.text(); }); return text; } int PdfDocument::pageCount() const { #ifdef HAVE_POPPLER return d->m_popplerDoc->getNumPages(); #else return 0; #endif } PdfPage PdfDocument::page(int index) const { return d->m_pages[index]; } int PdfDocument::fileSize() const { return d->m_pdfData.size(); } static QDateTime parsePdfDateTime(const char *str) { int year, month, day, hour, min, sec, tzHours, tzMins; char tz; if (!parseDateString(str, &year, &month, &day, &hour, &min, &sec, &tz, &tzHours, &tzMins)) { return {}; } QDate date(year, month, day); QTime time(hour, min, sec); if (!date.isValid() || !time.isValid()) { return {}; } int offset = tzHours * 3600 + tzMins * 60; if (tz == '+') { return QDateTime(date, time, Qt::OffsetFromUTC, offset); } else if (tz == '-') { return QDateTime(date, time, Qt::OffsetFromUTC, -offset); } return QDateTime(date, time, Qt::UTC); } QDateTime PdfDocument::creationTime() const { std::unique_ptr dt(d->m_popplerDoc->getDocInfoCreatDate()); if (!dt) { return {}; } #if KPOPPLER_VERSION >= QT_VERSION_CHECK(0, 72, 0) return parsePdfDateTime(dt->c_str()); #else return parsePdfDateTime(dt->getCString()); #endif } QDateTime PdfDocument::modificationTime() const { std::unique_ptr dt(d->m_popplerDoc->getDocInfoModDate()); if (!dt) { return {}; } #if KPOPPLER_VERSION >= QT_VERSION_CHECK(0, 72, 0) return parsePdfDateTime(dt->c_str()); #else return parsePdfDateTime(dt->getCString()); #endif } QVariantList PdfDocument::pagesVariant() const { QVariantList l; l.reserve(pageCount()); std::for_each(d->m_pages.begin(), d->m_pages.end(), [&l](const PdfPage& p) { l.push_back(QVariant::fromValue(p)); }); return l; } PdfDocument* PdfDocument::fromData(const QByteArray &data, QObject *parent) { #ifdef HAVE_POPPLER - QScopedValueRollback globalParamResetter(globalParams, PopplerUtils::globalParams()); + PopplerGlobalParams gp; std::unique_ptr doc(new PdfDocument(parent)); doc->d->m_pdfData = data; // PDFDoc takes ownership of stream #if KPOPPLER_VERSION >= QT_VERSION_CHECK(0, 58, 0) auto stream = new MemStream(const_cast(doc->d->m_pdfData.constData()), 0, doc->d->m_pdfData.size(), Object()); #else Object obj; obj.initNull(); auto stream = new MemStream(const_cast(doc->d->m_pdfData.constData()), 0, doc->d->m_pdfData.size(), &obj); #endif std::unique_ptr popplerDoc(new PDFDoc(stream, nullptr, nullptr)); if (!popplerDoc->isOk()) { qCWarning(Log) << "Got invalid PDF document!" << popplerDoc->getErrorCode(); return nullptr; } doc->d->m_pages.reserve(popplerDoc->getNumPages()); for (int i = 0; i < popplerDoc->getNumPages(); ++i) { PdfPage page; page.d->m_pageNum = i; page.d->m_doc = doc->d.get(); doc->d->m_pages.push_back(page); } doc->d->m_popplerDoc = std::move(popplerDoc); return doc.release(); #else Q_UNUSED(data); Q_UNUSED(parent); return nullptr; #endif } diff --git a/src/pdf/pdfimage.cpp b/src/pdf/pdfimage.cpp index 4fa9016..2cfcc32 100644 --- a/src/pdf/pdfimage.cpp +++ b/src/pdf/pdfimage.cpp @@ -1,235 +1,236 @@ /* 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 "pdfimage.h" #include "pdfimage_p.h" #include "pdfdocument_p.h" +#include "popplerglobalparams_p.h" #include "popplerutils_p.h" #include #include #ifdef HAVE_POPPLER #include #include #include #include #include #endif using namespace KItinerary; #ifdef HAVE_POPPLER // legacy image loading #if KPOPPLER_VERSION < QT_VERSION_CHECK(0, 69, 0) namespace KItinerary { class ImageLoaderOutputDevice : public OutputDev { public: ImageLoaderOutputDevice(PdfImagePrivate *dd); bool interpretType3Chars() override { return false; } bool needNonText() override { return true; } bool upsideDown() override { return false; } bool useDrawChar() override { return false; } void drawImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, bool interpolate, int *maskColors, bool inlineImg) override; QImage image() const { return m_image; } private: PdfImagePrivate *d; QImage m_image; }; ImageLoaderOutputDevice::ImageLoaderOutputDevice(PdfImagePrivate* dd) : d(dd) { } void ImageLoaderOutputDevice::drawImage(GfxState *state, Object *ref, Stream *str, int width, int height, GfxImageColorMap *colorMap, bool interpolate, int *maskColors, bool inlineImg) { Q_UNUSED(state); Q_UNUSED(height); Q_UNUSED(width); Q_UNUSED(interpolate); Q_UNUSED(maskColors); Q_UNUSED(inlineImg); if (!colorMap || !colorMap->isOk() || !ref) { return; } if (ref->isRef() && d->m_refNum != ref->getRef().num) { return; } m_image = d->load(str, colorMap); } } #endif static inline bool isColor(GfxRGB rgb) { enum { Threshold = 72 * 256 }; // GfxComp is stored as color value * 255 // barcode images for SNCF and Renfe for example are anti-aliased, so we cannot simply filter for black or white // KLM/AF use tinted barcodes, so checking for R = G = B doesn't help either return std::abs(rgb.r - rgb.g) > Threshold || std::abs(rgb.r - rgb.b) > Threshold || std::abs(rgb.g - rgb.b) > Threshold; } QImage PdfImagePrivate::load(Stream* str, GfxImageColorMap* colorMap) { auto img = QImage(m_sourceWidth, m_sourceHeight, (m_loadingHints & PdfImage::ConvertToGrayscaleHint) ? QImage::Format_Grayscale8 : m_format); const auto bytesPerPixel = colorMap->getNumPixelComps(); std::unique_ptr imgStream(new ImageStream(str, m_sourceWidth, bytesPerPixel, colorMap->getBits())); imgStream->reset(); switch (m_format) { case QImage::Format_RGB888: for (int i = 0; i < m_sourceHeight; ++i) { const auto row = imgStream->getLine(); auto imgData = img.scanLine(i); GfxRGB rgb; for (int j = 0; j < m_sourceWidth; ++j) { colorMap->getRGB(row + (j * bytesPerPixel), &rgb); if ((m_loadingHints & PdfImage::AbortOnColorHint) && isColor(rgb)) { return {}; } if ((m_loadingHints & PdfImage::ConvertToGrayscaleHint)) { *imgData++ = colToByte(rgb.g); // technically not correct but good enough } else { *imgData++ = colToByte(rgb.r); *imgData++ = colToByte(rgb.g); *imgData++ = colToByte(rgb.b); } } } break; case QImage::Format_Grayscale8: for (int i = 0; i < m_sourceHeight; ++i) { const auto row = imgStream->getLine(); auto imgData = img.scanLine(i); GfxGray gray; for (int j = 0; j < m_sourceWidth; ++j) { colorMap->getGray(row + j, &gray); *imgData++ = colToByte(gray); } } break; default: break; } imgStream->close(); m_page->m_doc->m_imageData[m_refNum] = img; return img; } #endif QImage PdfImagePrivate::load() { const auto it = m_page->m_doc->m_imageData.find(m_refNum); if (it != m_page->m_doc->m_imageData.end()) { return (*it).second; } #ifdef HAVE_POPPLER - QScopedValueRollback globalParamResetter(globalParams, PopplerUtils::globalParams()); + PopplerGlobalParams gp; #if KPOPPLER_VERSION >= QT_VERSION_CHECK(0, 69, 0) const auto xref = m_page->m_doc->m_popplerDoc->getXRef(); const auto obj = xref->fetch(m_refNum, m_refGen); return load(obj.getStream(), m_colorMap.get()); #else std::unique_ptr device(new ImageLoaderOutputDevice(this)); m_page->m_doc->m_popplerDoc->displayPageSlice(device.get(), m_page->m_pageNum + 1, 72, 72, 0, false, true, false, -1, -1, -1, -1); return device->image(); #endif #else return {}; #endif } PdfImage::PdfImage() : d(new PdfImagePrivate) { } PdfImage::PdfImage(const PdfImage&) = default; PdfImage::~PdfImage() = default; PdfImage& PdfImage::operator=(const PdfImage&) = default; int PdfImage::height() const { if (d->m_format == QImage::Format_Invalid) { return d->m_height; } return d->m_transform.map(QRectF(0, 0, 1, -1)).boundingRect().height(); } int PdfImage::width() const { if (d->m_format == QImage::Format_Invalid) { return d->m_width; } return d->m_transform.map(QRectF(0, 0, 1, -1)).boundingRect().width(); } int PdfImage::sourceHeight() const { return d->m_sourceHeight; } int PdfImage::sourceWidth() const { return d->m_sourceWidth; } QTransform PdfImage::transform() const { return d->m_transform; } void PdfImage::setLoadingHints(LoadingHints hints) { d->m_loadingHints = hints; } QImage PdfImage::image() const { if (d->m_format == QImage::Format_Invalid) { return d->m_vectorPicture.renderToImage(); } const auto img = d->load(); if (d->m_width != d->m_sourceWidth || d->m_height != d->m_sourceHeight) { return img.scaled(d->m_width, d->m_height); } return img; } bool PdfImage::hasObjectId() const { return d->m_refNum >= 0; } int PdfImage::objectId() const { return d->m_refNum; } diff --git a/src/pdf/popplerglobalparams.cpp b/src/pdf/popplerglobalparams.cpp new file mode 100644 index 0000000..85ef935 --- /dev/null +++ b/src/pdf/popplerglobalparams.cpp @@ -0,0 +1,55 @@ +/* + 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 "config-kitinerary.h" +#include "popplerglobalparams_p.h" + +#include + +#ifdef HAVE_POPPLER +#include + +using namespace KItinerary; + +static std::unique_ptr s_globalParams; + +PopplerGlobalParams::PopplerGlobalParams() +{ + if (!s_globalParams) { + s_globalParams.reset(new GlobalParams); + } + +#if KPOPPLER_VERSION <= QT_VERSION_CHECK(0, 82, 0) + m_prev.reset(globalParams); + globalParams = s_globalParams.get(); +#else + std::swap(globalParams, m_prev); + std::swap(s_globalParams, globalParams); +#endif +} + +PopplerGlobalParams::~PopplerGlobalParams() +{ +#if KPOPPLER_VERSION <= QT_VERSION_CHECK(0, 82, 0) + globalParams = m_prev.release(); +#else + std::swap(s_globalParams, globalParams); + std::swap(globalParams, m_prev); +#endif +} + +#endif diff --git a/src/pdf/popplerutils_p.h b/src/pdf/popplerglobalparams_p.h similarity index 52% copy from src/pdf/popplerutils_p.h copy to src/pdf/popplerglobalparams_p.h index 1f5cf13..01bd90e 100644 --- a/src/pdf/popplerutils_p.h +++ b/src/pdf/popplerglobalparams_p.h @@ -1,52 +1,40 @@ /* 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_POPPLERUTILS_P_H -#define KITINERARY_POPPLERUTILS_P_H +#ifndef KITINERARY_POPPLERGLOBALPARAMS_H +#define KITINERARY_POPPLERGLOBALPARAMS_H -#include +#include -class GfxPath; -class GfxState; class GlobalParams; -class QBrush; -class QPainterPath; -class QPen; -class QTransform; - namespace KItinerary { -/** Utilities for interacting with Poppler. */ -namespace PopplerUtils +/** RAII wrapper of the globalParams object. */ +class PopplerGlobalParams { - /** Returns the current pen. */ - QPen currentPen(GfxState *state); - /** Retruns the current brush. */ - QBrush currentBrush(GfxState *state); - /** Returns the current transformation matrix. */ - QTransform currentTransform(GfxState *state); - - /** Convets a Poppler path into a Qt path. */ - QPainterPath convertPath(GfxPath *path, Qt::FillRule fillRule); +public: + PopplerGlobalParams(); + ~PopplerGlobalParams(); - GlobalParams* globalParams(); -} +private: + std::unique_ptr m_prev; +}; } -#endif // KITINERARY_POPPLERUTILS_P_H +#endif // KITINERARY_POPPLERGLOBALPARAMS_H diff --git a/src/pdf/popplerutils.cpp b/src/pdf/popplerutils.cpp index 4d69750..943f055 100644 --- a/src/pdf/popplerutils.cpp +++ b/src/pdf/popplerutils.cpp @@ -1,119 +1,109 @@ /* 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 #include "popplerutils_p.h" #include #include #include #include #ifdef HAVE_POPPLER #include -#include using namespace KItinerary; QPen PopplerUtils::currentPen(GfxState *state) { QPen pen; pen.setStyle(Qt::SolidLine); pen.setWidthF(state->getLineWidth()); GfxRGB rgb; state->getStrokeRGB(&rgb); QColor c; c.setRgbF(colToDbl(rgb.r), colToDbl(rgb.g), colToDbl(rgb.b), 1.0f); pen.setColor(c); switch (state->getLineCap()) { case 0: pen.setCapStyle(Qt::FlatCap); break; case 1: pen.setCapStyle(Qt::RoundCap); break; case 2: pen.setCapStyle(Qt::SquareCap); break; } switch (state->getLineJoin()) { case 0: pen.setJoinStyle(Qt::SvgMiterJoin); break; case 1: pen.setJoinStyle(Qt::RoundJoin); break; case 2: pen.setJoinStyle(Qt::BevelJoin); break; } pen.setMiterLimit(state->getMiterLimit()); return pen; } QBrush PopplerUtils::currentBrush(GfxState* state) { QBrush brush; brush.setStyle(Qt::SolidPattern); GfxRGB rgb; state->getFillRGB(&rgb); QColor c; c.setRgbF(colToDbl(rgb.r), colToDbl(rgb.g), colToDbl(rgb.b), 1.0f); brush.setColor(c); return brush; } QTransform KItinerary::PopplerUtils::currentTransform(GfxState *state) { const auto ctm = state->getCTM(); return QTransform(ctm[0], ctm[1], ctm[2], ctm[3], ctm[4], ctm[5]); } QPainterPath PopplerUtils::convertPath(GfxPath *path, Qt::FillRule fillRule) { QPainterPath qpp; qpp.setFillRule(fillRule); for (auto i = 0; i < path->getNumSubpaths(); ++i) { const auto subpath = path->getSubpath(i); if (subpath->getNumPoints() > 0) { qpp.moveTo(subpath->getX(0), subpath->getY(0)); for (auto j = 1;j < subpath->getNumPoints();) { if (subpath->getCurve(j)) { qpp.cubicTo(subpath->getX(j), subpath->getY(j), subpath->getX(j+1), subpath->getY(j+1), subpath->getX(j+2), subpath->getY(j+2)); j += 3; } else { qpp.lineTo(subpath->getX(j), subpath->getY(j)); ++j; } } if (subpath->isClosed()) { qpp.closeSubpath(); } } } return qpp; } -GlobalParams* PopplerUtils::globalParams() -{ - static std::unique_ptr s_globalParams; - if (!s_globalParams) { - s_globalParams.reset(new GlobalParams); - } - return s_globalParams.get(); -} - #endif diff --git a/src/pdf/popplerutils_p.h b/src/pdf/popplerutils_p.h index 1f5cf13..e3e819d 100644 --- a/src/pdf/popplerutils_p.h +++ b/src/pdf/popplerutils_p.h @@ -1,52 +1,49 @@ /* 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_POPPLERUTILS_P_H #define KITINERARY_POPPLERUTILS_P_H #include class GfxPath; class GfxState; -class GlobalParams; class QBrush; class QPainterPath; class QPen; class QTransform; namespace KItinerary { /** Utilities for interacting with Poppler. */ namespace PopplerUtils { /** Returns the current pen. */ QPen currentPen(GfxState *state); /** Retruns the current brush. */ QBrush currentBrush(GfxState *state); /** Returns the current transformation matrix. */ QTransform currentTransform(GfxState *state); /** Convets a Poppler path into a Qt path. */ QPainterPath convertPath(GfxPath *path, Qt::FillRule fillRule); - - GlobalParams* globalParams(); } } #endif // KITINERARY_POPPLERUTILS_P_H