Stop resizing images when transferred as such

This commit is contained in:
Anton Thomasson 2022-05-16 21:52:00 +02:00
parent ff2eae04cf
commit 08b66ed711
14 changed files with 116 additions and 63 deletions

View file

@ -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:

View file

@ -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 {

View file

@ -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))
{ {

View file

@ -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);

View file

@ -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()

View file

@ -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)
{ {

View file

@ -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);

View file

@ -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);

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>

View file

@ -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>