diff options
author | Rhys Weatherley <rhys.weatherley@nokia.com> | 2009-12-23 05:10:15 (GMT) |
---|---|---|
committer | Rhys Weatherley <rhys.weatherley@nokia.com> | 2009-12-23 05:10:15 (GMT) |
commit | 61f214e60a074cbaf2413b2c77ed5a4cfd638edb (patch) | |
tree | e92442160ea6df2cbae30621c1727b9a689675bc /src | |
parent | 762496dba277f31e55a216c9761a51bf306adec0 (diff) | |
download | Qt-61f214e60a074cbaf2413b2c77ed5a4cfd638edb.zip Qt-61f214e60a074cbaf2413b2c77ed5a4cfd638edb.tar.gz Qt-61f214e60a074cbaf2413b2c77ed5a4cfd638edb.tar.bz2 |
Implement ScaledClipRect in the jpeg image plugin
Where possible, we convert the post-scale clip rectangle into a
pre-scale clip rectangle because it is more efficient to clip first.
Task-number: QT-2023
Reviewed-by: Sarah Smith
Reviewed-by: Daniel Pope
Diffstat (limited to 'src')
-rw-r--r-- | src/plugins/imageformats/jpeg/qjpeghandler.cpp | 55 | ||||
-rw-r--r-- | src/plugins/imageformats/jpeg/qjpeghandler.h | 1 |
2 files changed, 47 insertions, 9 deletions
diff --git a/src/plugins/imageformats/jpeg/qjpeghandler.cpp b/src/plugins/imageformats/jpeg/qjpeghandler.cpp index 7165c38..11608ef 100644 --- a/src/plugins/imageformats/jpeg/qjpeghandler.cpp +++ b/src/plugins/imageformats/jpeg/qjpeghandler.cpp @@ -721,8 +721,8 @@ static bool ensureValidImage(QImage *dest, struct jpeg_decompress_struct *info, } static bool read_jpeg_image(QIODevice *device, QImage *outImage, - QSize scaledSize, const QRect& clipRect, - int inQuality ) + QSize scaledSize, QRect scaledClipRect, + QRect clipRect, int inQuality ) { struct jpeg_decompress_struct cinfo; @@ -748,6 +748,42 @@ static bool read_jpeg_image(QIODevice *device, QImage *outImage, if (quality < 0) quality = 75; + // If possible, merge the scaledClipRect into either scaledSize + // or clipRect to avoid doing a separate scaled clipping pass. + // Best results are achieved by clipping before scaling, not after. + if (!scaledClipRect.isEmpty()) { + if (scaledSize.isEmpty() && clipRect.isEmpty()) { + // No clipping or scaling before final clip. + clipRect = scaledClipRect; + scaledClipRect = QRect(); + } else if (scaledSize.isEmpty()) { + // Clipping, but no scaling: combine the clip regions. + scaledClipRect.translate(clipRect.topLeft()); + clipRect = scaledClipRect.intersected(clipRect); + scaledClipRect = QRect(); + } else if (clipRect.isEmpty()) { + // No clipping, but scaling: if we can map back to an + // integer pixel boundary, then clip before scaling. + if ((cinfo.image_width % scaledSize.width()) == 0 && + (cinfo.image_height % scaledSize.height()) == 0) { + int x = scaledClipRect.x() * cinfo.image_width / + scaledSize.width(); + int y = scaledClipRect.y() * cinfo.image_height / + scaledSize.height(); + int width = (scaledClipRect.right() + 1) * + cinfo.image_width / scaledSize.width() - x; + int height = (scaledClipRect.bottom() + 1) * + cinfo.image_height / scaledSize.height() - y; + clipRect = QRect(x, y, width, height); + scaledSize = scaledClipRect.size(); + scaledClipRect = QRect(); + } + } else { + // Clipping and scaling: too difficult to figure out, + // and not a likely use case, so do it the long way. + } + } + // Determine the scale factor to pass to libjpeg for quick downscaling. if (!scaledSize.isEmpty()) { if (clipRect.isEmpty()) { @@ -900,6 +936,8 @@ static bool read_jpeg_image(QIODevice *device, QImage *outImage, jpeg_destroy_decompress(&cinfo); delete iod_src; + if (!scaledClipRect.isEmpty()) + *outImage = outImage->copy(scaledClipRect); return !outImage->isNull(); } @@ -1157,7 +1195,7 @@ bool QJpegHandler::read(QImage *image) { if (!canRead()) return false; - return read_jpeg_image(device(), image, scaledSize, clipRect, quality); + return read_jpeg_image(device(), image, scaledSize, scaledClipRect, clipRect, quality); } bool QJpegHandler::write(const QImage &image) @@ -1168,9 +1206,8 @@ bool QJpegHandler::write(const QImage &image) bool QJpegHandler::supportsOption(ImageOption option) const { return option == Quality -#ifndef QT_NO_IMAGE_SMOOTHSCALE || option == ScaledSize -#endif + || option == ScaledClipRect || option == ClipRect || option == Size || option == ImageFormat; @@ -1180,10 +1217,10 @@ QVariant QJpegHandler::option(ImageOption option) const { if (option == Quality) { return quality; -#ifndef QT_NO_IMAGE_SMOOTHSCALE } else if (option == ScaledSize) { return scaledSize; -#endif + } else if (option == ScaledClipRect) { + return scaledClipRect; } else if (option == ClipRect) { return clipRect; } else if (option == Size) { @@ -1212,10 +1249,10 @@ void QJpegHandler::setOption(ImageOption option, const QVariant &value) { if (option == Quality) quality = value.toInt(); -#ifndef QT_NO_IMAGE_SMOOTHSCALE else if ( option == ScaledSize ) scaledSize = value.toSize(); -#endif + else if ( option == ScaledClipRect ) + scaledClipRect = value.toRect(); else if ( option == ClipRect ) clipRect = value.toRect(); } diff --git a/src/plugins/imageformats/jpeg/qjpeghandler.h b/src/plugins/imageformats/jpeg/qjpeghandler.h index 108b131..6870cd6 100644 --- a/src/plugins/imageformats/jpeg/qjpeghandler.h +++ b/src/plugins/imageformats/jpeg/qjpeghandler.h @@ -68,6 +68,7 @@ public: private: int quality; QSize scaledSize; + QRect scaledClipRect; QRect clipRect; }; |