Stop resizing images when transferred as such
This commit is contained in:
parent
ff2eae04cf
commit
08b66ed711
14 changed files with 116 additions and 63 deletions
|
@ -34,9 +34,12 @@ For images, your printer needs to support one of the following formats:
|
||||||
* PDF
|
* PDF
|
||||||
* Postscript
|
* Postscript
|
||||||
|
|
||||||
For printing JPEG images, transferring the unaltered image has priority and the printer does the scaling.
|
When printing images the result may depend on how they are transferred.
|
||||||
JPEGs are however (losslessly) re-encoded to the baseline encoding profile to work with all printers (since SeaPrint 1.1).
|
If a document-oriented format like PDF/Postscript/PWG/URF is used SeaPrint does scale-and-rotate to fit, otherwise (when transferred as PNG or JPEG) that is left up to the printer. Only when printing images *as images* can the scaling setting be used.
|
||||||
Other image formats are lossless and SeaPrint does scale-and-rotate to fit, so JPEG has lowest prio there.
|
|
||||||
|
For printing JPEG images, transferring them as JPEG has highest priority.
|
||||||
|
JPEGs are then (losslessly) re-encoded to the baseline encoding profile to work with all printers (since SeaPrint 1.1).
|
||||||
|
For other image formats JPEG has lowest priority as transfer format since it is lossy.
|
||||||
|
|
||||||
Printers with any of these IPP certifications and derivative standards should likely be supported:
|
Printers with any of these IPP certifications and derivative standards should likely be supported:
|
||||||
|
|
||||||
|
|
|
@ -148,10 +148,10 @@ Page {
|
||||||
tag: IppMsg.Keyword
|
tag: IppMsg.Keyword
|
||||||
name: "print-scaling"
|
name: "print-scaling"
|
||||||
prettyName: qsTr("Scaling")
|
prettyName: qsTr("Scaling")
|
||||||
valid: _valid && selectedFileType == Mimer.JPEG
|
valid: _valid && Mimer.isImage(selectedFileType)
|
||||||
DependentOn {
|
DependentOn {
|
||||||
target: transferFormatSetting
|
target: transferFormatSetting
|
||||||
values: [Mimer.JPEG]
|
values: [Mimer.JPEG, Mimer.PNG]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ChoiceSetting {
|
ChoiceSetting {
|
||||||
|
|
|
@ -20,7 +20,7 @@ IppPrinter::IppPrinter() : _worker(this)
|
||||||
connect(this, &IppPrinter::doIdentify, &_worker, &PrinterWorker::identify);
|
connect(this, &IppPrinter::doIdentify, &_worker, &PrinterWorker::identify);
|
||||||
connect(this, &IppPrinter::doJustUpload, &_worker, &PrinterWorker::justUpload);
|
connect(this, &IppPrinter::doJustUpload, &_worker, &PrinterWorker::justUpload);
|
||||||
connect(this, &IppPrinter::doFixupPlaintext, &_worker, &PrinterWorker::fixupPlaintext);
|
connect(this, &IppPrinter::doFixupPlaintext, &_worker, &PrinterWorker::fixupPlaintext);
|
||||||
connect(this, &IppPrinter::doFixupJpeg, &_worker, &PrinterWorker::fixupJpeg);
|
connect(this, &IppPrinter::doFixupImage, &_worker, &PrinterWorker::fixupImage);
|
||||||
|
|
||||||
connect(this, &IppPrinter::doConvertPdf, &_worker, &PrinterWorker::convertPdf);
|
connect(this, &IppPrinter::doConvertPdf, &_worker, &PrinterWorker::convertPdf);
|
||||||
connect(this, &IppPrinter::doConvertImage, &_worker, &PrinterWorker::convertImage);
|
connect(this, &IppPrinter::doConvertImage, &_worker, &PrinterWorker::convertImage);
|
||||||
|
@ -566,7 +566,7 @@ void IppPrinter::print(QJsonObject jobAttrs, QString filename)
|
||||||
getAttrOrDefault(jobAttrs, "media-bottom-margin", "media-col").toInt());
|
getAttrOrDefault(jobAttrs, "media-bottom-margin", "media-col").toInt());
|
||||||
|
|
||||||
// Only keep margin setting for JPEG - but only attemt to remove it if media-col exists
|
// Only keep margin setting for JPEG - but only attemt to remove it if media-col exists
|
||||||
if(!(mimeType == Mimer::JPEG && targetFormat == Mimer::JPEG) && jobAttrs.contains("media-col"))
|
if(!mimer->isImage(targetFormat) && jobAttrs.contains("media-col"))
|
||||||
{
|
{
|
||||||
QJsonObject MediaCol = jobAttrs["media-col"].toObject();
|
QJsonObject MediaCol = jobAttrs["media-col"].toObject();
|
||||||
QJsonObject MediaColValue = MediaCol["value"].toObject();
|
QJsonObject MediaColValue = MediaCol["value"].toObject();
|
||||||
|
@ -688,9 +688,9 @@ void IppPrinter::print(QJsonObject jobAttrs, QString filename)
|
||||||
{ // Can't process Postscript
|
{ // Can't process Postscript
|
||||||
emit doJustUpload(filename, contents);
|
emit doJustUpload(filename, contents);
|
||||||
}
|
}
|
||||||
else if((mimeType == targetFormat) && (targetFormat == Mimer::JPEG))
|
else if(mimer->isImage(targetFormat))
|
||||||
{ // Just make the jpeg baseline-encoded, don't resize locally
|
{ // Just make sure the image is in the desired format (and jpeg baseline-encoded), don't resize locally
|
||||||
emit doFixupJpeg(filename, contents);
|
emit doFixupImage(filename, contents, targetFormat);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -723,7 +723,7 @@ void IppPrinter::print(QJsonObject jobAttrs, QString filename)
|
||||||
}
|
}
|
||||||
else if (Mimer::isImage(mimeType))
|
else if (Mimer::isImage(mimeType))
|
||||||
{
|
{
|
||||||
emit doConvertImage(filename, contents, Params, targetFormat, margins);
|
emit doConvertImage(filename, contents, Params, margins);
|
||||||
}
|
}
|
||||||
else if(Mimer::isOffice(mimeType))
|
else if(Mimer::isOffice(mimeType))
|
||||||
{
|
{
|
||||||
|
|
|
@ -62,11 +62,11 @@ signals:
|
||||||
|
|
||||||
void doJustUpload(QString filename, Bytestream header);
|
void doJustUpload(QString filename, Bytestream header);
|
||||||
void doFixupPlaintext(QString filename, Bytestream header);
|
void doFixupPlaintext(QString filename, Bytestream header);
|
||||||
void doFixupJpeg(QString filename, Bytestream header);
|
void doFixupImage(QString filename, Bytestream header, QString targetFormat);
|
||||||
|
|
||||||
void doConvertPdf(QString filename, Bytestream header, PrintParameters Params);
|
void doConvertPdf(QString filename, Bytestream header, PrintParameters Params);
|
||||||
|
|
||||||
void doConvertImage(QString filename, Bytestream header, PrintParameters Params, QString targetFormat, QMargins margins);
|
void doConvertImage(QString filename, Bytestream header, PrintParameters Params, QMargins margins);
|
||||||
|
|
||||||
void doConvertOfficeDocument(QString filename, Bytestream header, PrintParameters Params);
|
void doConvertOfficeDocument(QString filename, Bytestream header, PrintParameters Params);
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,7 @@ const QString Mimer::ODP = "application/vnd.oasis.opendocument.presentation";
|
||||||
|
|
||||||
const QString Mimer::Plaintext = "text/plain";
|
const QString Mimer::Plaintext = "text/plain";
|
||||||
|
|
||||||
|
const QStringList Mimer::RasterFormats = {PWG, URF};
|
||||||
const QStringList Mimer::OfficeFormats = {DOC, DOCX, RTF, RTF_APP, ODT, PPT, PPTX, ODP};
|
const QStringList Mimer::OfficeFormats = {DOC, DOCX, RTF, RTF_APP, ODT, PPT, PPTX, ODP};
|
||||||
|
|
||||||
Mimer::Mimer()
|
Mimer::Mimer()
|
||||||
|
|
|
@ -61,11 +61,16 @@ public:
|
||||||
|
|
||||||
static const QString Plaintext;
|
static const QString Plaintext;
|
||||||
|
|
||||||
|
static const QStringList RasterFormats;
|
||||||
static const QStringList OfficeFormats;
|
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/") && ! isRaster(mimeType);
|
||||||
|
}
|
||||||
|
Q_INVOKABLE static bool isRaster(QString mimeType)
|
||||||
|
{
|
||||||
|
return RasterFormats.contains(mimeType);
|
||||||
}
|
}
|
||||||
Q_INVOKABLE static bool isOffice(QString mimeType)
|
Q_INVOKABLE static bool isOffice(QString mimeType)
|
||||||
{
|
{
|
||||||
|
|
|
@ -85,17 +85,54 @@ catch(const ConvertFailedException& e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PrinterWorker::fixupJpeg(QString filename, Bytestream header)
|
void PrinterWorker::fixupImage(QString filename, Bytestream header, QString targetFormat)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
|
QString imageFormat = "";
|
||||||
|
QStringList supportedImageFormats = {Mimer::JPEG, Mimer::PNG};
|
||||||
|
|
||||||
|
if(supportedImageFormats.contains(targetFormat))
|
||||||
|
{
|
||||||
|
imageFormat = targetFormat.split("/")[1];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw ConvertFailedException(tr("Unknown target format"));
|
||||||
|
}
|
||||||
|
|
||||||
|
QString mimeType = Mimer::instance()->get_type(filename);
|
||||||
|
Bytestream OutBts;
|
||||||
|
|
||||||
CurlRequester cr(_printer->httpUrl());
|
CurlRequester cr(_printer->httpUrl());
|
||||||
connect(&cr, &CurlRequester::done, _printer, &IppPrinter::printRequestFinished);
|
connect(&cr, &CurlRequester::done, _printer, &IppPrinter::printRequestFinished);
|
||||||
|
|
||||||
std::ifstream ifs = std::ifstream(filename.toStdString(), std::ios::in | std::ios::binary);
|
if(mimeType == Mimer::JPEG && targetFormat == Mimer::JPEG)
|
||||||
Bytestream InBts(ifs);
|
{
|
||||||
Bytestream OutBts;
|
std::ifstream ifs = std::ifstream(filename.toStdString(), std::ios::in | std::ios::binary);
|
||||||
|
Bytestream InBts(ifs);
|
||||||
|
|
||||||
baselinify(InBts, OutBts);
|
baselinify(InBts, OutBts);
|
||||||
|
}
|
||||||
|
else if(targetFormat == mimeType)
|
||||||
|
{
|
||||||
|
std::ifstream ifs = std::ifstream(filename.toStdString(), std::ios::in | std::ios::binary);
|
||||||
|
OutBts = Bytestream(ifs);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
QImage inImage;
|
||||||
|
QBuffer buf;
|
||||||
|
if(!inImage.load(filename))
|
||||||
|
{
|
||||||
|
qDebug() << "failed to load";
|
||||||
|
throw ConvertFailedException(tr("Failed to load image"));
|
||||||
|
}
|
||||||
|
buf.open(QIODevice::ReadWrite);
|
||||||
|
inImage.save(&buf, imageFormat.toStdString().c_str());
|
||||||
|
buf.seek(0);
|
||||||
|
OutBts = Bytestream(buf.size());
|
||||||
|
buf.read((char*)(OutBts.raw()), buf.size());
|
||||||
|
}
|
||||||
|
|
||||||
emit busyMessage(tr("Printing"));
|
emit busyMessage(tr("Printing"));
|
||||||
|
|
||||||
|
@ -192,17 +229,10 @@ catch(const ConvertFailedException& e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PrinterWorker::convertImage(QString filename, Bytestream header, PrintParameters Params, QString targetFormat, QMargins margins)
|
void PrinterWorker::convertImage(QString filename, Bytestream header, PrintParameters Params, QMargins margins)
|
||||||
{
|
{
|
||||||
try {
|
try {
|
||||||
|
|
||||||
QString imageFormat = "";
|
|
||||||
QStringList supportedImageFormats = {Mimer::JPEG, Mimer::PNG};
|
|
||||||
|
|
||||||
if(supportedImageFormats.contains(targetFormat))
|
|
||||||
{
|
|
||||||
imageFormat = targetFormat.split("/")[1];
|
|
||||||
}
|
|
||||||
|
|
||||||
if(Params.format == PrintParameters::URF && (Params.hwResW != Params.hwResH))
|
if(Params.format == PrintParameters::URF && (Params.hwResW != Params.hwResH))
|
||||||
{ // URF only supports symmetric resolutions
|
{ // URF only supports symmetric resolutions
|
||||||
|
@ -235,7 +265,7 @@ try {
|
||||||
inImage = inImage.scaled(Params.getPaperSizeWInPixels()-totalXMarginPx, Params.getPaperSizeHInPixels()-totalYMarginPx,
|
inImage = inImage.scaled(Params.getPaperSizeWInPixels()-totalXMarginPx, Params.getPaperSizeHInPixels()-totalYMarginPx,
|
||||||
Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
||||||
|
|
||||||
if(imageFormat == "" && (Params.format == PrintParameters::PDF || Params.format == PrintParameters::Postscript))
|
if(Params.format == PrintParameters::PDF || Params.format == PrintParameters::Postscript)
|
||||||
{
|
{
|
||||||
QTemporaryFile tmpPdfFile;
|
QTemporaryFile tmpPdfFile;
|
||||||
tmpPdfFile.open();
|
tmpPdfFile.open();
|
||||||
|
@ -267,45 +297,35 @@ try {
|
||||||
buf.open(QIODevice::ReadWrite);
|
buf.open(QIODevice::ReadWrite);
|
||||||
Bytestream outBts;
|
Bytestream outBts;
|
||||||
|
|
||||||
if(imageFormat != "")
|
|
||||||
{ // We are converting to a supported image format
|
if(inImage.allGray())
|
||||||
outImage.save(&buf, imageFormat.toStdString().c_str());
|
{
|
||||||
buf.seek(0);
|
Params.colors = 1; // No need to waste space/bandwidth...
|
||||||
outBts = Bytestream(buf.size());
|
|
||||||
buf.read((char*)(outBts.raw()), buf.size());
|
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{ // We are converting to a raster format
|
|
||||||
|
|
||||||
if(inImage.allGray())
|
outImage.save(&buf, Params.colors==1 ? "pgm" : "ppm");
|
||||||
{
|
buf.seek(0);
|
||||||
Params.colors = 1; // No need to waste space/bandwidth...
|
// Skip header - TODO consider reimplementing
|
||||||
}
|
buf.readLine(255);
|
||||||
|
buf.readLine(255);
|
||||||
|
buf.readLine(255);
|
||||||
|
|
||||||
outImage.save(&buf, Params.colors==1 ? "pgm" : "ppm");
|
Bytestream inBts(Params.getPaperSizeWInPixels() * Params.getPaperSizeHInPixels() * Params.colors);
|
||||||
buf.seek(0);
|
|
||||||
// Skip header - TODO consider reimplementing
|
|
||||||
buf.readLine(255);
|
|
||||||
buf.readLine(255);
|
|
||||||
buf.readLine(255);
|
|
||||||
|
|
||||||
Bytestream inBts(Params.getPaperSizeWInPixels() * Params.getPaperSizeHInPixels() * Params.colors);
|
if((((size_t)buf.size())-buf.pos()) != inBts.size())
|
||||||
|
{
|
||||||
if((((size_t)buf.size())-buf.pos()) != inBts.size())
|
qDebug() << buf.size() << buf.pos() << inBts.size();
|
||||||
{
|
throw ConvertFailedException();
|
||||||
qDebug() << buf.size() << buf.pos() << inBts.size();
|
|
||||||
throw ConvertFailedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
buf.read((char*)(inBts.raw()), inBts.size());
|
|
||||||
|
|
||||||
outBts << (Params.format == PrintParameters::URF ? make_urf_file_hdr(1) : make_pwg_file_hdr());
|
|
||||||
|
|
||||||
bool verbose = QLoggingCategory::defaultCategory()->isDebugEnabled();
|
|
||||||
|
|
||||||
bmp_to_pwg(inBts, outBts, 1, Params, verbose);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
buf.read((char*)(inBts.raw()), inBts.size());
|
||||||
|
|
||||||
|
outBts << (Params.format == PrintParameters::URF ? make_urf_file_hdr(1) : make_pwg_file_hdr());
|
||||||
|
|
||||||
|
bool verbose = QLoggingCategory::defaultCategory()->isDebugEnabled();
|
||||||
|
|
||||||
|
bmp_to_pwg(inBts, outBts, 1, Params, verbose);
|
||||||
|
|
||||||
CurlRequester cr(_printer->httpUrl());
|
CurlRequester cr(_printer->httpUrl());
|
||||||
connect(&cr, &CurlRequester::done, _printer, &IppPrinter::printRequestFinished);
|
connect(&cr, &CurlRequester::done, _printer, &IppPrinter::printRequestFinished);
|
||||||
|
|
||||||
|
|
|
@ -40,13 +40,13 @@ public slots:
|
||||||
|
|
||||||
void justUpload(QString filename, Bytestream header);
|
void justUpload(QString filename, Bytestream header);
|
||||||
|
|
||||||
void fixupJpeg(QString filename, Bytestream header);
|
void fixupImage(QString filename, Bytestream header, QString targetFormat);
|
||||||
|
|
||||||
void fixupPlaintext(QString filename, Bytestream header);
|
void fixupPlaintext(QString filename, Bytestream header);
|
||||||
|
|
||||||
void convertPdf(QString filename, Bytestream header, PrintParameters Params);
|
void convertPdf(QString filename, Bytestream header, PrintParameters Params);
|
||||||
|
|
||||||
void convertImage(QString filename, Bytestream header, PrintParameters Params, QString targetFormat, QMargins margins);
|
void convertImage(QString filename, Bytestream header, PrintParameters Params, QMargins margins);
|
||||||
|
|
||||||
void convertOfficeDocument(QString filename, Bytestream header, PrintParameters Params);
|
void convertOfficeDocument(QString filename, Bytestream header, PrintParameters Params);
|
||||||
|
|
||||||
|
|
|
@ -520,6 +520,10 @@ auf diesem Drucker</translation>
|
||||||
<source>Upload error</source>
|
<source>Upload error</source>
|
||||||
<translation>Übertragungsfehler</translation>
|
<translation>Übertragungsfehler</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Unknown target format</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>RangeSetting</name>
|
<name>RangeSetting</name>
|
||||||
|
|
|
@ -519,6 +519,10 @@
|
||||||
<source>Upload error</source>
|
<source>Upload error</source>
|
||||||
<translation>Error de carga</translation>
|
<translation>Error de carga</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Unknown target format</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>RangeSetting</name>
|
<name>RangeSetting</name>
|
||||||
|
|
|
@ -520,6 +520,10 @@ sur cette imprimante</translation>
|
||||||
<source>Upload error</source>
|
<source>Upload error</source>
|
||||||
<translation>Erreur de chargement</translation>
|
<translation>Erreur de chargement</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Unknown target format</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>RangeSetting</name>
|
<name>RangeSetting</name>
|
||||||
|
|
|
@ -519,6 +519,10 @@
|
||||||
<source>Upload error</source>
|
<source>Upload error</source>
|
||||||
<translation>Uploadfout</translation>
|
<translation>Uploadfout</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Unknown target format</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>RangeSetting</name>
|
<name>RangeSetting</name>
|
||||||
|
|
|
@ -519,6 +519,10 @@
|
||||||
<source>Upload error</source>
|
<source>Upload error</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Unknown target format</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>RangeSetting</name>
|
<name>RangeSetting</name>
|
||||||
|
|
|
@ -519,6 +519,10 @@
|
||||||
<source>Upload error</source>
|
<source>Upload error</source>
|
||||||
<translation type="unfinished"></translation>
|
<translation type="unfinished"></translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<source>Unknown target format</source>
|
||||||
|
<translation type="unfinished"></translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>RangeSetting</name>
|
<name>RangeSetting</name>
|
||||||
|
|
Loading…
Reference in a new issue