From 4e8692c4314554fdbcae1e6b2fd1f68a1e339b48 Mon Sep 17 00:00:00 2001 From: Anton Thomasson Date: Sat, 12 Jun 2021 12:45:58 +0200 Subject: [PATCH] Add plaintext support --- qml/components/DocumentFilter.notqml | 10 ++ qml/components/DocumentFilterOffice.notqml | 10 ++ qml/pages/FirstPage.qml | 13 +- qml/pages/utils.js | 17 +- src/convertworker.cpp | 172 ++++++++++++++++++++- src/convertworker.h | 4 + src/ippprinter.cpp | 8 +- src/ippprinter.h | 4 + src/mimer.cpp | 2 + src/mimer.h | 4 + translations/harbour-seaprint-de.ts | 4 + translations/harbour-seaprint-es.ts | 4 + translations/harbour-seaprint-fr.ts | 4 + translations/harbour-seaprint-nl.ts | 4 + translations/harbour-seaprint-pl.ts | 4 + translations/harbour-seaprint-zh_CN.ts | 4 + translations/harbour-seaprint.ts | 4 + 17 files changed, 267 insertions(+), 5 deletions(-) diff --git a/qml/components/DocumentFilter.notqml b/qml/components/DocumentFilter.notqml index 91d30be..a78967a 100644 --- a/qml/components/DocumentFilter.notqml +++ b/qml/components/DocumentFilter.notqml @@ -12,6 +12,11 @@ GalleryFilterUnion { value: ".ps" } + GalleryEndsWithFilter { + property: "fileName" + value: ".txt" + } + GalleryEndsWithFilter { property: "fileName" value: ".PDF" @@ -22,4 +27,9 @@ GalleryFilterUnion { value: ".PS" } + GalleryEndsWithFilter { + property: "fileName" + value: ".TXT" + } + } diff --git a/qml/components/DocumentFilterOffice.notqml b/qml/components/DocumentFilterOffice.notqml index 302fd8c..b40ff96 100644 --- a/qml/components/DocumentFilterOffice.notqml +++ b/qml/components/DocumentFilterOffice.notqml @@ -12,6 +12,11 @@ GalleryFilterUnion { value: ".ps" } + GalleryEndsWithFilter { + property: "fileName" + value: ".txt" + } + GalleryEndsWithFilter { property: "fileName" value: ".PDF" @@ -22,6 +27,11 @@ GalleryFilterUnion { value: ".PS" } + GalleryEndsWithFilter { + property: "fileName" + value: ".TXT" + } + GalleryEndsWithFilter { property: "fileName" value: ".odt" diff --git a/qml/pages/FirstPage.qml b/qml/pages/FirstPage.qml index 103856c..2c7f46b 100644 --- a/qml/pages/FirstPage.qml +++ b/qml/pages/FirstPage.qml @@ -276,7 +276,8 @@ Page { spacing: Theme.paddingMedium Label { id: format_unsupported_label - visible: !supported_formats.pdf && !supported_formats.postscript && !supported_formats.office && !supported_formats.images + visible: !supported_formats.pdf && !supported_formats.postscript && !supported_formats.plaintext + && !supported_formats.office && !supported_formats.images color: "red" font.pixelSize: Theme.fontSizeExtraSmall text: qsTr("No compatible formats supported") @@ -299,6 +300,14 @@ Page { source: "image://theme/icon-m-file-other" } + HighlightImage { + height: Theme.itemSizeExtraSmall/2 + width: Theme.itemSizeExtraSmall/2 + visible: supported_formats.plaintext + highlightColor: "red" + highlighted: !(selectedFile == "" || canPrint) + source: "image://theme/icon-m-file-document" + } HighlightImage { height: Theme.itemSizeExtraSmall/2 width: Theme.itemSizeExtraSmall/2 @@ -441,7 +450,7 @@ Page { onSelectedContentPropertiesChanged: { var mimeType = Mimer.get_type(selectedContentProperties.filePath) - if(mimeType == "application/pdf" || mimeType == "application/postscript" || Mimer.isOffice(mimeType)) + if(mimeType == Mimer.PDF || mimeType == Mimer.Postscript || mimeType == Mimer.Plaintext || Mimer.isOffice(mimeType)) { page.selectedFile = selectedContentProperties.filePath page.selectedFileType = mimeType diff --git a/qml/pages/utils.js b/qml/pages/utils.js index c5e307b..4929729 100644 --- a/qml/pages/utils.js +++ b/qml/pages/utils.js @@ -15,12 +15,15 @@ function supported_formats(printer, ConvertChecker, considerAdditionalFormats) var postscript = false; var office = false; var images = false; + var plaintext = false; if(has(formats, Mimer.PDF) || (ConvertChecker.pdf && ( has(formats, Mimer.Postscript) || raster ))) { pdf = true; mimetypes.push(Mimer.PDF); + plaintext = true; + mimetypes.push(Mimer.Plaintext); } if(has(formats, Mimer.Postscript)) { @@ -44,7 +47,7 @@ function supported_formats(printer, ConvertChecker, considerAdditionalFormats) mimetypes.push(Mimer.GIF); } - return {pdf: pdf, postscript: postscript, office: office, images: images, mimetypes: mimetypes}; + return {pdf: pdf, postscript: postscript, plaintext: plaintext, office: office, images: images, mimetypes: mimetypes}; } function has(arrayish, what) @@ -316,6 +319,18 @@ function limitChoices(name, choices, mimeType, ConvertChecker) } } + else if(mimeType == Mimer.Plaintext) + { + // We convert plaintext to PDF internally + if(ConvertChecker.pdf) + { + return choices.filter(canConvertPdfTo) + } + else + { + return choices.filter(canTransferPdfAs) + } + } else if(mimeType == Mimer.Postscript) { return choices.filter(canTransferPostscriptAs) diff --git a/src/convertworker.cpp b/src/convertworker.cpp index 4568628..86f624c 100644 --- a/src/convertworker.cpp +++ b/src/convertworker.cpp @@ -6,6 +6,8 @@ #include #include #include +#include +#include void ppm2PwgEnv(QStringList& env, bool urf, quint32 Quality, QString PaperSize, quint32 HwResX, quint32 HwResY, bool TwoSided, bool Tumble, @@ -379,6 +381,171 @@ catch(const ConvertFailedException& e) } } +void ConvertWorker::convertPlaintext(QNetworkRequest request, QString filename, QTemporaryFile* tempfile, + QString targetFormat, quint32 Colors, quint32 Quality, QString PaperSize, + quint32 HwResX, quint32 HwResY, bool TwoSided, bool Tumble) +{ +try { + + if(!PaperSizes.contains(PaperSize)) + { + qDebug() << "Unsupported paper size" << PaperSize; + throw ConvertFailedException(tr("Unsupported paper size")); + } + QPair wh = PaperSizes[PaperSize]; + + QFile inFile(filename); + if(!inFile.open(QIODevice::ReadOnly)) + { + throw ConvertFailedException(tr("Failed to open file")); + } + + quint32 resolution = std::min(HwResX, HwResY); + + QTemporaryFile tmpPdfFile; + tmpPdfFile.open(); + + QPdfWriter pdfWriter(tmpPdfFile.fileName()); + QPageSize pageSize(QSizeF {wh.first, wh.second}, QPageSize::Millimeter); + pdfWriter.setPageSize(pageSize); + pdfWriter.setResolution(resolution); + + qreal docHeight = pageSize.sizePixels(resolution).height(); + + QTextDocument doc; + + QFont font = QFont("Courier"); + font.setPointSizeF(1); + + qreal charHeight = 0; + + // Find the optimal font size + while(true) { + QFont tmpFont = font; + tmpFont.setPointSizeF(font.pointSizeF()+0.5); + QFontMetricsF qfm(tmpFont, &pdfWriter); + + charHeight = qfm.lineSpacing(); + + if(charHeight*66 > docHeight) + { + break; + } + font=tmpFont; + } + + QFontMetricsF qfm(font, &pdfWriter); + + charHeight = qfm.height(); + + int textHeight = 60*charHeight; + qreal margin = ((docHeight-textHeight)/2); + + doc.setDefaultFont(font); + (void)doc.documentLayout(); // wat + + // Needs to be before painter + pdfWriter.setMargins({0, 0, 0, 0}); + + QPainter painter(&pdfWriter); + + doc.documentLayout()->setPaintDevice(painter.device()); + doc.setDocumentMargin(margin); + + QRectF body = QRectF(0, 0, pdfWriter.width(), pdfWriter.height()); + doc.setPageSize(body.size()); + + QString allText = inFile.readAll(); + if(allText.startsWith("\f")) + { + allText.remove(0, 1); + } + + if(allText.endsWith("\f")) + { + allText.chop(1); + } + else if(allText.endsWith("\f\n")) + { + allText.chop(2); + } + + QStringList pages = allText.split('\f'); + + bool first = true; + int pageCount = 0; + + foreach(QString page, pages) + { + if(!first) + { + pdfWriter.newPage(); + } + first = false; + + if(page.endsWith("\n")) + { + page.chop(1); + } + doc.setPlainText(page); + + int p = 0; // Page number in this document, starting from 0 + + while(true) + { + painter.translate(body.left(), body.top() - p*body.height()); + QRectF view(0, p*body.height(), body.width(), body.height()); + painter.setClipRect(view); + + QAbstractTextDocumentLayout::PaintContext context; + context.clip = view; + context.palette.setColor(QPalette::Text, Qt::black); + doc.documentLayout()->draw(&painter, context); + + p++; + pageCount++; + + if(p >= doc.pageCount()) + break; + + pdfWriter.newPage(); + } + } + + painter.end(); + + + if(targetFormat == Mimer::PDF) + { + QFile tempfileAsFile(tempfile->fileName()); + tempfileAsFile.open(QIODevice::Append); + tempfileAsFile.write(tmpPdfFile.readAll()); + tempfileAsFile.close(); + } + else if(targetFormat == Mimer::Postscript) + { + pdftoPs(PaperSize, TwoSided, 0, 0, tmpPdfFile.fileName(), tempfile); + } + else + { + pdfToRaster(targetFormat, Colors, Quality, PaperSize, + HwResX, HwResY, TwoSided, Tumble, + 0, 0, pageCount, + tmpPdfFile.fileName(), tempfile, false); + } + + qDebug() << "Finished"; + + emit done(request, tempfile); + +} +catch(const ConvertFailedException& e) +{ + tempfile->deleteLater(); + emit failed(e.what() == QString("") ? tr("Conversion error") : e.what()); +} +} + QString ConvertWorker::getPopplerShortPaperSize(QString PaperSize) { QString ShortPaperSize; @@ -456,7 +623,10 @@ void ConvertWorker::pdftoPs(QString PaperSize, bool TwoSided, quint32 PageRangeL QString ShortPaperSize = getPopplerShortPaperSize(PaperSize); - PdfToPsArgs << QStringList {"-f", QString::number(PageRangeLow), "-l", QString::number(PageRangeHigh)}; + if(PageRangeLow != 0 && PageRangeHigh != 0) + { + PdfToPsArgs << QStringList {"-f", QString::number(PageRangeLow), "-l", QString::number(PageRangeHigh)}; + } PdfToPsArgs << QStringList {"-paper", ShortPaperSize, pdfFileName, "-"}; diff --git a/src/convertworker.h b/src/convertworker.h index c932145..c2322d8 100644 --- a/src/convertworker.h +++ b/src/convertworker.h @@ -36,6 +36,10 @@ public slots: quint32 HwResX, quint32 HwResY, bool TwoSided, bool Tumble, quint32 PageRangeLow, quint32 PageRangeHigh); + void convertPlaintext(QNetworkRequest request, QString filename, QTemporaryFile* tempfile, + QString targetFormat, quint32 Colors, quint32 Quality, QString PaperSize, + quint32 HwResX, quint32 HwResY, bool TwoSided, bool Tumble); + signals: void done(QNetworkRequest request, QTemporaryFile* data); void progress(qint64 done, qint64 pages); diff --git a/src/ippprinter.cpp b/src/ippprinter.cpp index bd6e849..1bbed7b 100644 --- a/src/ippprinter.cpp +++ b/src/ippprinter.cpp @@ -34,6 +34,7 @@ IppPrinter::IppPrinter() connect(this, &IppPrinter::doConvertPdf, _worker, &ConvertWorker::convertPdf); connect(this, &IppPrinter::doConvertImage, _worker, &ConvertWorker::convertImage); connect(this, &IppPrinter::doConvertOfficeDocument, _worker, &ConvertWorker::convertOfficeDocument); + connect(this, &IppPrinter::doConvertPlaintext, _worker, &ConvertWorker::convertPlaintext); connect(_worker, &ConvertWorker::done, this, &IppPrinter::convertDone); connect(_worker, &ConvertWorker::progress, this, &IppPrinter::setProgress); connect(_worker, &ConvertWorker::failed, this, &IppPrinter::convertFailed); @@ -310,7 +311,7 @@ QString targetFormatIfAuto(QString documentFormat, QString mimeType, QJsonArray { if(documentFormat == Mimer::OctetStream) { - if(mimeType == Mimer::PDF) + if(mimeType == Mimer::PDF || mimeType == Mimer::Plaintext) { return firstMatch(supportedMimeTypes, {Mimer::PDF, Mimer::Postscript, Mimer::PWG, Mimer::URF }); } @@ -534,6 +535,11 @@ void IppPrinter::print(QJsonObject attrs, QString filename, bool alwaysUseMediaC emit doConvertPdf(request, filename, tempfile, documentFormat, Colors, Quality, PaperSize, HwResX, HwResY, TwoSided, Tumble, PageRangeLow, PageRangeHigh); } + else if(mimeType == Mimer::Plaintext) + { + emit doConvertPlaintext(request, filename, tempfile, documentFormat, Colors, Quality, + PaperSize, HwResX, HwResY, TwoSided, Tumble); + } else if (Mimer::isImage(mimeType)) { emit doConvertImage(request, filename, tempfile, documentFormat, Colors, Quality, diff --git a/src/ippprinter.h b/src/ippprinter.h index b0739eb..99bd94f 100644 --- a/src/ippprinter.h +++ b/src/ippprinter.h @@ -54,6 +54,10 @@ signals: quint32 HwResX, quint32 HwResY, bool TwoSided, bool Tumble, quint32 PageRangeLow, quint32 PageRangeHigh); + void doConvertPlaintext(QNetworkRequest request, QString filename, QTemporaryFile* tempfile, + QString targetFormat, quint32 Colors, quint32 Quality, QString PaperSize, + quint32 HwResX, quint32 HwResY, bool TwoSided, bool Tumble); + void additionalDocumentFormatsChanged(); void busyMessageChanged(); void progressChanged(); diff --git a/src/mimer.cpp b/src/mimer.cpp index 04f92aa..388469b 100644 --- a/src/mimer.cpp +++ b/src/mimer.cpp @@ -18,6 +18,8 @@ const QString Mimer::RTF = "text/rtf"; const QString Mimer::RTF_APP = "application/rtf"; const QString Mimer::ODT = "application/vnd.oasis.opendocument.text"; +const QString Mimer::Plaintext = "text/plain"; + const QStringList Mimer::OfficeFormats = {DOC, DOCX, RTF, RTF_APP, ODT}; Mimer::Mimer() diff --git a/src/mimer.h b/src/mimer.h index 948323f..bccc046 100644 --- a/src/mimer.h +++ b/src/mimer.h @@ -30,6 +30,8 @@ public: Q_PROPERTY(const QString RTF MEMBER RTF CONSTANT); Q_PROPERTY(const QString ODT MEMBER ODT CONSTANT); + Q_PROPERTY(const QString Plaintext MEMBER Plaintext CONSTANT); + Q_PROPERTY(const QStringList OfficeFormats MEMBER OfficeFormats CONSTANT); static const QString OctetStream; @@ -50,6 +52,8 @@ public: static const QString RTF_APP; static const QString ODT; + static const QString Plaintext; + static const QStringList OfficeFormats; Q_INVOKABLE static bool isImage(QString mimeType) diff --git a/translations/harbour-seaprint-de.ts b/translations/harbour-seaprint-de.ts index 9fafb2b..421bc70 100644 --- a/translations/harbour-seaprint-de.ts +++ b/translations/harbour-seaprint-de.ts @@ -171,6 +171,10 @@ Failed to get info about PDF file PDF Info nicht abrufbar + + Failed to open file + Öffnen der Datei fehlgeschlagen + CoverPage diff --git a/translations/harbour-seaprint-es.ts b/translations/harbour-seaprint-es.ts index 6c43337..b2753a2 100644 --- a/translations/harbour-seaprint-es.ts +++ b/translations/harbour-seaprint-es.ts @@ -171,6 +171,10 @@ Failed to get info about PDF file Error al obtener info de archivo PDF + + Failed to open file + Error al abrir archivo + CoverPage diff --git a/translations/harbour-seaprint-fr.ts b/translations/harbour-seaprint-fr.ts index 3d7318f..d08bad3 100644 --- a/translations/harbour-seaprint-fr.ts +++ b/translations/harbour-seaprint-fr.ts @@ -171,6 +171,10 @@ Failed to get info about PDF file + + Failed to open file + + CoverPage diff --git a/translations/harbour-seaprint-nl.ts b/translations/harbour-seaprint-nl.ts index 49c4dd1..a68a50e 100644 --- a/translations/harbour-seaprint-nl.ts +++ b/translations/harbour-seaprint-nl.ts @@ -171,6 +171,10 @@ Failed to get info about PDF file Informatie over het PDF-bestand ophalen mislukt + + Failed to open file + Bestand openen mislukt + CoverPage diff --git a/translations/harbour-seaprint-pl.ts b/translations/harbour-seaprint-pl.ts index 1994ac9..9f7d3b6 100644 --- a/translations/harbour-seaprint-pl.ts +++ b/translations/harbour-seaprint-pl.ts @@ -171,6 +171,10 @@ Failed to load image + + Failed to open file + + CoverPage diff --git a/translations/harbour-seaprint-zh_CN.ts b/translations/harbour-seaprint-zh_CN.ts index 53855c4..77f3cd0 100644 --- a/translations/harbour-seaprint-zh_CN.ts +++ b/translations/harbour-seaprint-zh_CN.ts @@ -171,6 +171,10 @@ Failed to get info about PDF file 获取PDF文件信息错误 + + Failed to open file + 打开文件失败 + CoverPage diff --git a/translations/harbour-seaprint.ts b/translations/harbour-seaprint.ts index 8ffe8f6..f878f07 100644 --- a/translations/harbour-seaprint.ts +++ b/translations/harbour-seaprint.ts @@ -171,6 +171,10 @@ Failed to get info about PDF file + + Failed to open file + + CoverPage