src/plugins/imageformats/jpeg/qjpeghandler.cpp
branchRCL_3
changeset 4 3b1da2848fc7
parent 3 41300fa6a67c
child 8 3f74d0d4af4c
--- a/src/plugins/imageformats/jpeg/qjpeghandler.cpp	Tue Feb 02 00:43:10 2010 +0200
+++ b/src/plugins/imageformats/jpeg/qjpeghandler.cpp	Fri Feb 19 23:40:16 2010 +0200
@@ -1,6 +1,6 @@
 /****************************************************************************
 **
-** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
 ** All rights reserved.
 ** Contact: Nokia Corporation (qt-info@nokia.com)
 **
@@ -84,15 +84,12 @@
 public:
     QImageSmoothScaler(const int w, const int h, const QImage &src);
     QImageSmoothScaler(const int srcWidth, const int srcHeight,
-                       const char *parameters);
+                       const int dstWidth, const int dstHeight);
 
     virtual ~QImageSmoothScaler(void);
 
     QImage  scale();
 
-protected:
-    int scaledWidth(void) const;
-
 private:
     QImageSmoothScalerPrivate	*d;
     virtual QRgb *scanLine(const int line = 0, const QImage *src = 0);
@@ -123,33 +120,9 @@
 }
 
 QImageSmoothScaler::QImageSmoothScaler(const int srcWidth, const int srcHeight,
-                                       const char *parameters)
+                                       const int dstWidth, const int dstHeight)
 {
-    char    sModeStr[1024];
-    int	    t1;
-    int	    t2;
-    int	    dstWidth;
-    int	    dstHeight;
-
-    sModeStr[0] = '\0';
-
     d = new QImageSmoothScalerPrivate;
-#if defined(Q_OS_WIN) && !defined(Q_OS_WINCE) && defined(_MSC_VER) && _MSC_VER >= 1400
-    sscanf_s(parameters, "Scale( %i, %i, %1023s )", &dstWidth, &dstHeight, sModeStr, sizeof(sModeStr));
-#else
-    sscanf(parameters, "Scale( %i, %i, %s )", &dstWidth, &dstHeight, sModeStr);
-#endif
-    QString sModeQStr = QString::fromLatin1(sModeStr);
-
-    t1 = srcWidth * dstHeight;
-    t2 = srcHeight * dstWidth;
-
-    if (((sModeQStr == QLatin1String("ScaleMin")) && (t1 > t2)) || ((sModeQStr == QLatin1String("ScaleMax")) && (t2 < t2))) {
-	dstHeight = t2 / srcWidth;
-    } else if (sModeQStr != QLatin1String("ScaleFree")) {
-	dstWidth = t1 / srcHeight;
-    }
-
     d->setup(srcWidth, srcHeight, dstWidth, dstHeight, 0);
 }
 
@@ -164,11 +137,6 @@
     hasAlpha = hasAlphaChannel;
 }
 
-int QImageSmoothScaler::scaledWidth() const
-{
-    return d->cols;
-}
-
 QImageSmoothScaler::~QImageSmoothScaler()
 {
     delete d;
@@ -467,20 +435,18 @@
 class jpegSmoothScaler : public QImageSmoothScaler
 {
 public:
-    jpegSmoothScaler(struct jpeg_decompress_struct *info, const char *params):
-	QImageSmoothScaler(info->output_width, info->output_height, params)
+    jpegSmoothScaler(struct jpeg_decompress_struct *info, const QSize& dstSize, const QRect& clipRect)
+        : QImageSmoothScaler(clipRect.width(), clipRect.height(),
+                             dstSize.width(), dstSize.height())
     {
-	cinfo = info;
-	cols24Bit = scaledWidth() * 3;
-
-	cacheHeight = 1;
-	imageCache = QImage( info->output_width, cacheHeight, QImage::Format_RGB32 );
+        cinfo = info;
+        clip = clipRect;
+        imageCache = QImage(info->output_width, 1, QImage::Format_RGB32);
     }
 
 private:
-    int	    cols24Bit;
+    QRect   clip;
     QImage  imageCache;
-    int	    cacheHeight;
     struct jpeg_decompress_struct *cinfo;
 
     QRgb *scanLine(const int line = 0, const QImage *src = 0)
@@ -492,33 +458,42 @@
 	Q_UNUSED(src);
 
         uchar* data = imageCache.bits();
+
+        // Read ahead if we haven't reached the first clipped scanline yet.
+        while (int(cinfo->output_scanline) < clip.y() &&
+               cinfo->output_scanline < cinfo->output_height)
+	    jpeg_read_scanlines(cinfo, &data, 1);
+
+        // Read the next scanline.  We assume that "line"
+        // will never be >= clip.height().
 	jpeg_read_scanlines(cinfo, &data, 1);
-	out = (QRgb*)imageCache.scanLine(0);
+        if (cinfo->output_scanline == cinfo->output_height)
+            jpeg_finish_decompress(cinfo);
+
+	out = ((QRgb*)data) + clip.x();
 
 	//
 	// The smooth scale algorithm only works on 32-bit images;
 	// convert from (8|24) bits to 32.
 	//
 	if (cinfo->output_components == 1) {
-	    in = (uchar*)out + scaledWidth();
-	    for (uint i = scaledWidth(); i--; ) {
+	    in = data + clip.right();
+	    for (int i = clip.width(); i--; ) {
+		out[i] = qRgb(*in, *in, *in);
 		in--;
-		out[i] = qRgb(*in, *in, *in);
 	    }
-       } else if (cinfo->out_color_space == JCS_CMYK) {
-           int cols32Bit = scaledWidth() * 4;
-           in = (uchar*)out + cols32Bit;
-           for (uint i = scaledWidth(); i--; ) {
-               in -= 4;
-               int k = in[3];
-               out[i] = qRgb(k * in[0] / 255, k * in[1] / 255, k * in[2] / 255);
-               //out[i] = qRgb(in[0], in[1], in[2]);
-           }
-       } else {
-	    in = (uchar*)out + cols24Bit;
-	    for (uint i = scaledWidth(); i--; ) {
+        } else if (cinfo->out_color_space == JCS_CMYK) {
+            in = data + clip.right() * 4;
+            for (int i = clip.width(); i--; ) {
+                int k = in[3];
+                out[i] = qRgb(k * in[0] / 255, k * in[1] / 255, k * in[2] / 255);
+                in -= 4;
+            }
+        } else {
+	    in = data + clip.right() * 3;
+	    for (int i = clip.width(); i--; ) {
+		out[i] = qRgb(in[0], in[1], in[2]);
 		in -= 3;
-		out[i] = qRgb(in[0], in[1], in[2]);
 	    }
 	}
 
@@ -637,18 +612,6 @@
 }
 
 
-static void scaleSize(int &reqW, int &reqH, int imgW, int imgH, Qt::AspectRatioMode mode)
-{
-    if (mode == Qt::IgnoreAspectRatio)
-        return;
-    int t1 = imgW * reqH;
-    int t2 = reqW * imgH;
-    if ((mode == Qt::KeepAspectRatio && (t1 > t2)) || (mode == Qt::KeepAspectRatioByExpanding && (t1 < t2)))
-        reqH = t2 / imgW;
-    else
-        reqW = t1 / imgH;
-}
-
 static bool read_jpeg_size(QIODevice *device, int &w, int &h)
 {
     bool rt = false;
@@ -729,7 +692,7 @@
 }
 
 static bool ensureValidImage(QImage *dest, struct jpeg_decompress_struct *info,
-                             bool dummy = false)
+                             const QSize& size)
 {
     QImage::Format format;
     switch (info->output_components) {
@@ -744,13 +707,8 @@
         return false; // unsupported format
     }
 
-    const QSize size(info->output_width, info->output_height);
     if (dest->size() != size || dest->format() != format) {
-        static uchar dummyImage[1];
-        if (dummy) // Create QImage but don't read the pixels
-            *dest = QImage(dummyImage, size.width(), size.height(), format);
-        else
-            *dest = QImage(size, format);
+        *dest = QImage(size, format);
 
         if (format == QImage::Format_Indexed8) {
             dest->setColorCount(256);
@@ -763,13 +721,9 @@
 }
 
 static bool read_jpeg_image(QIODevice *device, QImage *outImage,
-                            const QByteArray &parameters, QSize scaledSize,
-                            int inQuality )
+                            QSize scaledSize, QRect scaledClipRect,
+                            QRect clipRect, int inQuality )
 {
-#ifdef QT_NO_IMAGE_SMOOTHSCALE
-    Q_UNUSED( scaledSize );
-#endif
-
     struct jpeg_decompress_struct cinfo;
 
     struct my_jpeg_source_mgr *iod_src = new my_jpeg_source_mgr(device);
@@ -794,18 +748,53 @@
         if (quality < 0)
             quality = 75;
 
-        QString params = QString::fromLatin1(parameters);
-        params.simplified();
-        int sWidth = 0, sHeight = 0;
-        char sModeStr[1024] = "";
-        Qt::AspectRatioMode sMode;
+        // 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.
+            }
+        }
 
-#ifndef QT_NO_IMAGE_SMOOTHSCALE
-        // If high quality not required, shrink image during decompression
-        if (scaledSize.isValid() && !scaledSize.isEmpty() && quality < HIGH_QUALITY_THRESHOLD
-            && !params.contains(QLatin1String("GetHeaderInformation")) ) {
-            cinfo.scale_denom = qMin(cinfo.image_width / scaledSize.width(),
-                                     cinfo.image_width / scaledSize.height());
+        // Determine the scale factor to pass to libjpeg for quick downscaling.
+        if (!scaledSize.isEmpty()) {
+            if (clipRect.isEmpty()) {
+                cinfo.scale_denom =
+                    qMin(cinfo.image_width / scaledSize.width(),
+                         cinfo.image_height / scaledSize.height());
+            } else {
+                cinfo.scale_denom =
+                    qMin(clipRect.width() / scaledSize.width(),
+                         clipRect.height() / scaledSize.height());
+            }
             if (cinfo.scale_denom < 2) {
                 cinfo.scale_denom = 1;
             } else if (cinfo.scale_denom < 4) {
@@ -816,9 +805,19 @@
                 cinfo.scale_denom = 8;
             }
             cinfo.scale_num = 1;
+            if (!clipRect.isEmpty()) {
+                // Correct the scale factor so that we clip accurately.
+                // It is recommended that the clip rectangle be aligned
+                // on an 8-pixel boundary for best performance.
+                while (cinfo.scale_denom > 1 &&
+                       ((clipRect.x() % cinfo.scale_denom) != 0 ||
+                        (clipRect.y() % cinfo.scale_denom) != 0 ||
+                        (clipRect.width() % cinfo.scale_denom) != 0 ||
+                        (clipRect.height() % cinfo.scale_denom) != 0)) {
+                    cinfo.scale_denom /= 2;
+                }
+            }
         }
-#endif
-
 
         // If high quality not required, use fast decompression
         if( quality < HIGH_QUALITY_THRESHOLD ) {
@@ -826,132 +825,102 @@
             cinfo.do_fancy_upsampling = FALSE;
         }
 
-
-        (void) jpeg_start_decompress(&cinfo);
-
-        if (params.contains(QLatin1String("GetHeaderInformation"))) {
-            if (!ensureValidImage(outImage, &cinfo, true))
-                longjmp(jerr.setjmp_buffer, 1);
-        } else if (params.contains(QLatin1String("Scale"))) {
-#if defined(_MSC_VER) && _MSC_VER >= 1400 && !defined(Q_OS_WINCE)
-            sscanf_s(params.toLatin1().data(), "Scale(%i, %i, %1023s)",
-                     &sWidth, &sHeight, sModeStr, sizeof(sModeStr));
-#else
-            sscanf(params.toLatin1().data(), "Scale(%i, %i, %1023s)",
-                   &sWidth, &sHeight, sModeStr);
-#endif
+        (void) jpeg_calc_output_dimensions(&cinfo);
 
-            QString sModeQStr(QString::fromLatin1(sModeStr));
-            if (sModeQStr == QLatin1String("IgnoreAspectRatio")) {
-                sMode = Qt::IgnoreAspectRatio;
-            } else if (sModeQStr == QLatin1String("KeepAspectRatio")) {
-                sMode = Qt::KeepAspectRatio;
-            } else if (sModeQStr == QLatin1String("KeepAspectRatioByExpanding")) {
-                sMode = Qt::KeepAspectRatioByExpanding;
-            } else {
-                qDebug("read_jpeg_image: invalid aspect ratio mode \"%s\", see QImage::AspectRatioMode documentation", sModeStr);
-                sMode = Qt::KeepAspectRatio;
-            }
+        // Determine the clip region to extract.
+        QRect imageRect(0, 0, cinfo.output_width, cinfo.output_height);
+        QRect clip;
+        if (clipRect.isEmpty()) {
+            clip = imageRect;
+        } else if (cinfo.scale_denom == 1) {
+            clip = clipRect.intersected(imageRect);
+        } else {
+            // The scale factor was corrected above to ensure that
+            // we don't miss pixels when we scale the clip rectangle.
+            clip = QRect(clipRect.x() / int(cinfo.scale_denom),
+                         clipRect.y() / int(cinfo.scale_denom),
+                         clipRect.width() / int(cinfo.scale_denom),
+                         clipRect.height() / int(cinfo.scale_denom));
+            clip = clip.intersected(imageRect);
+        }
 
-//            qDebug("Parameters ask to scale the image to %i x %i AspectRatioMode: %s", sWidth, sHeight, sModeStr);
-            scaleSize(sWidth, sHeight, cinfo.output_width, cinfo.output_height, sMode);
-//            qDebug("Scaling the jpeg to %i x %i", sWidth, sHeight, sModeStr);
+#ifndef QT_NO_IMAGE_SMOOTHSCALE
+        if (scaledSize.isValid() && scaledSize != clip.size()
+            && quality >= HIGH_QUALITY_THRESHOLD) {
+
+            (void) jpeg_start_decompress(&cinfo);
 
-            if (cinfo.output_components == 3 || cinfo.output_components == 4) {
-                if (outImage->size() != QSize(sWidth, sHeight) || outImage->format() != QImage::Format_RGB32)
-                    *outImage = QImage(sWidth, sHeight, QImage::Format_RGB32);
-            } else if (cinfo.output_components == 1) {
-                if (outImage->size() != QSize(sWidth, sHeight) || outImage->format() != QImage::Format_Indexed8)
-                    *outImage = QImage(sWidth, sHeight, QImage::Format_Indexed8);
-                outImage->setColorCount(256);
-                for (int i = 0; i < 256; ++i)
-                    outImage->setColor(i, qRgb(i,i,i));
-            } else {
-                // Unsupported format
-            }
-            if (outImage->isNull())
+            jpegSmoothScaler scaler(&cinfo, scaledSize, clip);
+            *outImage = scaler.scale();
+        } else
+#endif
+        {
+            // Allocate memory for the clipped QImage.
+            if (!ensureValidImage(outImage, &cinfo, clip.size()))
                 longjmp(jerr.setjmp_buffer, 1);
 
-            if (!outImage->isNull()) {
-                QImage tmpImage(cinfo.output_width, 1, QImage::Format_RGB32);
-                uchar* inData = tmpImage.bits();
-                uchar* outData = outImage->bits();
-                int out_bpl = outImage->bytesPerLine();
+            // Avoid memcpy() overhead if grayscale with no clipping.
+            bool quickGray = (cinfo.output_components == 1 &&
+                              clip == imageRect);
+            if (!quickGray) {
+                // Ask the jpeg library to allocate a temporary row.
+                // The library will automatically delete it for us later.
+                // The libjpeg docs say we should do this before calling
+                // jpeg_start_decompress().  We can't use "new" here
+                // because we are inside the setjmp() block and an error
+                // in the jpeg input stream would cause a memory leak.
+                JSAMPARRAY rows = (cinfo.mem->alloc_sarray)
+                    ((j_common_ptr)&cinfo, JPOOL_IMAGE,
+                     cinfo.output_width * cinfo.output_components, 1);
+
+                (void) jpeg_start_decompress(&cinfo);
+
                 while (cinfo.output_scanline < cinfo.output_height) {
-                    int outputLine = sHeight * cinfo.output_scanline / cinfo.output_height;
-                    (void) jpeg_read_scanlines(&cinfo, &inData, 1);
+                    int y = int(cinfo.output_scanline) - clip.y();
+                    if (y >= clip.height())
+                        break;      // We've read the entire clip region, so abort.
+
+                    (void) jpeg_read_scanlines(&cinfo, rows, 1);
+
+                    if (y < 0)
+                        continue;   // Haven't reached the starting line yet.
+
                     if (cinfo.output_components == 3) {
-                        uchar *in = inData;
-                        QRgb *out = (QRgb*)outData + outputLine * out_bpl;
-                        for (uint i=0; i<cinfo.output_width; i++) {
-// ### Only scaling down an image works, I don't think scaling up will work at the moment
-// ### An idea I have to make this a smooth scale is to progressively add the pixel values up
-// When scaling down, multiple values are being over drawn in to the output buffer.
-// Instead, a weighting based on the distance the line or pixel is from the output pixel determines
-// the weight of it when added to the output buffer. At present it is a non-smooth scale which is
-// inefficently implemented, it still uncompresses all the jpeg, an optimization for progressive
-// jpegs could be made if scaling by say 50% or some other special cases
-                            out[sWidth * i / cinfo.output_width] = qRgb(in[0], in[1], in[2]);
+                        // Expand 24->32 bpp.
+                        uchar *in = rows[0] + clip.x() * 3;
+                        QRgb *out = (QRgb*)outImage->scanLine(y);
+                        for (int i = 0; i < clip.width(); ++i) {
+                            *out++ = qRgb(in[0], in[1], in[2]);
                             in += 3;
                         }
-                    } else {
-// ### Need to test the case where the jpeg is grayscale, need some black and white jpegs to test
-// this code. (also only scales down and probably won't scale to a larger size)
-                        uchar *in = inData;
-                        uchar *out = outData + outputLine*out_bpl;
-                        for (uint i=0; i<cinfo.output_width; i++) {
-                            out[sWidth * i / cinfo.output_width] = in[i];
+                    } else if (cinfo.out_color_space == JCS_CMYK) {
+                        // Convert CMYK->RGB.
+                        uchar *in = rows[0] + clip.x() * 4;
+                        QRgb *out = (QRgb*)outImage->scanLine(y);
+                        for (int i = 0; i < clip.width(); ++i) {
+                            int k = in[3];
+                            *out++ = qRgb(k * in[0] / 255, k * in[1] / 255,
+                                          k * in[2] / 255);
+                            in += 4;
                         }
+                    } else if (cinfo.output_components == 1) {
+                        // Grayscale.
+                        memcpy(outImage->scanLine(y),
+                               rows[0] + clip.x(), clip.width());
                     }
                 }
-                (void) jpeg_finish_decompress(&cinfo);
-            }
-#ifndef QT_NO_IMAGE_SMOOTHSCALE
-        } else if (scaledSize.isValid() && scaledSize != QSize(cinfo.output_width, cinfo.output_height)
-            && quality >= HIGH_QUALITY_THRESHOLD) {
-
-            jpegSmoothScaler scaler(&cinfo, QString().sprintf("Scale( %d, %d, ScaleFree )",
-                                                              scaledSize.width(),
-                                                              scaledSize.height()).toLatin1().data());
-            *outImage = scaler.scale();
-#endif
-        } else {
-            if (!ensureValidImage(outImage, &cinfo))
-                longjmp(jerr.setjmp_buffer, 1);
-
-            uchar* data = outImage->bits();
-            int bpl = outImage->bytesPerLine();
-            while (cinfo.output_scanline < cinfo.output_height) {
-                uchar *d = data + cinfo.output_scanline * bpl;
-                (void) jpeg_read_scanlines(&cinfo,
-                                           &d,
-                                           1);
-            }
-            (void) jpeg_finish_decompress(&cinfo);
-
-            if (cinfo.output_components == 3) {
-                // Expand 24->32 bpp.
-                for (uint j=0; j<cinfo.output_height; j++) {
-                    uchar *in = outImage->scanLine(j) + cinfo.output_width * 3;
-                    QRgb *out = (QRgb*)outImage->scanLine(j);
-
-                    for (uint i=cinfo.output_width; i--;) {
-                        in-=3;
-                        out[i] = qRgb(in[0], in[1], in[2]);
-                    }
-                }
-            } else if (cinfo.out_color_space == JCS_CMYK) {
-                for (uint j = 0; j < cinfo.output_height; ++j) {
-                    uchar *in = outImage->scanLine(j) + cinfo.output_width * 4;
-                    QRgb *out = (QRgb*)outImage->scanLine(j);
-
-                    for (uint i = cinfo.output_width; i--; ) {
-                        in-=4;
-                        int k = in[3];
-                        out[i] = qRgb(k * in[0] / 255, k * in[1] / 255, k * in[2] / 255);
-                    }
+            } else {
+                // Load unclipped grayscale data directly into the QImage.
+                (void) jpeg_start_decompress(&cinfo);
+                while (cinfo.output_scanline < cinfo.output_height) {
+                    uchar *row = outImage->scanLine(cinfo.output_scanline);
+                    (void) jpeg_read_scanlines(&cinfo, &row, 1);
                 }
             }
+
+            if (cinfo.output_scanline == cinfo.output_height)
+                (void) jpeg_finish_decompress(&cinfo);
+
             if (cinfo.density_unit == 1) {
                 outImage->setDotsPerMeterX(int(100. * cinfo.X_density / 2.54));
                 outImage->setDotsPerMeterY(int(100. * cinfo.Y_density / 2.54));
@@ -960,13 +929,15 @@
                 outImage->setDotsPerMeterY(int(100. * cinfo.Y_density));
             }
 
-            if (scaledSize.isValid() && scaledSize != QSize(cinfo.output_width, cinfo.output_height))
+            if (scaledSize.isValid() && scaledSize != clip.size())
                 *outImage = outImage->scaled(scaledSize, Qt::IgnoreAspectRatio, Qt::FastTransformation);
         }
     }
 
     jpeg_destroy_decompress(&cinfo);
     delete iod_src;
+    if (!scaledClipRect.isEmpty())
+        *outImage = outImage->copy(scaledClipRect);
     return !outImage->isNull();
 }
 
@@ -1224,7 +1195,7 @@
 {
     if (!canRead())
         return false;
-    return read_jpeg_image(device(), image, parameters, scaledSize, quality);
+    return read_jpeg_image(device(), image, scaledSize, scaledClipRect, clipRect, quality);
 }
 
 bool QJpegHandler::write(const QImage &image)
@@ -1235,9 +1206,9 @@
 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;
 }
@@ -1246,10 +1217,12 @@
 {
     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) {
         if (canRead() && !device()->isSequential()) {
             qint64 pos = device()->pos();
@@ -1276,10 +1249,12 @@
 {
     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();
 }
 
 QByteArray QJpegHandler::name() const