Preserve aspect ratio when setting Image.sourceSize
authorMartin Jones <martin.jones@nokia.com>
Tue, 14 Feb 2012 01:57:25 +0000 (11:57 +1000)
committerQt by Nokia <qt-info@nokia.com>
Tue, 14 Feb 2012 07:50:57 +0000 (08:50 +0100)
Setting both sourceSize.width and sourceSize.height results in changing
the image aspect ratio.  This is never what you'd want.

Fit the image to the provided sourceSize, maintaining the aspect ratio.

Task-number: QTBUG-21161
Change-Id: I77e9aacb8d31475d5df0aef1de52c0edbd1e2fc9
Reviewed-by: Aaron Kennedy <aaron.kennedy@nokia.com>
doc/src/declarative/whatsnew.qdoc
src/quick/items/qquickimage.cpp
src/quick/util/qdeclarativepixmapcache.cpp
tests/auto/qtquick2/qquickimage/data/sourceSize.qml [new file with mode: 0644]
tests/auto/qtquick2/qquickimage/tst_qquickimage.cpp

index 4e67bac..05de859 100644 (file)
@@ -107,6 +107,7 @@ Added topMargin, bottomMargin, leftMargin, rightMargin, xOrigin, yOrigin propert
 
 Image has two new properties: horizontalAlignment and verticalAlignment. It also has a new value for
 fillMode (Image.Pad) that does not transform the image.
+Setting Image sourceSize.width and sourceSize.height will now fit the image to the size, maintaining aspect.
 
 Grid now has rowSpacing and columnSpacing properties.
 
index 9af3a7e..a71c666 100644 (file)
@@ -404,6 +404,10 @@ qreal QQuickImage::paintedHeight() const
     other dimension is set in proportion to preserve the source image's aspect ratio.
     (The \l fillMode is independent of this.)
 
+    If both the sourceSize.width and sourceSize.height are set the image will be scaled
+    down to fit within the specified size, maintaining the image's aspect ratio.  The actual
+    size of the image after scaling is available via \l implicitWidth and \l implicitHeight.
+
     If the source is an intrinsically scalable image (eg. SVG), this property
     determines the size of the loaded image regardless of intrinsic size.
     Avoid changing this property dynamically; rendering an SVG is \e slow compared
@@ -413,7 +417,7 @@ qreal QQuickImage::paintedHeight() const
     be no greater than this property specifies. For some formats (currently only JPEG),
     the whole image will never actually be loaded into memory.
 
-    Since QtQuick 1.1 the sourceSize can be cleared to the natural size of the image
+    sourceSize can be cleared to the natural size of the image
     by setting sourceSize to \c undefined.
 
     \note \e {Changing this property dynamically causes the image source to be reloaded,
index 3670c58..43ce334 100644 (file)
@@ -323,20 +323,22 @@ static bool readImage(const QUrl& url, QIODevice *dev, QImage *image, QString *e
         force_scale = true;
     }
 
-    bool scaled = false;
     if (requestSize.width() > 0 || requestSize.height() > 0) {
         QSize s = imgio.size();
+        qreal ratio = 0.0;
         if (requestSize.width() && (force_scale || requestSize.width() < s.width())) {
-            if (requestSize.height() <= 0)
-                s.setHeight(s.height()*requestSize.width()/s.width());
-            s.setWidth(requestSize.width()); scaled = true;
+            ratio = qreal(requestSize.width())/s.width();
         }
         if (requestSize.height() && (force_scale || requestSize.height() < s.height())) {
-            if (requestSize.width() <= 0)
-                s.setWidth(s.width()*requestSize.height()/s.height());
-            s.setHeight(requestSize.height()); scaled = true;
+            qreal hr = qreal(requestSize.height())/s.height();
+            if (ratio == 0.0 || hr < ratio)
+                ratio = hr;
+        }
+        if (ratio > 0.0) {
+            s.setHeight(qRound(s.height() * ratio));
+            s.setWidth(qRound(s.width() * ratio));
+            imgio.setScaledSize(s);
         }
-        if (scaled) { imgio.setScaledSize(s); }
     }
 
     if (impsize)
diff --git a/tests/auto/qtquick2/qquickimage/data/sourceSize.qml b/tests/auto/qtquick2/qquickimage/data/sourceSize.qml
new file mode 100644 (file)
index 0000000..8e25c25
--- /dev/null
@@ -0,0 +1,7 @@
+import QtQuick 2.0
+
+Image {
+    source: "heart.png"
+    sourceSize.width: srcWidth
+    sourceSize.height: srcHeight
+}
index b33caa7..7602f1b 100644 (file)
@@ -95,6 +95,8 @@ private slots:
     void sourceSize_QTBUG_16389();
     void nullPixmapPaint();
     void imageCrash_QTBUG_22125();
+    void sourceSize_data();
+    void sourceSize();
 
 private:
     QDeclarativeEngine engine;
@@ -498,6 +500,8 @@ void tst_qquickimage::tiling_QTBUG_6716()
             QVERIFY(img.pixel(x, y) == qRgb(0, 255, 0));
         }
     }
+
+    delete canvas;
 }
 
 void tst_qquickimage::tiling_QTBUG_6716_data()
@@ -674,6 +678,8 @@ void tst_qquickimage::nullPixmapPaint()
     qInstallMsgHandler(previousMsgHandler);
     QVERIFY(numberOfWarnings == 0);
     delete image;
+
+    delete canvas;
 }
 
 void tst_qquickimage::imageCrash_QTBUG_22125()
@@ -698,6 +704,46 @@ void tst_qquickimage::imageCrash_QTBUG_22125()
     QCoreApplication::processEvents();
 }
 
+void tst_qquickimage::sourceSize_data()
+{
+    QTest::addColumn<int>("sourceWidth");
+    QTest::addColumn<int>("sourceHeight");
+    QTest::addColumn<qreal>("implicitWidth");
+    QTest::addColumn<qreal>("implicitHeight");
+
+    QTest::newRow("unscaled") << 0 << 0 << 300.0 << 300.0;
+    QTest::newRow("scale width") << 100 << 0 << 100.0 << 100.0;
+    QTest::newRow("scale height") << 0 << 150 << 150.0 << 150.0;
+    QTest::newRow("larger sourceSize") << 400 << 400 << 300.0 << 300.0;
+}
+
+void tst_qquickimage::sourceSize()
+{
+    QFETCH(int, sourceWidth);
+    QFETCH(int, sourceHeight);
+    QFETCH(qreal, implicitWidth);
+    QFETCH(qreal, implicitHeight);
+
+    QQuickView *canvas = new QQuickView(0);
+    QDeclarativeContext *ctxt = canvas->rootContext();
+    ctxt->setContextProperty("srcWidth", sourceWidth);
+    ctxt->setContextProperty("srcHeight", sourceHeight);
+
+    canvas->setSource(testFileUrl("sourceSize.qml"));
+    canvas->show();
+    qApp->processEvents();
+
+    QQuickImage *image = qobject_cast<QQuickImage*>(canvas->rootObject());
+    QVERIFY(image);
+
+    QCOMPARE(image->sourceSize().width(), sourceWidth);
+    QCOMPARE(image->sourceSize().height(), sourceHeight);
+    QCOMPARE(image->implicitWidth(), implicitWidth);
+    QCOMPARE(image->implicitHeight(), implicitHeight);
+
+    delete canvas;
+}
+
 QTEST_MAIN(tst_qquickimage)
 
 #include "tst_qquickimage.moc"