Use pdf2printable

This commit is contained in:
Anton Thomasson 2021-11-08 19:49:47 +01:00
parent 0ef25112a5
commit b93568ad18
12 changed files with 181 additions and 220 deletions

View file

@ -27,8 +27,8 @@ system(lrelease $$PWD/translations/*.ts)
CONFIG += sailfishapp
QT += svg
PKGCONFIG += mlite5 libcurl
LIBS += -lcurl
PKGCONFIG += mlite5 libcurl poppler glib-2.0 cairo
LIBS += -lcurl -lpoppler -lcairo -lglib-2.0 -lgobject-2.0 -lpoppler-glib
# Write version file
VERSION_H = \
@ -40,13 +40,14 @@ write_file($$$$OUT_PWD/seaprint_version.h, VERSION_H)
SOURCES += src/harbour-seaprint.cpp \
src/convertchecker.cpp \
src/convertworker.cpp \
src/curliodevice.cpp \
src/curlrequester.cpp \
src/curlworker.cpp \
src/ippdiscovery.cpp \
src/ippmsg.cpp \
src/ippprinter.cpp \
src/mimer.cpp \
ppm2pwg/ppm2pwg.cpp \
ppm2pwg/pdf2printable.cpp \
ppm2pwg/bytestream/bytestream.cpp \
src/overrider.cpp \
src/settings.cpp \
@ -86,12 +87,14 @@ TRANSLATIONS += translations/harbour-seaprint-de.ts \
HEADERS += \
src/convertchecker.h \
src/convertworker.h \
src/curliodevice.h \
src/curlrequester.h \
src/curlworker.h \
src/ippdiscovery.h \
src/ippmsg.h \
src/ippprinter.h \
src/mimer.h \
ppm2pwg/ppm2pwg.h \
ppm2pwg/pdf2printable.h \
ppm2pwg/PwgPgHdr.h \
ppm2pwg/PwgPgHdr.codable \
ppm2pwg/UrfPgHdr.h \

@ -1 +1 @@
Subproject commit 331b4b5270264b604cd642201a7f5a2b6f2c9c1d
Subproject commit 6a93de071f3d2814260da5fe2ea14352483ea0a0

View file

@ -16,6 +16,10 @@ BuildRequires: pkgconfig(Qt5Svg)
BuildRequires: pkgconfig(mlite5)
BuildRequires: desktop-file-utils
BuildRequires: pkgconfig(libcurl)
BuildRequires: pkgconfig(poppler)
BuildRequires: pkgconfig(poppler-glib)
BuildRequires: pkgconfig(glib-2.0)
BuildRequires: pkgconfig(cairo)
%description
Network printing for Sailfish OS

View file

@ -11,6 +11,7 @@
#include <QPdfWriter>
#include <QAbstractTextDocumentLayout>
#include "ippprinter.h"
#include "pdf2printable.h"
void ppm2PwgEnv(QStringList& env, bool urf, quint32 Quality, QString PaperSize,
quint32 HwResX, quint32 HwResY, bool TwoSided, bool Tumble,
@ -64,7 +65,7 @@ ConvertWorker::ConvertWorker(IppPrinter* parent) // : QObject((QObject*)parent)
void ConvertWorker::command(QByteArray msg)
{
CurlIODevice cid(_printer->httpUrl());
CurlRequester cid(_printer->httpUrl());
cid.setFinishedCallback(_printer, &IppPrinter::getPrinterAttributesFinished);
qDebug() << "command...";
@ -75,7 +76,7 @@ void ConvertWorker::command(QByteArray msg)
// TODO: de-duplicate
void ConvertWorker::getJobs(QByteArray msg)
{
CurlIODevice cid(_printer->httpUrl());
CurlRequester cid(_printer->httpUrl());
cid.setFinishedCallback(_printer, &IppPrinter::getJobsRequestFinished);
cid.write(msg.data(), msg.length());
@ -83,7 +84,7 @@ void ConvertWorker::getJobs(QByteArray msg)
void ConvertWorker::cancelJob(QByteArray msg)
{
CurlIODevice cid(_printer->httpUrl());
CurlRequester cid(_printer->httpUrl());
cid.setFinishedCallback(_printer, &IppPrinter::cancelJobFinished);
cid.write(msg.data(), msg.length());
@ -93,11 +94,9 @@ void ConvertWorker::justUpload(QString filename, QByteArray header)
{
qDebug() << "justupload";
CurlIODevice cid(_printer->httpUrl());
CurlRequester cid(_printer->httpUrl());
cid.setFinishedCallback(_printer, &IppPrinter::printRequestFinished);
qDebug() << "justupload cp set";
QFile file(filename);
file.open(QFile::ReadOnly);
@ -113,87 +112,67 @@ void ConvertWorker::convertPdf(QString filename, QByteArray header,
quint32 PageRangeLow, quint32 PageRangeHigh, bool BackHFlip, bool BackVFlip)
{
try {
Format format;
quint32 pages = ConvertChecker::instance()->pdfPages(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;
bool urf = false;
bool ps = false;
bool pdf = false;
qDebug() << "to pdf" << HwResX << HwResY;
if(targetFormat == Mimer::URF)
{
urf = true;
format = Format::URF;
}
else if(targetFormat == Mimer::PWG)
{
//ok
format = Format::PWG;
}
else if(targetFormat == Mimer::Postscript)
{
ps = true;
format = Format::Postscript;
}
else if (targetFormat == Mimer::PDF)
{
pdf = true;
format = Format::PDF;
}
else
{
throw ConvertFailedException(tr("Unsupported target format"));
}
if(urf && (HwResX != HwResY))
{ // URF only supports symmetric resolutions
qDebug() << "Unsupported URF resolution" << PaperSize;
throw ConvertFailedException(tr("Unsupported resolution (dpi)"));
}
QTemporaryFile tempfile;
tempfile.open();
tempfile.close();
if(ps)
if(Colors == 0)
{
pdftoPs(PaperSize, TwoSided, PageRangeLow, PageRangeHigh, filename, &tempfile);
}
else if(pdf)
{
adjustPageRange(PaperSize, PageRangeLow, PageRangeHigh, filename, &tempfile);
}
else
{
pdfToRaster(targetFormat, Colors, Quality, PaperSize,
HwResX, HwResY, TwoSided, Tumble,
PageRangeLow, PageRangeHigh, pages, BackHFlip, BackVFlip,
filename, &tempfile, true);
Colors = 3;
}
CurlRequester cid(_printer->httpUrl());
cid.setFinishedCallback(_printer, &IppPrinter::printRequestFinished);
cid.write(header.data(), header.length());
write_fun WriteFun([&cid](unsigned char const* buf, unsigned int len) -> bool
{
qDebug() << "wf called " << len;
cid.write((const char*)buf, len);
qDebug() << "wf returns " << len;
return true;
});
if(!PaperSizes.contains(PaperSize))
{
qDebug() << "Unsupported paper size" << PaperSize;
throw ConvertFailedException(tr("Unsupported paper size"));
}
QSizeF size = PaperSizes[PaperSize];
float Width = size.width();
float Height = size.height();
int res = pdf_to_printable(filename.toStdString(), WriteFun, Colors, Quality, PaperSize.toStdString(), Width, Height, HwResX, HwResY,
format, TwoSided, Tumble, BackHFlip, BackVFlip, PageRangeLow, PageRangeHigh);
if(res != 0)
{
throw ConvertFailedException("Conversion failed");
}
qDebug() << "Finished";
justUpload(tempfile.fileName(), header);
qDebug() << "posted";
}
catch(const ConvertFailedException& e)
{

View file

@ -2,7 +2,7 @@
#define CONVERTWORKER_H
#include <QObject>
#include <QtNetwork>
#include "curliodevice.h"
#include "curlrequester.h"
class IppPrinter;

View file

@ -1,124 +0,0 @@
#include "curliodevice.h"
#include <seaprint_version.h>
#include <algorithm>
Q_DECLARE_METATYPE(CURLcode)
static size_t trampoline(char* dest, size_t size, size_t nmemb, void* userp)
{
qDebug() << "boingiddy!";
CurlIODevice* cid = (CurlIODevice*)userp;
return cid->requestWrite(dest, size*nmemb);
}
CurlIODevice::CurlIODevice(QUrl addr) : _addr(addr), _canWrite(1), _canRead(), _reading(false), _done(false), _dest(nullptr), _size(0), _offset(0)
{
qRegisterMetaType<CURLcode>();
// if(openMode() != NotOpen && mode != WriteOnly)
// return false;
CURL* curl = curl_easy_init();
// if(!curl)
// return false;
curl_easy_setopt(curl, CURLOPT_URL, _addr.toString().toStdString().c_str());
curl_easy_setopt(curl, CURLOPT_POST, 1L);
curl_easy_setopt(curl, CURLOPT_READFUNCTION, trampoline);
curl_easy_setopt(curl, CURLOPT_READDATA, this);
curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
curl_easy_setopt(curl, CURLOPT_SSL_VERIFYSTATUS, 0L);
//TODO: free this list
struct curl_slist *opts = NULL;
opts = curl_slist_append(opts, "Transfer-Encoding: chunked");
opts = curl_slist_append(opts, "Content-Type: application/ipp");
opts = curl_slist_append(opts, "User-Agent: SeaPrint " SEAPRINT_VERSION);
opts = curl_slist_append(opts, "Accept-Encoding: identity");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, opts);
_performer = new CurlWorker(curl);
connect(_performer, &CurlWorker::done, this, &CurlIODevice::done);
connect(_performer, &CurlWorker::finished, _performer, &CurlWorker::deleteLater);
_performer->start();
qDebug() << "worker started";
}
CurlIODevice::~CurlIODevice()
{
qDebug() << "destroying";
_canWrite.acquire();
_done = true;
_canRead.release();
_performer->wait();
if(_dest != nullptr)
{
delete[] _dest;
}
qDebug() << "done destroying";
}
void CurlIODevice::write(const char *data, size_t size)
{
qDebug() << "write " << size;
_canWrite.acquire();
if(_dest != nullptr)
{
delete[] _dest;
}
_dest = new char[size];
memcpy(_dest, data, size);
_size = size;
_offset = 0;
_canRead.release();
}
size_t CurlIODevice::requestWrite(char* dest, size_t size)
{
qDebug() << "requestWrite " << size;
if(!_reading)
{
_canRead.acquire();
if(_done) // Can only have been set by write() - only relevant to check if strating to write
{
return 0;
}
_reading = true;
}
size_t remaining = _size - _offset;
qDebug() << "requestWrite canwrite";
size_t actualSize = std::min(size, remaining);
memcpy(dest, (_dest+_offset), actualSize);
_offset += actualSize;
remaining = _size - _offset;
if(remaining == 0)
{
_reading = false;
_canWrite.release();
}
qDebug() << "requestWrite returns " << _size;
return actualSize;
}
void CurlIODevice::done(CURLcode)
{
}

71
src/curlrequester.cpp Normal file
View file

@ -0,0 +1,71 @@
#include "curlrequester.h"
#include <algorithm>
CurlRequester::CurlRequester(QUrl addr) : _addr(addr), _canWrite(1), _canRead(), _reading(false), _done(false), _dest(nullptr), _size(0), _offset(0), _performer(addr, this)
{
connect(&_performer, &CurlWorker::done, this, &CurlRequester::done);
_performer.start();
}
CurlRequester::~CurlRequester()
{
_canWrite.acquire();
_done = true;
_canRead.release();
_performer.wait();
if(_dest != nullptr)
{
delete _dest;
}
}
void CurlRequester::write(const char *data, size_t size)
{
qDebug() << "write " << size;
_canWrite.acquire();
if(_dest != nullptr)
{
delete _dest;
}
_dest = new char[size];
memcpy(_dest, data, size);
_size = size;
_offset = 0;
_canRead.release();
}
size_t CurlRequester::requestWrite(char* dest, size_t size)
{
if(!_reading)
{
_canRead.acquire();
if(_done) // Can only have been set by write() - only relevant to check if strating to write
{
return 0;
}
_reading = true;
}
size_t remaining = _size - _offset;
size_t actualSize = std::min(size, remaining);
memcpy(dest, (_dest+_offset), actualSize);
_offset += actualSize;
remaining = _size - _offset;
if(remaining == 0)
{
_reading = false;
_canWrite.release();
}
return actualSize;
}
void CurlRequester::done(CURLcode)
{
}

View file

@ -1,5 +1,5 @@
#ifndef CURLIODEVICE_H
#define CURLIODEVICE_H
#ifndef CURLREQUESTER_H
#define CURLREQUESTER_H
#include <QUrl>
#include <QThread>
@ -9,17 +9,17 @@
#include <QDebug>
#include "curlworker.h"
class CurlIODevice : public QObject
class CurlRequester : public QObject
{
Q_OBJECT
public:
CurlIODevice(QUrl addr);
~CurlIODevice();
CurlRequester(QUrl addr);
~CurlRequester();
template<typename Class, typename Callback>
bool setFinishedCallback(const Class* receiverObject, Callback cb)
{
connect(_performer, &CurlWorker::done, receiverObject, cb);
connect(&_performer, &CurlWorker::done, receiverObject, cb);
return true;
}
@ -33,7 +33,6 @@ private:
QUrl _addr;
bool _open;
CurlWorker* _performer;
QSemaphore _canWrite;
QSemaphore _canRead;
@ -44,6 +43,7 @@ private:
size_t _size;
size_t _offset;
CurlWorker _performer;
};
#endif // CURLIODEVICE_H
#endif // CURLREQUESTER_H

View file

@ -1,22 +1,57 @@
#include "curlworker.h"
#include "curlrequester.h"
#include <seaprint_version.h>
CurlWorker::CurlWorker(CURL* curl)
Q_DECLARE_METATYPE(CURLcode)
static size_t trampoline(char* dest, size_t size, size_t nmemb, void* userp)
{
_curl = curl;
CurlRequester* cid = (CurlRequester*)userp;
return cid->requestWrite(dest, size*nmemb);
}
CurlWorker::CurlWorker(QUrl addr, void* parent)
{
qRegisterMetaType<CURLcode>();
_curl = curl_easy_init();
// if(!curl)
// return false;
curl_easy_setopt(_curl, CURLOPT_URL, addr.toString().toStdString().c_str());
curl_easy_setopt(_curl, CURLOPT_POST, 1L);
curl_easy_setopt(_curl, CURLOPT_READFUNCTION, trampoline);
curl_easy_setopt(_curl, CURLOPT_READDATA, parent);
curl_easy_setopt(_curl, CURLOPT_VERBOSE, 1L);
curl_easy_setopt(_curl, CURLOPT_SSL_VERIFYPEER, 0L);
curl_easy_setopt(_curl, CURLOPT_SSL_VERIFYHOST, 0L);
curl_easy_setopt(_curl, CURLOPT_SSL_VERIFYSTATUS, 0L);
_opts = NULL;
_opts = curl_slist_append(_opts, "Transfer-Encoding: chunked");
_opts = curl_slist_append(_opts, "Content-Type: application/ipp");
_opts = curl_slist_append(_opts, "User-Agent: SeaPrint " SEAPRINT_VERSION);
_opts = curl_slist_append(_opts, "Accept-Encoding: identity");
curl_easy_setopt(_curl, CURLOPT_HTTPHEADER, _opts);
}
CurlWorker::~CurlWorker()
{
curl_slist_free_all(_opts);
curl_easy_cleanup(_curl);
}
void CurlWorker::run(){
QByteArray buf;
curl_easy_setopt(_curl, CURLOPT_WRITEDATA, &buf);
curl_easy_setopt(_curl, CURLOPT_WRITEFUNCTION, write_callback);
qDebug() << "performer running";
CURLcode res = curl_easy_perform(_curl);
if(res != CURLE_OK)
qDebug() << "curl_easy_perform() failed: " << curl_easy_strerror(res);
curl_easy_cleanup(_curl);
curl_global_cleanup();
qDebug() << "performer done " << buf.length();
emit done(res, buf);
}

View file

@ -2,6 +2,7 @@
#define CURLWORKER_H
#include <QThread>
#include <QUrl>
#include <curl/curl.h>
#include <QtDebug>
@ -9,12 +10,13 @@ class CurlWorker : public QThread
{
Q_OBJECT
public:
CurlWorker(CURL* curl);
CurlWorker(QUrl addr, void* parent);
~CurlWorker();
void run() override;
static size_t write_callback(char *ptr, size_t size, size_t nmemb, void* userdata)
{
qDebug() << "writing resp" << size*nmemb;
size_t bytes_to_write = size*nmemb;
((QByteArray*)userdata)->append(ptr, bytes_to_write);
return bytes_to_write;
@ -41,6 +43,7 @@ private:
CurlWorker();
CURL* _curl = nullptr;
struct curl_slist* _opts;
};

View file

@ -9,9 +9,6 @@
#include <src/svgprovider.h>
#include <src/settings.h>
#define PPM2PWG_MAIN ppm2pwg_main
#include <ppm2pwg/ppm2pwg.cpp>
template <class T>
static QObject* singletontype_provider(QQmlEngine *engine, QJSEngine *scriptEngine)
{
@ -25,12 +22,6 @@ static QObject* singletontype_provider(QQmlEngine *engine, QJSEngine *scriptEngi
int main(int argc, char *argv[])
{
if(argc >= 1 && QString("ppm2pwg") == argv[1])
{
return ppm2pwg_main(argc-1, &(argv[1]));
}
QGuiApplication* app = SailfishApp::application(argc, argv);
app->setOrganizationName(QStringLiteral("net.attah"));
@ -53,5 +44,4 @@ int main(int argc, char *argv[])
view->setSource(SailfishApp::pathToMainQml());
view->show();
return app->exec();
}

View file

@ -5,7 +5,7 @@
#include <QNetworkAccessManager>
#include "ippmsg.h"
#include "convertworker.h"
#include "curliodevice.h"
#include "curlrequester.h"
#include <mlite5/MGConfItem>
class IppPrinter : public QObject