Add OptimizedWrite & ProgressiveScanWrite options to QImageIOHandler and use for JPEG writing
Exposes two options from libjpeg: the optimize option and progressive scan option. These are both lossless operations, so they do not change the image's quality. Using these switches can result in smaller jpeg files. Task-number: QTBUG-20075 Change-Id: I8d0bd6a712b8a365265b7bd517e136b0755b90cb Reviewed-by: Gunnar Sletta <gunnar@sletta.org> Reviewed-by: aavit <eirik.aavitsland@theqtcompany.com>
This commit is contained in:
parent
fc5e6b37a1
commit
163af2cf53
@ -153,6 +153,12 @@
|
||||
\value SupportedSubTypes Image formats that support different saving
|
||||
variants should return a list of supported variant names
|
||||
(QList<QByteArray>) in this option.
|
||||
|
||||
\value OptimizedWrite. A handler which supports this option
|
||||
is expected to turn on optimization flags when writing.
|
||||
|
||||
\value ProgressiveScanWrite. A handler which supports
|
||||
this option is expected to write the image as a progressive scan image.
|
||||
*/
|
||||
|
||||
/*!
|
||||
|
@ -84,7 +84,9 @@ public:
|
||||
Animation,
|
||||
BackgroundColor,
|
||||
ImageFormat,
|
||||
SupportedSubTypes
|
||||
SupportedSubTypes,
|
||||
OptimizedWrite,
|
||||
ProgressiveScanWrite
|
||||
};
|
||||
virtual QVariant option(ImageOption option) const;
|
||||
virtual void setOption(ImageOption option, const QVariant &value);
|
||||
|
@ -252,6 +252,8 @@ public:
|
||||
QString description;
|
||||
QString text;
|
||||
QByteArray subType;
|
||||
bool optimizedWrite;
|
||||
bool progressiveScanWrite;
|
||||
|
||||
// error
|
||||
QImageWriter::ImageWriterError imageWriterError;
|
||||
@ -271,6 +273,8 @@ QImageWriterPrivate::QImageWriterPrivate(QImageWriter *qq)
|
||||
quality = -1;
|
||||
compression = 0;
|
||||
gamma = 0.0;
|
||||
optimizedWrite = false;
|
||||
progressiveScanWrite = false;
|
||||
imageWriterError = QImageWriter::UnknownError;
|
||||
errorString = QImageWriter::tr("Unknown error");
|
||||
|
||||
@ -554,6 +558,63 @@ QList<QByteArray> QImageWriter::supportedSubTypes() const
|
||||
return d->handler->option(QImageIOHandler::SupportedSubTypes).value< QList<QByteArray> >();
|
||||
}
|
||||
|
||||
/*!
|
||||
\since 5.5
|
||||
|
||||
This is an image format-specific function which sets the \a optimize flags when
|
||||
writing images. For image formats that do not support setting an \a optimize flag,
|
||||
this value is ignored.
|
||||
|
||||
The default is false.
|
||||
|
||||
\sa optimizedWrite()
|
||||
*/
|
||||
void QImageWriter::setOptimizedWrite(bool optimize)
|
||||
{
|
||||
d->optimizedWrite = optimize;
|
||||
}
|
||||
|
||||
/*!
|
||||
\since 5.5
|
||||
|
||||
Returns whether optimization has been turned on for writing the image.
|
||||
|
||||
\sa setOptimizedWrite()
|
||||
*/
|
||||
bool QImageWriter::optimizedWrite() const
|
||||
{
|
||||
return d->optimizedWrite;
|
||||
}
|
||||
|
||||
/*!
|
||||
\since 5.5
|
||||
|
||||
This is an image format-specific function which turns on \a progressive scanning
|
||||
when writing images. For image formats that do not support setting a \a progressive
|
||||
scan flag, this value is ignored.
|
||||
|
||||
The default is false.
|
||||
|
||||
\sa progressiveScanWrite()
|
||||
*/
|
||||
|
||||
void QImageWriter::setProgressiveScanWrite(bool progressive)
|
||||
{
|
||||
d->progressiveScanWrite = progressive;
|
||||
}
|
||||
|
||||
/*!
|
||||
\since 5.5
|
||||
|
||||
Returns whether the image should be written as a progressive image.
|
||||
|
||||
\sa setProgressiveScanWrite()
|
||||
*/
|
||||
bool QImageWriter::progressiveScanWrite() const
|
||||
{
|
||||
return d->progressiveScanWrite;
|
||||
}
|
||||
|
||||
/*!
|
||||
\obsolete
|
||||
|
||||
@ -657,6 +718,10 @@ bool QImageWriter::write(const QImage &image)
|
||||
d->handler->setOption(QImageIOHandler::Description, d->description);
|
||||
if (!d->subType.isEmpty() && d->handler->supportsOption(QImageIOHandler::SubType))
|
||||
d->handler->setOption(QImageIOHandler::SubType, d->subType);
|
||||
if (d->handler->supportsOption(QImageIOHandler::OptimizedWrite))
|
||||
d->handler->setOption(QImageIOHandler::OptimizedWrite, d->optimizedWrite);
|
||||
if (d->handler->supportsOption(QImageIOHandler::ProgressiveScanWrite))
|
||||
d->handler->setOption(QImageIOHandler::ProgressiveScanWrite, d->progressiveScanWrite);
|
||||
|
||||
if (!d->handler->write(image))
|
||||
return false;
|
||||
|
@ -83,6 +83,12 @@ public:
|
||||
QByteArray subType() const;
|
||||
QList<QByteArray> supportedSubTypes() const;
|
||||
|
||||
void setOptimizedWrite(bool optimize);
|
||||
bool optimizedWrite() const;
|
||||
|
||||
void setProgressiveScanWrite(bool progressive);
|
||||
bool progressiveScanWrite() const;
|
||||
|
||||
// Obsolete as of 4.1
|
||||
void setDescription(const QString &description);
|
||||
QString description() const;
|
||||
|
@ -538,7 +538,7 @@ static inline void set_text(const QImage &image, j_compress_ptr cinfo, const QSt
|
||||
}
|
||||
}
|
||||
|
||||
static bool write_jpeg_image(const QImage &image, QIODevice *device, volatile int sourceQuality, const QString &description)
|
||||
static bool write_jpeg_image(const QImage &image, QIODevice *device, volatile int sourceQuality, const QString &description, bool optimize, bool progressive)
|
||||
{
|
||||
bool success = false;
|
||||
const QVector<QRgb> cmap = image.colorTable();
|
||||
@ -607,6 +607,11 @@ static bool write_jpeg_image(const QImage &image, QIODevice *device, volatile in
|
||||
cinfo.Y_density = (image.dotsPerMeterY()+50) / 100;
|
||||
}
|
||||
|
||||
if (optimize)
|
||||
cinfo.optimize_coding = true;
|
||||
|
||||
if (progressive)
|
||||
jpeg_simple_progression(&cinfo);
|
||||
|
||||
int quality = sourceQuality >= 0 ? qMin(int(sourceQuality),100) : 75;
|
||||
jpeg_set_quality(&cinfo, quality, TRUE /* limit to baseline-JPEG values */);
|
||||
@ -729,7 +734,7 @@ public:
|
||||
};
|
||||
|
||||
QJpegHandlerPrivate(QJpegHandler *qq)
|
||||
: quality(75), exifOrientation(1), iod_src(0), state(Ready), q(qq)
|
||||
: quality(75), exifOrientation(1), iod_src(0), state(Ready), optimize(false), progressive(false), q(qq)
|
||||
{}
|
||||
|
||||
~QJpegHandlerPrivate()
|
||||
@ -762,6 +767,9 @@ public:
|
||||
|
||||
State state;
|
||||
|
||||
bool optimize;
|
||||
bool progressive;
|
||||
|
||||
QJpegHandler *q;
|
||||
};
|
||||
|
||||
@ -1066,7 +1074,7 @@ bool QJpegHandler::read(QImage *image)
|
||||
|
||||
bool QJpegHandler::write(const QImage &image)
|
||||
{
|
||||
return write_jpeg_image(image, device(), d->quality, d->description);
|
||||
return write_jpeg_image(image, device(), d->quality, d->description, d->optimize, d->progressive);
|
||||
}
|
||||
|
||||
bool QJpegHandler::supportsOption(ImageOption option) const
|
||||
@ -1077,7 +1085,9 @@ bool QJpegHandler::supportsOption(ImageOption option) const
|
||||
|| option == ClipRect
|
||||
|| option == Description
|
||||
|| option == Size
|
||||
|| option == ImageFormat;
|
||||
|| option == ImageFormat
|
||||
|| option == OptimizedWrite
|
||||
|| option == ProgressiveScanWrite;
|
||||
}
|
||||
|
||||
QVariant QJpegHandler::option(ImageOption option) const
|
||||
@ -1100,6 +1110,10 @@ QVariant QJpegHandler::option(ImageOption option) const
|
||||
case ImageFormat:
|
||||
d->readJpegHeader(device());
|
||||
return d->format;
|
||||
case OptimizedWrite:
|
||||
return d->optimize;
|
||||
case ProgressiveScanWrite:
|
||||
return d->progressive;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -1125,6 +1139,12 @@ void QJpegHandler::setOption(ImageOption option, const QVariant &value)
|
||||
case Description:
|
||||
d->description = value.toString();
|
||||
break;
|
||||
case OptimizedWrite:
|
||||
d->optimize = value.toBool();
|
||||
break;
|
||||
case ProgressiveScanWrite:
|
||||
d->progressive = value.toBool();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user