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:
Andy Maloney 2015-01-02 09:48:44 -05:00 committed by Giuseppe D'Angelo
parent fc5e6b37a1
commit 163af2cf53
5 changed files with 104 additions and 5 deletions

View File

@ -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.
*/
/*!

View File

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

View File

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

View File

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

View File

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