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

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

View file

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

View file

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

View file

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

View file

@ -1,22 +1,57 @@
#include "curlworker.h" #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(){ void CurlWorker::run(){
QByteArray buf; QByteArray buf;
curl_easy_setopt(_curl, CURLOPT_WRITEDATA, &buf); curl_easy_setopt(_curl, CURLOPT_WRITEDATA, &buf);
curl_easy_setopt(_curl, CURLOPT_WRITEFUNCTION, write_callback); curl_easy_setopt(_curl, CURLOPT_WRITEFUNCTION, write_callback);
qDebug() << "performer running";
CURLcode res = curl_easy_perform(_curl); CURLcode res = curl_easy_perform(_curl);
if(res != CURLE_OK) if(res != CURLE_OK)
qDebug() << "curl_easy_perform() failed: " << curl_easy_strerror(res); 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); emit done(res, buf);
} }

View file

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

View file

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

View file

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