File indexing completed on 2024-04-21 05:54:06
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 , m_OCREngine(nullptr) 0019 { 0020 } 0021 0022 DocumentSaver::~DocumentSaver() 0023 { 0024 } 0025 0026 void DocumentSaver::setOCREngine(OCREngine *engine) 0027 { 0028 m_OCREngine = engine; 0029 } 0030 0031 void DocumentSaver::saveDocument(const QUrl &fileUrl, const SkanpageUtils::DocumentPages &document, const SkanpageUtils::FileType type, const QString &title) 0032 { 0033 if (fileUrl.isEmpty()) { 0034 Q_EMIT showUserMessage(SkanpageUtils::ErrorMessage, i18n("No file path given.")); 0035 return; 0036 } 0037 if (document.isEmpty()) { 0038 Q_EMIT showUserMessage(SkanpageUtils::ErrorMessage, i18n("Nothing to save.")); 0039 return; 0040 } 0041 if (!fileUrl.isLocalFile()) { 0042 Q_EMIT showUserMessage(SkanpageUtils::ErrorMessage, i18n("Saving to non-local directories is currently unsupported.")); 0043 return; 0044 } 0045 qCDebug(SKANPAGE_LOG) << QStringLiteral("Saving document to") << fileUrl; 0046 0047 const QFileInfo &fileInfo = QFileInfo(fileUrl.toLocalFile()); 0048 const QString &fileSuffix = fileInfo.suffix(); 0049 0050 qCDebug(SKANPAGE_LOG) << QStringLiteral("Selected file suffix is") << fileSuffix; 0051 0052 if (type == SkanpageUtils::OCRDocument) { 0053 m_OCREngine->InitForOCR(); 0054 saveSearchablePDF(fileUrl, document, title); 0055 } else if (fileSuffix == QLatin1String("pdf") || fileSuffix.isEmpty()) { 0056 savePDF(fileUrl, document, type); 0057 } else { 0058 saveImage(fileInfo, document, type); 0059 } 0060 } 0061 0062 void DocumentSaver::savePDF(const QUrl &fileUrl, const SkanpageUtils::DocumentPages &document, const SkanpageUtils::FileType type) 0063 { 0064 QFile file(fileUrl.toLocalFile()); 0065 bool ok = file.open(QIODevice::ReadWrite); 0066 if (!ok) { 0067 Q_EMIT showUserMessage(SkanpageUtils::ErrorMessage, i18nc("%1 is the error message", "An error ocurred while saving: %1.", file.errorString())); 0068 return; 0069 } 0070 QPdfWriter writer(&file); 0071 writer.setCreator(QStringLiteral("org.kde.skanpage")); 0072 QPainter painter; 0073 0074 for (int i = 0; i < document.count(); ++i) { 0075 printPage(writer, painter, document.at(i), i == 0); 0076 } 0077 0078 if (type == SkanpageUtils::EntireDocument || type == SkanpageUtils::PageSelection) { 0079 Q_EMIT showUserMessage(SkanpageUtils::InformationMessage, i18n("Document saved as PDF.")); 0080 } 0081 0082 if (type == SkanpageUtils::EntireDocument) { 0083 Q_EMIT fileSaved({fileUrl}, document); 0084 } else if (type == SkanpageUtils::SharingDocument) { 0085 Q_EMIT sharingFileSaved({fileUrl}); 0086 } 0087 } 0088 0089 void DocumentSaver::saveSearchablePDF(const QUrl &fileUrl, const SkanpageUtils::DocumentPages &document, const QString &title) 0090 { 0091 if (m_OCREngine == nullptr) { 0092 return; 0093 } 0094 0095 QFile file(fileUrl.toLocalFile()); 0096 bool ok = file.open(QIODevice::ReadWrite); 0097 if (!ok) { 0098 Q_EMIT showUserMessage(SkanpageUtils::ErrorMessage, i18nc("%1 is the error message", "An error ocurred while saving: %1.", file.errorString())); 0099 return; 0100 } 0101 QPdfWriter writer(&file); 0102 writer.setCreator(QStringLiteral("org.kde.skanpage")); 0103 writer.setTitle(title); 0104 QPainter painter; 0105 0106 for (int i = 0; i < document.count(); ++i) { 0107 printPage(writer, painter, document.at(i), i == 0); 0108 m_OCREngine->OCRPage(writer, painter, document.at(i)); 0109 } 0110 0111 Q_EMIT showUserMessage(SkanpageUtils::InformationMessage, i18n("Document saved with OCR as PDF.")); 0112 } 0113 0114 void DocumentSaver::printPage(QPdfWriter &writer, QPainter &painter, const SkanpageUtils::PageProperties &page, bool firstPage) 0115 { 0116 writer.setResolution(page.dpi); 0117 writer.setPageSize(page.pageSize); 0118 writer.setPageMargins(QMarginsF(0, 0, 0, 0)); 0119 int rotationAngle = page.rotationAngle; 0120 if (rotationAngle == 90 || rotationAngle == 270) { 0121 writer.setPageOrientation(QPageLayout::Landscape); 0122 } else { 0123 writer.setPageOrientation(QPageLayout::Portrait); 0124 } 0125 writer.newPage(); 0126 0127 QTransform transformation; 0128 if (rotationAngle != 0) { 0129 transformation.translate(writer.width()/2, writer.height()/2); 0130 transformation.rotate(rotationAngle); 0131 transformation.translate(-writer.width()/2, -writer.height()/2); 0132 } 0133 if (rotationAngle == 90 || rotationAngle == 270) { 0134 //strange that this is needed and Qt does not do this automatically 0135 transformation.translate((writer.width()-writer.height())/2, (writer.height()-writer.width())/2); 0136 } 0137 0138 if (firstPage) { 0139 painter.begin(&writer); 0140 } 0141 0142 painter.setTransform(transformation); 0143 QImage pageImage(page.temporaryFile->fileName()); 0144 painter.drawImage(QPoint(0, 0), pageImage, pageImage.rect()); 0145 } 0146 0147 void DocumentSaver::saveImage(const QFileInfo &fileInfo, const SkanpageUtils::DocumentPages &document, const SkanpageUtils::FileType type) 0148 { 0149 const int count = document.count(); 0150 QImage pageImage; 0151 QString fileName; 0152 QList<QUrl> fileUrls; 0153 0154 bool success = true; 0155 if (count == 1) { 0156 pageImage.load(document.at(0).temporaryFile->fileName()); 0157 fileName = fileInfo.absoluteFilePath(); 0158 const int rotationAngle = document.at(0).rotationAngle; 0159 if (rotationAngle != 0) { 0160 pageImage = pageImage.transformed(QTransform().rotate(rotationAngle)); 0161 } 0162 success = pageImage.save(fileName, fileInfo.suffix().toLocal8Bit().constData()); 0163 fileUrls.append(QUrl::fromLocalFile(fileName)); 0164 } else { 0165 fileUrls.reserve(count); 0166 for (int i = 0; i < count; ++i) { 0167 pageImage.load(document.at(i).temporaryFile->fileName()); 0168 const int rotationAngle = document.at(i).rotationAngle; 0169 if (rotationAngle != 0) { 0170 pageImage = pageImage.transformed(QTransform().rotate(rotationAngle)); 0171 } 0172 fileName = 0173 QStringLiteral("%1/%2%3.%4").arg(fileInfo.absolutePath(), fileInfo.baseName(), QLocale().toString(i).rightJustified(4, QLatin1Char('0')), fileInfo.suffix()); 0174 if(!pageImage.save(fileName, fileInfo.suffix().toLocal8Bit().constData())) { 0175 success = false; 0176 } 0177 fileUrls.append(QUrl::fromLocalFile(fileName)); 0178 } 0179 } 0180 0181 if (success) { 0182 if (type == SkanpageUtils::EntireDocument || type == SkanpageUtils::PageSelection) { 0183 Q_EMIT showUserMessage(SkanpageUtils::InformationMessage, i18n("Document saved as image.")); 0184 } 0185 if (type == SkanpageUtils::EntireDocument) { 0186 Q_EMIT fileSaved(fileUrls, document); 0187 } else if (type == SkanpageUtils::SharingDocument) { 0188 Q_EMIT sharingFileSaved(fileUrls); 0189 } 0190 } else { 0191 if (type == SkanpageUtils::EntireDocument || type == SkanpageUtils::PageSelection) { 0192 Q_EMIT showUserMessage(SkanpageUtils::ErrorMessage, i18n("Failed to save document as image.")); 0193 } 0194 } 0195 } 0196 0197 void DocumentSaver::saveNewPageTemporary(const int pageID, const QImage &image) 0198 { 0199 const QPageSize pageSize = QPageSize(QSizeF(image.width() * 1000.0 / image.dotsPerMeterX() , image.height() * 1000.0 / image.dotsPerMeterY()), QPageSize::Millimeter); 0200 const int dpi = qRound(image.dotsPerMeterX() / 1000.0 * 25.4); 0201 QTemporaryFile *tempImageFile = new QTemporaryFile(); 0202 tempImageFile->open(); 0203 if (image.save(tempImageFile, "PNG")) { 0204 qCDebug(SKANPAGE_LOG) << "Saved new image to temporary file."; 0205 } else { 0206 qCDebug(SKANPAGE_LOG) << "Saving new image to temporary file failed!"; 0207 Q_EMIT showUserMessage(SkanpageUtils::ErrorMessage, i18n("Failed to save image")); 0208 } 0209 qCDebug(SKANPAGE_LOG) << image << tempImageFile << "with page size" << pageSize << "and resolution of" << dpi << "dpi"; 0210 tempImageFile->close(); 0211 Q_EMIT pageTemporarilySaved(pageID, {std::shared_ptr<QTemporaryFile>(tempImageFile), pageSize, dpi}); 0212 } 0213 0214 #include "moc_DocumentSaver.cpp"