Support more scaling factors for JPEG decompression

Since libjpeg 7, decompression scaling factors of [1,16]/8 have
been supported. Upscaling is slower, but using the entire range
of downscaling factors is significantly faster for sizes between
the power-of-two factors.

Time to decompress a 5184x3456 image and scale to 1900x1200,
slightly less than 3/8ths, changes from 251ms to 203ms.

libjpeg versions prior to 7 will round up to the next largest
factor they support, and continue to work as before.

Change-Id: I00a0655df2ef057e739927a643bfe0b0cabd5602
Reviewed-by: Robin Burchell <robin+qt@viroteck.net>
Reviewed-by: aavit <qt_aavit@ovi.com>
This commit is contained in:
John Brooks 2012-04-10 22:52:49 -06:00 committed by Qt by Nokia
parent 011b88a7b3
commit 56ff31f0c1

View File

@ -45,6 +45,7 @@
#include <qvariant.h> #include <qvariant.h>
#include <qvector.h> #include <qvector.h>
#include <qbuffer.h> #include <qbuffer.h>
#include <qmath.h>
#include <private/qsimd_p.h> #include <private/qsimd_p.h>
#include <stdio.h> // jpeglib needs this to be pre-included #include <stdio.h> // jpeglib needs this to be pre-included
@ -321,27 +322,31 @@ static bool read_jpeg_image(QImage *outImage,
} }
// Determine the scale factor to pass to libjpeg for quick downscaling. // Determine the scale factor to pass to libjpeg for quick downscaling.
if (!scaledSize.isEmpty()) { if (!scaledSize.isEmpty() && info->image_width && info->image_height) {
if (clipRect.isEmpty()) { if (clipRect.isEmpty()) {
info->scale_denom = double f = qMin(double(info->image_width) / scaledSize.width(),
qMin(info->image_width / scaledSize.width(), double(info->image_height) / scaledSize.height());
info->image_height / scaledSize.height());
} else { // libjpeg supports M/8 scaling with M=[1,16]. All downscaling factors
info->scale_denom = // are a speed improvement, but upscaling during decode is slower.
qMin(clipRect.width() / scaledSize.width(), info->scale_num = qBound(1, qCeil(8/f), 8);
clipRect.height() / scaledSize.height());
}
if (info->scale_denom < 2) {
info->scale_denom = 1;
} else if (info->scale_denom < 4) {
info->scale_denom = 2;
} else if (info->scale_denom < 8) {
info->scale_denom = 4;
} else {
info->scale_denom = 8; info->scale_denom = 8;
} } else {
info->scale_num = 1; info->scale_denom = qMin(clipRect.width() / scaledSize.width(),
if (!clipRect.isEmpty()) { clipRect.height() / scaledSize.height());
// Only scale by powers of two when clipping so we can
// keep the exact pixel boundaries
if (info->scale_denom < 2)
info->scale_denom = 1;
else if (info->scale_denom < 4)
info->scale_denom = 2;
else if (info->scale_denom < 8)
info->scale_denom = 4;
else
info->scale_denom = 8;
info->scale_num = 1;
// Correct the scale factor so that we clip accurately. // Correct the scale factor so that we clip accurately.
// It is recommended that the clip rectangle be aligned // It is recommended that the clip rectangle be aligned
// on an 8-pixel boundary for best performance. // on an 8-pixel boundary for best performance.