Add calligraconverter support

This commit is contained in:
Anton Thomasson 2021-03-06 12:59:47 +01:00
parent d16562900f
commit 43373d159e
10 changed files with 332 additions and 26 deletions

View file

@ -76,6 +76,7 @@ Page {
if(status==PageStatus.Active && !nagged && nagScreenSetting.value != nagScreenSetting.expectedValue) if(status==PageStatus.Active && !nagged && nagScreenSetting.value != nagScreenSetting.expectedValue)
{ {
console.log("Can convert from PDF:", ConvertChecker.pdf) console.log("Can convert from PDF:", ConvertChecker.pdf)
console.log("Can convert from Office:", ConvertChecker.calligra)
if(!ConvertChecker.pdf) if(!ConvertChecker.pdf)
{ {
nagged=true nagged=true
@ -345,24 +346,25 @@ Page {
DocumentPickerPage { DocumentPickerPage {
allowedOrientations: Orientation.All allowedOrientations: Orientation.All
Component.onCompleted: { // Component.onCompleted: {
var thingy = Qt.createComponent("../components/DocumentFilter.notqml"); // var thingy = Qt.createComponent("../components/DocumentFilter.notqml");
if (thingy.status == Component.Ready) { // if (thingy.status == Component.Ready) {
_contentModel.contentFilter = thingy.createObject(this); // _contentModel.contentFilter = thingy.createObject(this);
} // }
} // }
title: qsTr("Choose file") title: qsTr("Choose file")
onSelectedContentPropertiesChanged: { onSelectedContentPropertiesChanged: {
var mimeType = Mimer.get_type(selectedContentProperties.filePath) var mimeType = Mimer.get_type(selectedContentProperties.filePath)
if(mimeType == "application/pdf" || mimeType == "application/postscript") if(mimeType == "application/pdf" || mimeType == "application/postscript" || Mimer.isOffice(mimeType))
{ {
page.selectedFile = selectedContentProperties.filePath page.selectedFile = selectedContentProperties.filePath
page.selectedFileType = mimeType page.selectedFileType = mimeType
} }
else else
{ {
console.log("UNSUPPORTED", mimeType);
notifier.notify(qsTr("Unsupported document format")) notifier.notify(qsTr("Unsupported document format"))
page.selectedFile = "" page.selectedFile = ""
page.selectedFileType = "" page.selectedFileType = ""

View file

@ -22,6 +22,12 @@ function supported_formats(printer, ConvertChecker, considerAdditionalFormats)
supported.push("Postscript"); supported.push("Postscript");
} }
if((ConvertChecker.pdf && ConvertChecker.calligra) &&
( has(formats, Mimer.PDF) || has(formats, Mimer.Postscript) || raster ))
{
mimetypes = mimetypes.concat(Mimer.OfficeFormats);
}
if (raster || has(formats, Mimer.JPEG) || has(formats, Mimer.PNG)) if (raster || has(formats, Mimer.JPEG) || has(formats, Mimer.PNG))
{ {
mimetypes.push(Mimer.JPEG); mimetypes.push(Mimer.JPEG);
@ -266,6 +272,12 @@ function canTransferPostscriptAs(type)
return has(targets, type) return has(targets, type)
} }
function canConvertOfficeDocumentTo(type)
{
var targets = [Mimer.OctetStream, Mimer.PDF, Mimer.Postscript, Mimer.PWG, Mimer.URF];
return has(targets, type)
}
function canConvertImageTo(type) function canConvertImageTo(type)
{ {
var targets = [Mimer.OctetStream, Mimer.JPEG, Mimer.PNG, Mimer.PWG, Mimer.URF]; var targets = [Mimer.OctetStream, Mimer.JPEG, Mimer.PNG, Mimer.PWG, Mimer.URF];
@ -298,7 +310,11 @@ function limitChoices(name, choices, mimeType, ConvertChecker)
{ {
return choices.filter(canTransferPostscriptAs) return choices.filter(canTransferPostscriptAs)
} }
else if(mimeType.indexOf("image") != -1) else if(Mimer.isOffice(mimeType))
{
return choices.filter(canConvertOfficeDocumentTo)
}
else if(Mimer.isImage(mimeType))
{ {
return choices.filter(canConvertImageTo); return choices.filter(canConvertImageTo);
} }

View file

@ -8,8 +8,8 @@ class ConvertChecker : public QObject
Q_OBJECT Q_OBJECT
public: public:
static ConvertChecker* instance(); static ConvertChecker* instance();
Q_PROPERTY(bool pdf MEMBER _pdf) Q_PROPERTY(bool pdf MEMBER _pdf CONSTANT)
Q_PROPERTY(bool calligra MEMBER _calligra) Q_PROPERTY(bool calligra MEMBER _calligra CONSTANT)
Q_INVOKABLE quint32 pdfPages(QString pdf); Q_INVOKABLE quint32 pdfPages(QString pdf);

View file

@ -430,3 +430,232 @@ catch(const ConvertFailedException& e)
emit failed(e.what() == QString("") ? tr("Conversion error") : e.what()); emit failed(e.what() == QString("") ? tr("Conversion error") : e.what());
} }
} }
void ConvertWorker::convertOfficeDocument(QNetworkRequest request, QString filename, QTemporaryFile* tempfile,
QString targetFormat, quint32 Colors, quint32 Quality, QString PaperSize,
quint32 HwResX, quint32 HwResY, bool TwoSided, bool Tumble,
quint32 PageRangeLow, quint32 PageRangeHigh)
{
try {
if(targetFormat == Mimer::URF && (HwResX != HwResY))
{ // URF only supports symmetric resolutions
qDebug() << "Unsupported URF resolution" << PaperSize;
throw ConvertFailedException(tr("Unsupported resolution (dpi)"));
}
QString ShortPaperSize;
if(CalligraPaperSizes.contains(PaperSize))
{
ShortPaperSize = CalligraPaperSizes[PaperSize];
}
else
{
qDebug() << "Unsupported PDF paper size" << PaperSize;
throw ConvertFailedException(tr("Unsupported PDF paper size"));
}
QProcess* CalligraConverter = new QProcess(this);
CalligraConverter->setProgram("calligraconverter");
QStringList CalligraConverterArgs = {"--batch", "--mimetype", Mimer::PDF, "--print-orientation", "Portrait", "--print-papersize", ShortPaperSize};
CalligraConverterArgs << filename;
QTemporaryFile tmpPdfFile;
tmpPdfFile.open();
CalligraConverterArgs << tmpPdfFile.fileName();
qDebug() << "CalligraConverteArgs is" << CalligraConverterArgs;
CalligraConverter->setArguments(CalligraConverterArgs);
connect(CalligraConverter, SIGNAL(finished(int, QProcess::ExitStatus)), CalligraConverter, SLOT(deleteLater()));
CalligraConverter->start();
qDebug() << "CalligraConverter Starting";
if(!CalligraConverter->waitForStarted())
{
qDebug() << "CalligraConverter died";
throw ConvertFailedException();
}
qDebug() << "CalligraConverter Started";
if(!CalligraConverter->waitForFinished(-1))
{
qDebug() << "CalligraConverter failed";
throw ConvertFailedException();
}
// qDebug() << CalligraConverter->readAllStandardError();
quint32 pages = ConvertChecker::instance()->pdfPages(tmpPdfFile.fileName());
if (!pages)
{
qDebug() << "pdfinfo returned 0 pages";
throw ConvertFailedException(tr("Failed to get info about PDF file"));
}
if(PageRangeLow==0)
{
PageRangeLow=1;
}
if(PageRangeHigh==0)
{
PageRangeHigh=pages;
}
// Actual number of pages to print
pages = PageRangeHigh-PageRangeLow+1;
qDebug() << "PageRangeLow" << PageRangeLow << "PageRangeHigh" << PageRangeHigh << "pages" << pages;
if(targetFormat == Mimer::PDF)
{
// TODO Page ranges
QFile tempfileAsFile(tempfile->fileName());
tempfileAsFile.open(QIODevice::Append);
tempfileAsFile.write(tmpPdfFile.readAll());
tempfileAsFile.close();
}
else if(targetFormat == Mimer::Postscript)
{
QProcess* PdfToPs = new QProcess(this);
PdfToPs->setProgram("pdftops");
QStringList PdfToPsArgs;
if(TwoSided)
{
PdfToPsArgs.append("-duplex");
}
PdfToPsArgs << QStringList {"-f", QString::number(PageRangeLow), "-l", QString::number(PageRangeHigh)};
PdfToPsArgs << QStringList {tmpPdfFile.fileName(), "-"};
qDebug() << "pdftops args is " << PdfToPsArgs;
PdfToPs->setArguments(PdfToPsArgs);
PdfToPs->setStandardOutputFile(tempfile->fileName(), QIODevice::Append);
connect(PdfToPs, SIGNAL(finished(int, QProcess::ExitStatus)), PdfToPs, SLOT(deleteLater()));
PdfToPs->start();
qDebug() << "PdfToPs Starting";
if(!PdfToPs->waitForStarted())
{
qDebug() << "PdfToPs died";
throw ConvertFailedException();
}
qDebug() << "PdfToPs Started";
if(!PdfToPs->waitForFinished(-1))
{
qDebug() << "PdfToPs failed";
throw ConvertFailedException();
}
}
else
{
QProcess* pdftoppm = new QProcess(this);
pdftoppm->setProgram("pdftoppm");
QStringList Pdf2PpmArgs = {"-rx", QString::number(HwResX), "-ry", QString::number(HwResY)};
Pdf2PpmArgs << QStringList {"-f", QString::number(PageRangeLow), "-l", QString::number(PageRangeHigh)};
if(Colors == 1)
{
Pdf2PpmArgs.append("-gray");
}
qDebug() << "pdf2ppm args is " << Pdf2PpmArgs;
pdftoppm->setArguments(Pdf2PpmArgs);
QProcess* ppm2pwg = new QProcess(this);
// Yo dawg, I heard you like programs...
ppm2pwg->setProgram("harbour-seaprint");
ppm2pwg->setArguments({"ppm2pwg"});
bool urf = targetFormat == Mimer::URF;
QStringList env;
ppm2PwgEnv(env, urf, Quality, PaperSize, HwResX, HwResY, TwoSided, Tumble, true, pages);
qDebug() << "ppm2pwg env is " << env;
ppm2pwg->setEnvironment(env);
pdftoppm->setStandardInputFile(tmpPdfFile.fileName());
pdftoppm->setStandardOutputProcess(ppm2pwg);
ppm2pwg->setStandardOutputFile(tempfile->fileName(), QIODevice::Append);
connect(pdftoppm, SIGNAL(finished(int, QProcess::ExitStatus)), pdftoppm, SLOT(deleteLater()));
connect(ppm2pwg, SIGNAL(finished(int, QProcess::ExitStatus)), ppm2pwg, SLOT(deleteLater()));
qDebug() << "All connected";
pdftoppm->start();
ppm2pwg->start();
qDebug() << "Starting";
if(!pdftoppm->waitForStarted())
{
qDebug() << "pdftoppm died";
throw ConvertFailedException();
}
if(!ppm2pwg->waitForStarted())
{
qDebug() << "ppm2pwg died";
throw ConvertFailedException();
}
qDebug() << "All started";
bool ppm2pwgSuccess = false;
for(;;)
{
if(ppm2pwg->waitForFinished(1000))
{
ppm2pwgSuccess = true;
break;
}
else
{
QList<QByteArray> ppm2pwgOutput = ppm2pwg->readAllStandardError().split('\n');
for(QList<QByteArray>::iterator it = ppm2pwgOutput.begin(); it != ppm2pwgOutput.end(); it++)
{
if(it->startsWith("Page"))
{
QList<QByteArray> ppm2pwgTokens = it->split(' ');
emit progress(ppm2pwgTokens.last().toInt()-1, pages);
}
}
}
}
if(!ppm2pwgSuccess)
{
qDebug() << "ppm2pwg failed";
throw ConvertFailedException();
}
}
qDebug() << "Finished";
emit done(request, tempfile);
qDebug() << "posted";
}
catch(const ConvertFailedException& e)
{
tempfile->deleteLater();
emit failed(e.what() == QString("") ? tr("Conversion error") : e.what());
}
}

View file

@ -31,6 +31,11 @@ public slots:
QString targetFormat, quint32 Colors, quint32 Quality, QString PaperSize, QString targetFormat, quint32 Colors, quint32 Quality, QString PaperSize,
quint32 HwResX, quint32 HwResY); quint32 HwResX, quint32 HwResY);
void convertOfficeDocument(QNetworkRequest request, QString filename, QTemporaryFile* tempfile,
QString targetFormat, quint32 Colors, quint32 Quality, QString PaperSize,
quint32 HwResX, quint32 HwResY, bool TwoSided, bool Tumble,
quint32 PageRangeLow, quint32 PageRangeHigh);
signals: signals:
void done(QNetworkRequest request, QTemporaryFile* data); void done(QNetworkRequest request, QTemporaryFile* data);
void progress(qint64 done, qint64 pages); void progress(qint64 done, qint64 pages);

View file

@ -32,6 +32,7 @@ IppPrinter::IppPrinter()
connect(this, &IppPrinter::doConvertPdf, _worker, &ConvertWorker::convertPdf); connect(this, &IppPrinter::doConvertPdf, _worker, &ConvertWorker::convertPdf);
connect(this, &IppPrinter::doConvertImage, _worker, &ConvertWorker::convertImage); connect(this, &IppPrinter::doConvertImage, _worker, &ConvertWorker::convertImage);
connect(this, &IppPrinter::doConvertOfficeDocument, _worker, &ConvertWorker::convertOfficeDocument);
connect(_worker, &ConvertWorker::done, this, &IppPrinter::convertDone); connect(_worker, &ConvertWorker::done, this, &IppPrinter::convertDone);
connect(_worker, &ConvertWorker::progress, this, &IppPrinter::setProgress); connect(_worker, &ConvertWorker::progress, this, &IppPrinter::setProgress);
connect(_worker, &ConvertWorker::failed, this, &IppPrinter::convertFailed); connect(_worker, &ConvertWorker::failed, this, &IppPrinter::convertFailed);
@ -503,10 +504,6 @@ void IppPrinter::print(QJsonObject attrs, QString filename, bool alwaysConvert,
qDebug() << tempfile->fileName(); qDebug() << tempfile->fileName();
tempfile->close(); tempfile->close();
setBusyMessage("Converting");
if(mimeType == Mimer::PDF)
{
bool TwoSided = false; bool TwoSided = false;
bool Tumble = false; bool Tumble = false;
if(Sides=="two-sided-long-edge") if(Sides=="two-sided-long-edge")
@ -519,6 +516,10 @@ void IppPrinter::print(QJsonObject attrs, QString filename, bool alwaysConvert,
Tumble = true; Tumble = true;
} }
setBusyMessage("Converting");
if(mimeType == Mimer::PDF)
{
emit doConvertPdf(request, filename, tempfile, documentFormat, Colors, Quality, emit doConvertPdf(request, filename, tempfile, documentFormat, Colors, Quality,
PaperSize, HwResX, HwResY, TwoSided, Tumble, PageRangeLow, PageRangeHigh); PaperSize, HwResX, HwResY, TwoSided, Tumble, PageRangeLow, PageRangeHigh);
} }
@ -527,6 +528,11 @@ void IppPrinter::print(QJsonObject attrs, QString filename, bool alwaysConvert,
emit doConvertImage(request, filename, tempfile, documentFormat, Colors, Quality, emit doConvertImage(request, filename, tempfile, documentFormat, Colors, Quality,
PaperSize, HwResX, HwResY); PaperSize, HwResX, HwResY);
} }
else if(Mimer::isOffice(mimeType))
{
emit doConvertOfficeDocument(request, filename, tempfile, documentFormat, Colors, Quality,
PaperSize, HwResX, HwResY, TwoSided, Tumble, PageRangeLow, PageRangeHigh);
}
else else
{ {
emit convertFailed(tr("Cannot convert this file format")); emit convertFailed(tr("Cannot convert this file format"));

View file

@ -49,6 +49,11 @@ signals:
QString targetFormat, quint32 Colors, quint32 Quality, QString PaperSize, QString targetFormat, quint32 Colors, quint32 Quality, QString PaperSize,
quint32 HwResX, quint32 HwResY); quint32 HwResX, quint32 HwResY);
void doConvertOfficeDocument(QNetworkRequest request, QString filename, QTemporaryFile* tempfile,
QString targetFormat, quint32 Colors, quint32 Quality, QString PaperSize,
quint32 HwResX, quint32 HwResY, bool TwoSided, bool Tumble,
quint32 PageRangeLow, quint32 PageRangeHigh);
void additionalDocumentFormatsChanged(); void additionalDocumentFormatsChanged();
void busyMessageChanged(); void busyMessageChanged();
void progressChanged(); void progressChanged();

View file

@ -15,8 +15,10 @@ const QString Mimer::TIFF = "image/tiff";
const QString Mimer::DOC = "application/msword"; const QString Mimer::DOC = "application/msword";
const QString Mimer::DOCX = "application/vnd.openxmlformats-officedocument.wordprocessingml.document"; const QString Mimer::DOCX = "application/vnd.openxmlformats-officedocument.wordprocessingml.document";
const QString Mimer::RTF = "text/rtf"; 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::ODT = "application/vnd.oasis.opendocument.text";
const QStringList Mimer::OfficeFormats = {DOC, DOCX, RTF, RTF_APP, ODT};
Mimer::Mimer() Mimer::Mimer()
{ {

View file

@ -25,6 +25,13 @@ public:
Q_PROPERTY(const QString JPEG MEMBER JPEG CONSTANT); Q_PROPERTY(const QString JPEG MEMBER JPEG CONSTANT);
Q_PROPERTY(const QString TIFF MEMBER TIFF CONSTANT); Q_PROPERTY(const QString TIFF MEMBER TIFF CONSTANT);
Q_PROPERTY(const QString DOC MEMBER DOC CONSTANT);
Q_PROPERTY(const QString DOCX MEMBER DOCX CONSTANT);
Q_PROPERTY(const QString RTF MEMBER RTF CONSTANT);
Q_PROPERTY(const QString ODT MEMBER ODT CONSTANT);
Q_PROPERTY(const QStringList OfficeFormats MEMBER OfficeFormats CONSTANT);
static const QString OctetStream; static const QString OctetStream;
static const QString PDF; static const QString PDF;
@ -40,20 +47,20 @@ public:
static const QString DOC; static const QString DOC;
static const QString DOCX; static const QString DOCX;
static const QString RTF; static const QString RTF;
static const QString RTF_APP;
static const QString ODT; static const QString ODT;
static const QStringList OfficeFormats;
Q_INVOKABLE static bool isImage(QString mimeType) Q_INVOKABLE static bool isImage(QString mimeType)
{ {
return mimeType.startsWith("image/"); return mimeType.startsWith("image/");
} }
Q_INVOKABLE static bool isOffice(QString mimeType) Q_INVOKABLE static bool isOffice(QString mimeType)
{ {
static QStringList OfficeForamts {DOC, DOCX, RTF, ODT}; return OfficeFormats.contains(mimeType);
return OfficeForamts.contains(mimeType);
} }
private: private:
Mimer(); Mimer();
static Mimer* m_Instance; static Mimer* m_Instance;

View file

@ -205,5 +205,39 @@ static QMap<QString, QPair<float,float>> PaperSizes =
{"roc_16k_7.75x10.75in", {196.85, 273.05}}, {"roc_16k_7.75x10.75in", {196.85, 273.05}},
{"roc_8k_10.75x15.5in", {273.05, 393.70}}}; {"roc_8k_10.75x15.5in", {273.05, 393.70}}};
static QMap<QString, QString> CalligraPaperSizes =
{{"iso_a0_841x1189mm", "A0"},
{"iso_a1_594x841mm", "A1"},
{"iso_a2_420x594mm", "A2"},
{"iso_a3_297x420mm", "A3"},
{"iso_a4_210x297mm", "A4"},
{"iso_a5_148x210mm", "A5"},
{"iso_a6_105x148mm", "A6"},
{"iso_a7_74x105mm", "A7"},
{"iso_a8_52x74mm", "A8"},
{"iso_a9_37x52mm", "A9"},
{"iso_b0_1000x1414mm", "B0"},
{"iso_b1_707x1000mm", "B1"},
{"iso_b2_500x707mm", "B2"},
{"iso_b3_353x500mm", "B3"},
{"iso_b4_250x353mm", "B4"},
{"iso_b5_176x250mm", "B5"},
{"iso_b6_125x176mm", "B6"},
{"iso_b7_88x125mm", "B7"},
{"iso_b8_62x88mm", "B8"},
{"iso_b9_44x62mm", "B9"},
{"iso_b10_31x44mm", "B10"},
{"iso_c5_162x229mm", "C5E"},
{"na_number-10_4.125x9.5in", "Comm10E"},
{"iso_dl_110x220mm", "DLE"},
{"na_executive_7.25x10.5in", "Executive"},
{"om_folio_210x330mm", "Folio"},
{"na_ledger_11x17in", "Ledger"},
{"na_legal_8.5x14in", "Legal"},
{"na_letter_8.5x11in", "Letter"},
{"na_ledger_11x17in", "Tabloid"} // Dimension match
};
#endif // PAPERSIZES_H #endif // PAPERSIZES_H