tests/auto/qimagewriter/tst_qimagewriter.cpp
changeset 0 1918ee327afb
child 3 41300fa6a67c
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/auto/qimagewriter/tst_qimagewriter.cpp	Mon Jan 11 14:00:40 2010 +0000
@@ -0,0 +1,655 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the test suite of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights.  These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include <QtTest/QtTest>
+
+
+#include <QDebug>
+#include <QFile>
+#include <QImage>
+#include <QImageReader>
+#include <QImageWriter>
+#include <QLabel>
+#include <QPainter>
+#include <QSet>
+
+#if defined(Q_OS_SYMBIAN)
+# define SRCDIR ""
+#endif
+typedef QMap<QString, QString> QStringMap;
+typedef QList<int> QIntList;
+Q_DECLARE_METATYPE(QImage)
+Q_DECLARE_METATYPE(QStringMap)
+Q_DECLARE_METATYPE(QIntList)
+Q_DECLARE_METATYPE(QImageWriter::ImageWriterError)
+Q_DECLARE_METATYPE(QIODevice *)
+Q_DECLARE_METATYPE(QImage::Format)
+
+//TESTED_FILES=
+
+class tst_QImageWriter : public QObject
+{
+    Q_OBJECT
+
+public:
+    tst_QImageWriter();
+    virtual ~tst_QImageWriter();
+
+public slots:
+    void init();
+    void cleanup();
+
+private slots:
+    void getSetCheck();
+    void writeImage_data();
+    void writeImage();
+    void writeImage2_data();
+    void writeImage2();
+    void supportedFormats();
+
+    void readWriteNonDestructive_data();
+    void readWriteNonDestructive();
+
+#if defined QTEST_HAVE_TIFF
+    void largeTiff();
+#endif
+
+    void setDescription_data();
+    void setDescription();
+
+    void writeToInvalidDevice();
+
+    void supportsOption_data();
+    void supportsOption();
+
+    void saveWithNoFormat_data();
+    void saveWithNoFormat();
+
+    void resolution_data();
+    void resolution();
+
+    void saveToTemporaryFile();
+};
+#ifdef Q_OS_SYMBIAN
+static const QLatin1String prefix(SRCDIR "images/");
+#else
+static const QLatin1String prefix(SRCDIR "/images/");
+#endif
+static void initializePadding(QImage *image)
+{
+    int effectiveBytesPerLine = (image->width() * image->depth() + 7) / 8;
+    int paddingBytes = image->bytesPerLine() - effectiveBytesPerLine;
+    if (paddingBytes == 0)
+        return;
+    for (int y = 0; y < image->height(); ++y) {
+        qMemSet(image->scanLine(y) + effectiveBytesPerLine, 0, paddingBytes);
+    }
+}
+
+// Testing get/set functions
+void tst_QImageWriter::getSetCheck()
+{
+    QImageWriter obj1;
+    // QIODevice * QImageWriter::device()
+    // void QImageWriter::setDevice(QIODevice *)
+    QFile *var1 = new QFile;
+    obj1.setDevice(var1);
+
+    QCOMPARE((QIODevice *) var1, obj1.device());
+    // The class should possibly handle a 0-pointer as a device, since
+    // there is a default contructor, so it's "handling" a 0 device by default.
+    // For example: QMovie::setDevice(0) works just fine
+    obj1.setDevice((QIODevice *)0);
+    QCOMPARE((QIODevice *) 0, obj1.device());
+    delete var1;
+
+    // int QImageWriter::quality()
+    // void QImageWriter::setQuality(int)
+    obj1.setQuality(0);
+    QCOMPARE(0, obj1.quality());
+    obj1.setQuality(INT_MIN);
+    QCOMPARE(INT_MIN, obj1.quality());
+    obj1.setQuality(INT_MAX);
+    QCOMPARE(INT_MAX, obj1.quality());
+
+    // int QImageWriter::compression()
+    // void QImageWriter::setCompression(int)
+    obj1.setCompression(0);
+    QCOMPARE(0, obj1.compression());
+    obj1.setCompression(INT_MIN);
+    QCOMPARE(INT_MIN, obj1.compression());
+    obj1.setCompression(INT_MAX);
+    QCOMPARE(INT_MAX, obj1.compression());
+
+    // float QImageWriter::gamma()
+    // void QImageWriter::setGamma(float)
+    obj1.setGamma(0.0f);
+    QCOMPARE(0.0f, obj1.gamma());
+    obj1.setGamma(1.1f);
+    QCOMPARE(1.1f, obj1.gamma());
+}
+
+tst_QImageWriter::tst_QImageWriter()
+{
+}
+
+tst_QImageWriter::~tst_QImageWriter()
+{
+    QDir dir(prefix);
+    QStringList filesToDelete = dir.entryList(QStringList() << "gen-*" , QDir::NoDotAndDotDot | QDir::Files);
+    foreach( QString file, filesToDelete) {
+        QFile::remove(dir.absoluteFilePath(file));
+    }
+
+}
+
+void tst_QImageWriter::init()
+{
+}
+
+void tst_QImageWriter::cleanup()
+{
+}
+
+void tst_QImageWriter::writeImage_data()
+{
+    QTest::addColumn<QString>("fileName");
+    QTest::addColumn<bool>("lossy");
+    QTest::addColumn<QByteArray>("format");
+
+    QTest::newRow("BMP: colorful") << QString("colorful.bmp") << false << QByteArray("bmp");
+    QTest::newRow("BMP: font") << QString("font.bmp") << false << QByteArray("bmp");
+    QTest::newRow("XPM: marble") << QString("marble.xpm") << false << QByteArray("xpm");
+    QTest::newRow("PNG: kollada") << QString("kollada.png") << false << QByteArray("png");
+    QTest::newRow("PPM: teapot") << QString("teapot.ppm") << false << QByteArray("ppm");
+    QTest::newRow("PBM: ship63") << QString("ship63.pbm") << true << QByteArray("pbm");
+    QTest::newRow("XBM: gnus") << QString("gnus.xbm") << false << QByteArray("xbm");
+    QTest::newRow("JPEG: beavis") << QString("beavis.jpg") << true << QByteArray("jpeg");
+#if defined QTEST_HAVE_TIFF
+    QTest::newRow("TIFF: teapot") << QString("teapot.tiff") << false << QByteArray("tiff");
+#endif
+}
+
+void tst_QImageWriter::writeImage()
+{
+    QFETCH(QString, fileName);
+    QFETCH(bool, lossy);
+    QFETCH(QByteArray, format);
+
+    QImage image;
+    {
+        QImageReader reader(prefix + fileName);
+        image = reader.read();
+        QVERIFY2(!image.isNull(), qPrintable(reader.errorString()));
+    }
+    {
+        QImageWriter writer(prefix + "gen-" + fileName, format);
+        QVERIFY(writer.write(image));
+    }
+
+    {
+        // Shouldn't be able to write to read-only file
+        QFile sourceFile(prefix + "gen-" + fileName);
+        QFile::Permissions permissions = sourceFile.permissions();
+        QVERIFY(sourceFile.setPermissions(QFile::ReadOwner | QFile::ReadUser | QFile::ReadGroup | QFile::ReadOther));
+
+        QImageWriter writer(prefix + "gen-" + fileName, format);
+        QVERIFY(!writer.write(image));
+
+        QVERIFY(sourceFile.setPermissions(permissions));
+    }
+
+    QImage image2;
+    {
+        QImageReader reader(prefix + "gen-" + fileName);
+        image2 = reader.read();
+        QVERIFY(!image2.isNull());
+    }
+    if (!lossy) {
+        QCOMPARE(image, image2);
+    } else {
+        QCOMPARE(image.format(), image2.format());
+        QCOMPARE(image.depth(), image2.depth());
+    }
+}
+
+void tst_QImageWriter::writeImage2_data()
+{
+    QTest::addColumn<QString>("fileName");
+    QTest::addColumn<QByteArray>("format");
+    QTest::addColumn<QImage>("image");
+
+    const QStringList formats = QStringList() << "bmp" << "xpm" << "png"
+                                              << "ppm"; //<< "jpeg";
+    QImage image0(70, 70, QImage::Format_ARGB32);
+    image0.fill(QColor(Qt::red).rgb());
+
+    QImage::Format imgFormat = QImage::Format_Mono;
+    while (imgFormat != QImage::NImageFormats) {
+        QImage image = image0.convertToFormat(imgFormat);
+        initializePadding(&image);
+        foreach (const QString format, formats) {
+            const QString fileName = QString("solidcolor_%1.%2").arg(imgFormat)
+                                     .arg(format);
+            QTest::newRow(fileName.toLatin1()) << fileName
+                                               << format.toLatin1()
+                                               << image;
+        }
+        imgFormat = QImage::Format(int(imgFormat) + 1);
+    }
+}
+
+#if defined QTEST_HAVE_TIFF
+void tst_QImageWriter::largeTiff()
+{
+#if !defined(Q_OS_WINCE) && !defined(Q_OS_SYMBIAN)
+    QImage img(4096, 2048, QImage::Format_ARGB32);
+
+    QPainter p(&img);
+    img.fill(0x0);
+    p.fillRect(0, 0, 4096, 2048, QBrush(Qt::CrossPattern));
+    p.end();
+
+    QByteArray array;
+    QBuffer writeBuffer(&array);
+    writeBuffer.open(QIODevice::WriteOnly);
+
+    QImageWriter writer(&writeBuffer, "tiff");
+    QVERIFY(writer.write(img));
+
+    writeBuffer.close();
+
+    QBuffer readBuffer(&array);
+    readBuffer.open(QIODevice::ReadOnly);
+
+    QImageReader reader(&readBuffer, "tiff");
+
+    QImage img2 = reader.read();
+    QVERIFY(!img2.isNull());
+
+    QCOMPARE(img, img2);
+#else
+    QWARN("not tested on Symbian/WinCE");
+#endif
+}
+#endif
+
+/*
+    Workaround for the equality operator for indexed formats
+    (which fails if the colortables are different).
+
+    Images must have the same format and size.
+*/
+static bool equalImageContents(const QImage &image1, const QImage &image2)
+{
+    switch (image1.format()) {
+    case QImage::Format_Mono:
+    case QImage::Format_Indexed8:
+        for (int y = 0; y < image1.height(); ++y)
+            for (int x = 0; x < image1.width(); ++x)
+                if (image1.pixel(x, y) != image2.pixel(x, y))
+                    return false;
+        return true;
+    default:
+        return (image1 == image2);
+    }
+}
+
+void tst_QImageWriter::writeImage2()
+{
+    QFETCH(QString, fileName);
+    QFETCH(QByteArray, format);
+    QFETCH(QImage, image);
+
+    //we reduce the scope of writer so that it closes the associated file
+    // and QFile::remove can actually work
+    {
+        QImageWriter writer(fileName, format);
+        QVERIFY(writer.write(image));
+    }
+
+    QImage written;
+
+    //we reduce the scope of reader so that it closes the associated file
+    // and QFile::remove can actually work
+    {
+        QImageReader reader(fileName, format);
+        QVERIFY(reader.read(&written));
+    }
+
+    written = written.convertToFormat(image.format());
+    if (!equalImageContents(written, image)) {
+        qDebug() << "image" << image.format() << image.width()
+                 << image.height() << image.depth()
+                 << hex << image.pixel(0, 0);
+        qDebug() << "written" << written.format() << written.width()
+                 << written.height() << written.depth()
+                 << hex << written.pixel(0, 0);
+    }
+    QVERIFY(equalImageContents(written, image));
+
+    QVERIFY(QFile::remove(fileName));
+}
+
+void tst_QImageWriter::supportedFormats()
+{
+    QList<QByteArray> formats = QImageWriter::supportedImageFormats();
+    QList<QByteArray> sortedFormats = formats;
+    qSort(sortedFormats);
+
+    // check that the list is sorted
+    QCOMPARE(formats, sortedFormats);
+
+    QSet<QByteArray> formatSet;
+    foreach (QByteArray format, formats)
+        formatSet << format;
+
+    // check that the list does not contain duplicates
+    QCOMPARE(formatSet.size(), formats.size());
+}
+
+void tst_QImageWriter::readWriteNonDestructive_data()
+{
+    QTest::addColumn<QImage::Format>("format");
+    QTest::addColumn<QImage::Format>("expectedFormat");
+    QTest::newRow("tiff mono") << QImage::Format_Mono << QImage::Format_Mono;
+    QTest::newRow("tiff indexed") << QImage::Format_Indexed8 << QImage::Format_Indexed8;
+    QTest::newRow("tiff rgb32") << QImage::Format_ARGB32 << QImage::Format_ARGB32;
+}
+
+void tst_QImageWriter::readWriteNonDestructive()
+{
+    QFETCH(QImage::Format, format);
+    QFETCH(QImage::Format, expectedFormat);
+    QImage image = QImage(prefix + "colorful.bmp").convertToFormat(format);
+    QVERIFY(image.save(prefix + "gen-readWriteNonDestructive.tiff"));
+
+    QImage image2 = QImage(prefix + "gen-readWriteNonDestructive.tiff");
+    QImage::Format readFormat = image2.format();
+    QCOMPARE(readFormat, expectedFormat);
+    QCOMPARE(image, image2);
+}
+
+void tst_QImageWriter::setDescription_data()
+{
+    QTest::addColumn<QString>("fileName");
+    QTest::addColumn<QStringMap>("description");
+
+    QMap<QString, QString> willem;
+    willem["Title"] = "PngSuite";
+    willem["Author"] = "Willem A.J. van Schaik (willem@schaik.com)";
+    willem["Copyright"] = "Copyright Willem van Schaik, Singapore 1995-96";
+    willem["Description"] = "A compilation of a set of images created to test the "
+                            "various color-types of the PNG format. Included are "
+                            "black&white, color, paletted, with alpha channel, with "
+                            "transparency formats. All bit-depths allowed according "
+                            "to the spec are present.";
+    willem["Software"] = "Created on a NeXTstation color using \"pnmtopng\".";
+    willem["Disclaimer"] = "Freeware.";
+
+    QTest::newRow("PNG") << prefix + QString("gen-pngwithtext.png") << willem;
+}
+
+void tst_QImageWriter::setDescription()
+{
+    QFETCH(QString, fileName);
+    QFETCH(QStringMap, description);
+
+    QImageWriter writer(fileName, "png");
+    foreach (QString key, description.keys())
+        writer.setText(key, description.value(key));
+    QVERIFY(writer.write(QImage(prefix + "kollada.png")));
+
+    QImageReader reader(fileName);
+    foreach (QString key, description.keys())
+        QCOMPARE(reader.text(key), description.value(key));
+}
+
+void tst_QImageWriter::writeToInvalidDevice()
+{
+    QLatin1String fileName("/these/directories/do/not/exist/001.png");
+    {
+        QImageWriter writer(fileName);
+        QVERIFY(!writer.canWrite());
+        QCOMPARE(writer.error(), QImageWriter::DeviceError);
+    }
+    {
+        QImageWriter writer(fileName);
+        writer.setFormat("png");
+        QVERIFY(!writer.canWrite());
+        QCOMPARE(writer.error(), QImageWriter::DeviceError);
+    }
+    {
+        QImageWriter writer(fileName);
+        QImage im(10, 10, QImage::Format_ARGB32);
+        QVERIFY(!writer.write(im));
+        QCOMPARE(writer.error(), QImageWriter::DeviceError);
+    }
+    {
+        QImageWriter writer(fileName);
+        writer.setFormat("png");
+        QImage im(10, 10, QImage::Format_ARGB32);
+        QVERIFY(!writer.write(im));
+        QCOMPARE(writer.error(), QImageWriter::DeviceError);
+    }
+}
+
+void tst_QImageWriter::supportsOption_data()
+{
+    QTest::addColumn<QString>("fileName");
+    QTest::addColumn<QIntList>("options");
+
+    QTest::newRow("png") << QString("gen-black.png")
+                         << (QIntList() << QImageIOHandler::Gamma
+                              << QImageIOHandler::Description
+                              << QImageIOHandler::Quality
+                              << QImageIOHandler::Size);
+#if defined QTEST_HAVE_TIFF
+    QTest::newRow("tiff") << QString("gen-black.tiff")
+                          << (QIntList() << QImageIOHandler::Size
+                              << QImageIOHandler::CompressionRatio);
+#endif
+}
+
+void tst_QImageWriter::supportsOption()
+{
+    QFETCH(QString, fileName);
+    QFETCH(QIntList, options);
+
+    QSet<QImageIOHandler::ImageOption> allOptions;
+    allOptions << QImageIOHandler::Size
+               << QImageIOHandler::ClipRect
+               << QImageIOHandler::Description
+               << QImageIOHandler::ScaledClipRect
+               << QImageIOHandler::ScaledSize
+               << QImageIOHandler::CompressionRatio
+               << QImageIOHandler::Gamma
+               << QImageIOHandler::Quality
+               << QImageIOHandler::Name
+               << QImageIOHandler::SubType
+               << QImageIOHandler::IncrementalReading
+               << QImageIOHandler::Endianness
+               << QImageIOHandler::Animation
+               << QImageIOHandler::BackgroundColor;
+
+    QImageWriter writer(prefix + fileName);
+    for (int i = 0; i < options.size(); ++i) {
+        QVERIFY(writer.supportsOption(QImageIOHandler::ImageOption(options.at(i))));
+        allOptions.remove(QImageIOHandler::ImageOption(options.at(i)));
+    }
+
+    foreach (QImageIOHandler::ImageOption option, allOptions)
+        QVERIFY(!writer.supportsOption(option));
+}
+
+void tst_QImageWriter::saveWithNoFormat_data()
+{
+    QTest::addColumn<QString>("fileName");
+    QTest::addColumn<QByteArray>("format");
+    QTest::addColumn<QImageWriter::ImageWriterError>("error");
+
+    QTest::newRow("garble") << prefix + QString("gen-out.garble") << QByteArray("jpeg") << QImageWriter::UnsupportedFormatError;
+    QTest::newRow("bmp") << prefix + QString("gen-out.bmp") << QByteArray("bmp") << QImageWriter::ImageWriterError(0);
+    QTest::newRow("xbm") << prefix + QString("gen-out.xbm") << QByteArray("xbm") << QImageWriter::ImageWriterError(0);
+    QTest::newRow("xpm") << prefix + QString("gen-out.xpm") << QByteArray("xpm") << QImageWriter::ImageWriterError(0);
+    QTest::newRow("png") << prefix + QString("gen-out.png") << QByteArray("png") << QImageWriter::ImageWriterError(0);
+    QTest::newRow("ppm") << prefix + QString("gen-out.ppm") << QByteArray("ppm") << QImageWriter::ImageWriterError(0);
+    QTest::newRow("pbm") << prefix + QString("gen-out.pbm") << QByteArray("pbm") << QImageWriter::ImageWriterError(0);
+#if defined QTEST_HAVE_TIFF
+    QTest::newRow("tiff") << prefix + QString("gen-out.tiff") << QByteArray("tiff") << QImageWriter::ImageWriterError(0);
+#endif
+}
+
+void tst_QImageWriter::saveWithNoFormat()
+{
+    QFETCH(QString, fileName);
+    QFETCH(QByteArray, format);
+    QFETCH(QImageWriter::ImageWriterError, error);
+
+    QImage niceImage(64, 64, QImage::Format_ARGB32);
+    qMemSet(niceImage.bits(), 0, niceImage.numBytes());
+
+    QImageWriter writer(fileName /* , 0 - no format! */);
+    if (error != 0) {
+        QVERIFY(!writer.write(niceImage));
+        QCOMPARE(writer.error(), error);
+        return;
+    }
+
+    QVERIFY2(writer.write(niceImage), qPrintable(writer.errorString()));
+
+    QImageReader reader(fileName);
+    QCOMPARE(reader.format(), format);
+
+    QVERIFY(reader.canRead());
+
+    QImage outImage = reader.read();
+    QVERIFY2(!outImage.isNull(), qPrintable(reader.errorString()));
+}
+
+void tst_QImageWriter::resolution_data()
+{
+    QTest::addColumn<QString>("filename");
+    QTest::addColumn<int>("expectedDotsPerMeterX");
+    QTest::addColumn<int>("expectedDotsPerMeterY");
+#if defined QTEST_HAVE_TIFF
+    QTest::newRow("TIFF: 100 dpi") << ("image_100dpi.tif") << qRound(100 * (100 / 2.54)) << qRound(100 * (100 / 2.54));
+    QTest::newRow("TIFF: 50 dpi") << ("image_50dpi.tif") << qRound(50 * (100 / 2.54)) << qRound(50 * (100 / 2.54));
+    QTest::newRow("TIFF: 300 dot per meter") << ("image_300dpm.tif") << 300 << 300;
+#endif
+}
+
+void tst_QImageWriter::resolution()
+{
+    QFETCH(QString, filename);
+    QFETCH(int, expectedDotsPerMeterX);
+    QFETCH(int, expectedDotsPerMeterY);
+
+    QImage image(prefix + QLatin1String("colorful.bmp"));
+    image.setDotsPerMeterX(expectedDotsPerMeterX);
+    image.setDotsPerMeterY(expectedDotsPerMeterY);
+    const QString generatedFilepath = prefix + "gen-" + filename;
+    {
+        QImageWriter writer(generatedFilepath);
+        QVERIFY(writer.write(image));
+    }
+    QImageReader reader(generatedFilepath);
+    const QImage generatedImage = reader.read();
+
+    QCOMPARE(expectedDotsPerMeterX, generatedImage.dotsPerMeterX());
+    QCOMPARE(expectedDotsPerMeterY, generatedImage.dotsPerMeterY());
+}
+
+void tst_QImageWriter::saveToTemporaryFile()
+{
+    QImage image(prefix + "kollada.png");
+    QVERIFY(!image.isNull());
+
+    {
+        // 1) Via QImageWriter's API, with a standard temp file name
+        QTemporaryFile file;
+        QVERIFY(file.open());
+        QImageWriter writer(&file, "PNG");
+        if (writer.canWrite())
+            QVERIFY(writer.write(image));
+        else
+            qWarning() << file.errorString();
+#if defined(Q_OS_WINCE)
+        file.reset();
+#endif
+        QCOMPARE(QImage(writer.fileName()), image);
+    }
+    {
+        // 2) Via QImage's API, with a standard temp file name
+        QTemporaryFile file;
+        QVERIFY(file.open());
+        QVERIFY(image.save(&file, "PNG"));
+        file.reset();
+        QImage tmp;
+        QVERIFY(tmp.load(&file, "PNG"));
+        QCOMPARE(tmp, image);
+    }
+    {
+        // 3) Via QImageWriter's API, with a named temp file
+        QTemporaryFile file("tempXXXXXX");
+        QVERIFY(file.open());
+        QImageWriter writer(&file, "PNG");
+        QVERIFY(writer.write(image));
+#if defined(Q_OS_WINCE)
+        file.reset();
+#endif
+        QCOMPARE(QImage(writer.fileName()), image);
+    }
+    {
+        // 4) Via QImage's API, with a named temp file
+        QTemporaryFile file("tempXXXXXX");
+        QVERIFY(file.open());
+        QVERIFY(image.save(&file, "PNG"));
+        file.reset();
+        QImage tmp;
+        QVERIFY(tmp.load(&file, "PNG"));
+        QCOMPARE(tmp, image);
+    }
+}
+
+QTEST_MAIN(tst_QImageWriter)
+#include "tst_qimagewriter.moc"