Warning, file /utilities/skanpage/src/DocumentSaver.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /**
0002  * SPDX-FileCopyrightText: 2021 by Alexander Stippich <a.stippich@gmx.net>
0003  *
0004  * SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0005  */
0006 
0007 #include "DocumentSaver.h"
0008 
0009 #include <QTransform>
0010 
0011 #include <KLocalizedString>
0012 
0013 #include "skanpage_debug.h"
0014 #include "OCREngine.h"
0015 
0016 DocumentSaver::DocumentSaver(QObject *parent)
0017     : QObject(parent)
0018 {
0019 }
0020 
0021 DocumentSaver::~DocumentSaver()
0022 {
0023 }
0024 
0025 void DocumentSaver::setOCREngine(OCREngine *engine)
0026 {
0027     m_OCREngine = engine;
0028 }
0029 
0030 void DocumentSaver::saveDocument(const QUrl &fileUrl, const SkanpageUtils::DocumentPages &document, const SkanpageUtils::FileType type, const QString &title)
0031 {
0032     if (fileUrl.isEmpty()) {
0033         Q_EMIT showUserMessage(SkanpageUtils::ErrorMessage, i18n("No file path given."));
0034         return;
0035     }
0036     if (document.isEmpty()) {
0037         Q_EMIT showUserMessage(SkanpageUtils::ErrorMessage, i18n("Nothing to save."));
0038         return;
0039     }
0040     qCDebug(SKANPAGE_LOG) << QStringLiteral("Saving document to") << fileUrl;
0041 
0042     const QFileInfo &fileInfo = QFileInfo(fileUrl.toLocalFile());
0043     const QString &fileSuffix = fileInfo.suffix();
0044 
0045     qCDebug(SKANPAGE_LOG) << QStringLiteral("Selected file suffix is") << fileSuffix;
0046 
0047     if (type == SkanpageUtils::OCRDocument) {
0048         m_OCREngine->InitForOCR();
0049         saveSearchablePDF(fileUrl, document, title);
0050     } else if (fileSuffix == QLatin1String("pdf") || fileSuffix.isEmpty()) {
0051         savePDF(fileUrl, document, type);
0052     } else {
0053         saveImage(fileInfo, document, type);
0054     }
0055 }
0056 
0057 void DocumentSaver::savePDF(const QUrl &fileUrl, const SkanpageUtils::DocumentPages &document, const SkanpageUtils::FileType type)
0058 {
0059     QPdfWriter writer(fileUrl.toLocalFile());
0060     writer.setCreator(QStringLiteral("org.kde.skanpage"));
0061     QPainter painter;
0062 
0063     for (int i = 0; i < document.count(); ++i) {
0064         printPage(writer, painter, document.at(i), i == 0);
0065     }
0066 
0067     if (type == SkanpageUtils::EntireDocument || type == SkanpageUtils::PageSelection) {
0068         Q_EMIT showUserMessage(SkanpageUtils::InformationMessage, i18n("Document saved as PDF."));
0069     }
0070 
0071     if (type == SkanpageUtils::EntireDocument) {
0072         Q_EMIT fileSaved({fileUrl}, document);
0073     } else if (type == SkanpageUtils::SharingDocument) {
0074         Q_EMIT sharingFileSaved({fileUrl});
0075     }
0076 }
0077 
0078 void DocumentSaver::saveSearchablePDF(const QUrl &fileUrl, const SkanpageUtils::DocumentPages &document, const QString &title)
0079 {
0080     if (m_OCREngine == nullptr) {
0081         return;
0082     }
0083     
0084     QPdfWriter writer(fileUrl.toLocalFile());
0085     writer.setCreator(QStringLiteral("org.kde.skanpage"));
0086     writer.setTitle(title);
0087     QPainter painter;
0088     
0089     for (int i = 0; i < document.count(); ++i) {
0090         printPage(writer, painter, document.at(i), i == 0);
0091         m_OCREngine->OCRPage(writer, painter, document.at(i));
0092     }
0093     
0094     Q_EMIT showUserMessage(SkanpageUtils::InformationMessage, i18n("Document saved with OCR as PDF."));
0095 }
0096 
0097 void DocumentSaver::printPage(QPdfWriter &writer, QPainter &painter, const SkanpageUtils::PageProperties &page, bool firstPage)
0098 {
0099     writer.setResolution(page.dpi);
0100     writer.setPageSize(page.pageSize);
0101     writer.setPageMargins(QMarginsF(0, 0, 0, 0));
0102     int rotationAngle = page.rotationAngle;
0103     if (rotationAngle == 90 || rotationAngle == 270) {
0104         writer.setPageOrientation(QPageLayout::Landscape);
0105     } else {
0106         writer.setPageOrientation(QPageLayout::Portrait);
0107     }
0108     writer.newPage();
0109 
0110     QTransform transformation;
0111     if (rotationAngle != 0) {
0112         transformation.translate(writer.width()/2, writer.height()/2);
0113         transformation.rotate(rotationAngle);
0114         transformation.translate(-writer.width()/2, -writer.height()/2);
0115     }
0116     if (rotationAngle == 90 || rotationAngle == 270) {
0117         //strange that this is needed and Qt does not do this automatically
0118         transformation.translate((writer.width()-writer.height())/2, (writer.height()-writer.width())/2);
0119     }
0120 
0121     if (firstPage) {
0122         painter.begin(&writer);
0123     }
0124 
0125     painter.setTransform(transformation);
0126     QImage pageImage(page.temporaryFile->fileName());
0127     painter.drawImage(QPoint(0, 0), pageImage, pageImage.rect());
0128 }
0129 
0130 void DocumentSaver::saveImage(const QFileInfo &fileInfo, const SkanpageUtils::DocumentPages &document, const SkanpageUtils::FileType type)
0131 {
0132     const int count = document.count();
0133     QImage pageImage;
0134     QString fileName;
0135     QList<QUrl> fileUrls;
0136 
0137     bool success = true;
0138     if (count == 1) {
0139         pageImage.load(document.at(0).temporaryFile->fileName());
0140         fileName = fileInfo.absoluteFilePath();
0141         const int rotationAngle = document.at(0).rotationAngle;
0142         if (rotationAngle != 0) {
0143             pageImage = pageImage.transformed(QTransform().rotate(rotationAngle));
0144         }
0145         success = pageImage.save(fileName, fileInfo.suffix().toLocal8Bit().constData());
0146         fileUrls.append(QUrl::fromLocalFile(fileName));
0147     } else {
0148         fileUrls.reserve(count);
0149         for (int i = 0; i < count; ++i) {
0150             pageImage.load(document.at(i).temporaryFile->fileName());
0151             const int rotationAngle = document.at(i).rotationAngle;
0152             if (rotationAngle != 0) {
0153                 pageImage = pageImage.transformed(QTransform().rotate(rotationAngle));
0154             }
0155             fileName =
0156                 QStringLiteral("%1/%2%3.%4").arg(fileInfo.absolutePath(), fileInfo.baseName(), QLocale().toString(i).rightJustified(4, QLatin1Char('0')), fileInfo.suffix());
0157             if(!pageImage.save(fileName, fileInfo.suffix().toLocal8Bit().constData())) {
0158                 success = false;
0159             }
0160             fileUrls.append(QUrl::fromLocalFile(fileName));
0161         }
0162     }
0163 
0164     if (success) {
0165         if (type == SkanpageUtils::EntireDocument || type == SkanpageUtils::PageSelection) {
0166             Q_EMIT showUserMessage(SkanpageUtils::InformationMessage, i18n("Document saved as image."));
0167         }
0168         if (type == SkanpageUtils::EntireDocument) {
0169             Q_EMIT fileSaved(fileUrls, document);
0170         } else if (type == SkanpageUtils::SharingDocument) {
0171             Q_EMIT sharingFileSaved(fileUrls);
0172         }
0173     } else {
0174         if (type == SkanpageUtils::EntireDocument || type == SkanpageUtils::PageSelection) {
0175             Q_EMIT showUserMessage(SkanpageUtils::ErrorMessage, i18n("Failed to save document as image."));
0176         }
0177     }
0178 }
0179 
0180 void DocumentSaver::saveNewPageTemporary(const int pageID, const QImage &image)
0181 {
0182     const QPageSize pageSize = QPageSize(QSizeF(image.width() * 1000.0 / image.dotsPerMeterX() , image.height() * 1000.0 / image.dotsPerMeterY()), QPageSize::Millimeter);
0183     const int dpi = qRound(image.dotsPerMeterX() / 1000.0 * 25.4);
0184     QTemporaryFile *tempImageFile = new QTemporaryFile();
0185     tempImageFile->open();
0186     if (image.save(tempImageFile, "PNG")) {
0187         qCDebug(SKANPAGE_LOG) << "Saved new image to temporary file.";
0188     } else {
0189         qCDebug(SKANPAGE_LOG) << "Saving new image to temporary file failed!";
0190         Q_EMIT showUserMessage(SkanpageUtils::ErrorMessage, i18n("Failed to save image"));
0191     }
0192     qCDebug(SKANPAGE_LOG) << image << tempImageFile << "with page size" << pageSize << "and resolution of" << dpi << "dpi";
0193     tempImageFile->close();
0194     Q_EMIT pageTemporarilySaved(pageID, {std::shared_ptr<QTemporaryFile>(tempImageFile), pageSize, dpi});
0195 }