Invalidate old QImage data if load()/loadFromData() has failed
This guarantees one will never get `!img.isNull()` after load()/loadFromData() has failed, even if the image was not null before. Apply the same fix to QPixmap and QPicture. Change-Id: Ida1ad6a6f0fc830df8e75ada0c163fc2d3360dea Reviewed-by: Samuel Rødal <samuel.rodal@digia.com>
This commit is contained in:
parent
34c31cd74c
commit
008e5ba61a
5
dist/changes-5.0.0
vendored
5
dist/changes-5.0.0
vendored
@ -494,6 +494,11 @@ QtGui
|
||||
For consistency with RGB32 and other 32-bit formats, function now expects
|
||||
image data in RGB layout as opposed to BGR layout.
|
||||
|
||||
* Behavioral change in QImage and QPixmap load()/loadFromData() on a non-null image:
|
||||
If load() or loadFromData() fails to load the image (returns false) then
|
||||
the existent image data will be invalidated, so that isNull() is guaranteed
|
||||
to return true in this case.
|
||||
|
||||
QtWidgets
|
||||
---------
|
||||
* QInputContext removed as well as related getters and setters on QWidget and QApplication.
|
||||
|
@ -4346,7 +4346,8 @@ QImage QImage::rgbSwapped() const
|
||||
|
||||
/*!
|
||||
Loads an image from the file with the given \a fileName. Returns true if
|
||||
the image was successfully loaded; otherwise returns false.
|
||||
the image was successfully loaded; otherwise invalidates the image
|
||||
and returns false.
|
||||
|
||||
The loader attempts to read the image using the specified \a format, e.g.,
|
||||
PNG or JPG. If \a format is not specified (which is the default), the
|
||||
@ -4363,15 +4364,9 @@ QImage QImage::rgbSwapped() const
|
||||
|
||||
bool QImage::load(const QString &fileName, const char* format)
|
||||
{
|
||||
if (fileName.isEmpty())
|
||||
return false;
|
||||
|
||||
QImage image = QImageReader(fileName, format).read();
|
||||
if (!image.isNull()) {
|
||||
operator=(image);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
operator=(image);
|
||||
return !isNull();
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -4384,11 +4379,8 @@ bool QImage::load(const QString &fileName, const char* format)
|
||||
bool QImage::load(QIODevice* device, const char* format)
|
||||
{
|
||||
QImage image = QImageReader(device, format).read();
|
||||
if(!image.isNull()) {
|
||||
operator=(image);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
operator=(image);
|
||||
return !isNull();
|
||||
}
|
||||
|
||||
/*!
|
||||
@ -4396,7 +4388,7 @@ bool QImage::load(QIODevice* device, const char* format)
|
||||
|
||||
Loads an image from the first \a len bytes of the given binary \a
|
||||
data. Returns true if the image was successfully loaded; otherwise
|
||||
returns false.
|
||||
invalidates the image and returns false.
|
||||
|
||||
The loader attempts to read the image using the specified \a format, e.g.,
|
||||
PNG or JPG. If \a format is not specified (which is the default), the
|
||||
@ -4408,11 +4400,8 @@ bool QImage::load(QIODevice* device, const char* format)
|
||||
bool QImage::loadFromData(const uchar *data, int len, const char *format)
|
||||
{
|
||||
QImage image = fromData(data, len, format);
|
||||
if (!image.isNull()) {
|
||||
operator=(image);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
operator=(image);
|
||||
return !isNull();
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -246,7 +246,7 @@ void QPicture::setData(const char* data, uint size)
|
||||
|
||||
/*!
|
||||
Loads a picture from the file specified by \a fileName and returns
|
||||
true if successful; otherwise returns false.
|
||||
true if successful; otherwise invalidates the picture and returns false.
|
||||
|
||||
Please note that the \a format parameter has been deprecated and
|
||||
will have no effect.
|
||||
@ -257,8 +257,10 @@ void QPicture::setData(const char* data, uint size)
|
||||
bool QPicture::load(const QString &fileName, const char *format)
|
||||
{
|
||||
QFile f(fileName);
|
||||
if (!f.open(QIODevice::ReadOnly))
|
||||
if (!f.open(QIODevice::ReadOnly)) {
|
||||
operator=(QPicture());
|
||||
return false;
|
||||
}
|
||||
return load(&f, format);
|
||||
}
|
||||
|
||||
@ -273,18 +275,14 @@ bool QPicture::load(QIODevice *dev, const char *format)
|
||||
if(format) {
|
||||
#ifndef QT_NO_PICTUREIO
|
||||
QPictureIO io(dev, format);
|
||||
bool result = io.read();
|
||||
if (result) {
|
||||
if (io.read()) {
|
||||
operator=(io.picture());
|
||||
|
||||
} else if (format)
|
||||
#else
|
||||
bool result = false;
|
||||
#endif
|
||||
{
|
||||
qWarning("QPicture::load: No such picture format: %s", format);
|
||||
return true;
|
||||
}
|
||||
return result;
|
||||
#endif
|
||||
qWarning("QPicture::load: No such picture format: %s", format);
|
||||
operator=(QPicture());
|
||||
return false;
|
||||
}
|
||||
|
||||
detach();
|
||||
|
@ -684,8 +684,8 @@ QBitmap QPixmap::createMaskFromColor(const QColor &maskColor, Qt::MaskMode mode)
|
||||
|
||||
/*!
|
||||
Loads a pixmap from the file with the given \a fileName. Returns
|
||||
true if the pixmap was successfully loaded; otherwise returns
|
||||
false.
|
||||
true if the pixmap was successfully loaded; otherwise invalidates
|
||||
the pixmap and returns false.
|
||||
|
||||
The loader attempts to read the pixmap using the specified \a
|
||||
format. If the \a format is not specified (which is the default),
|
||||
@ -711,8 +711,10 @@ QBitmap QPixmap::createMaskFromColor(const QColor &maskColor, Qt::MaskMode mode)
|
||||
|
||||
bool QPixmap::load(const QString &fileName, const char *format, Qt::ImageConversionFlags flags)
|
||||
{
|
||||
if (fileName.isEmpty())
|
||||
if (fileName.isEmpty()) {
|
||||
data.reset();
|
||||
return false;
|
||||
}
|
||||
|
||||
QFileInfo info(fileName);
|
||||
QString key = QLatin1String("qt_pixmap")
|
||||
@ -723,19 +725,23 @@ bool QPixmap::load(const QString &fileName, const char *format, Qt::ImageConvers
|
||||
|
||||
// Note: If no extension is provided, we try to match the
|
||||
// file against known plugin extensions
|
||||
if (!info.completeSuffix().isEmpty() && !info.exists())
|
||||
if (!info.completeSuffix().isEmpty() && !info.exists()) {
|
||||
data.reset();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (QPixmapCache::find(key, *this))
|
||||
if (QPixmapCache::find(key, this))
|
||||
return true;
|
||||
|
||||
QScopedPointer<QPlatformPixmap> tmp(QPlatformPixmap::create(0, 0, data ? data->type : QPlatformPixmap::PixmapType));
|
||||
if (tmp->fromFile(fileName, format, flags)) {
|
||||
data = tmp.take();
|
||||
if (!data)
|
||||
data = QPlatformPixmap::create(0, 0, QPlatformPixmap::PixmapType);
|
||||
|
||||
if (data->fromFile(fileName, format, flags)) {
|
||||
QPixmapCache::insert(key, *this);
|
||||
return true;
|
||||
}
|
||||
|
||||
data.reset();
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -744,7 +750,7 @@ bool QPixmap::load(const QString &fileName, const char *format, Qt::ImageConvers
|
||||
|
||||
Loads a pixmap from the \a len first bytes of the given binary \a
|
||||
data. Returns true if the pixmap was loaded successfully;
|
||||
otherwise returns false.
|
||||
otherwise invalidates the pixmap and returns false.
|
||||
|
||||
The loader attempts to read the pixmap using the specified \a
|
||||
format. If the \a format is not specified (which is the default),
|
||||
@ -760,13 +766,19 @@ bool QPixmap::load(const QString &fileName, const char *format, Qt::ImageConvers
|
||||
|
||||
bool QPixmap::loadFromData(const uchar *buf, uint len, const char *format, Qt::ImageConversionFlags flags)
|
||||
{
|
||||
if (len == 0 || buf == 0)
|
||||
if (len == 0 || buf == 0) {
|
||||
data.reset();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!data)
|
||||
data = QPlatformPixmap::create(0, 0, QPlatformPixmap::PixmapType);
|
||||
|
||||
return data->fromData(buf, len, format, flags);
|
||||
if (data->fromData(buf, len, format, flags))
|
||||
return true;
|
||||
|
||||
data.reset();
|
||||
return false;
|
||||
}
|
||||
|
||||
/*!
|
||||
|
@ -95,6 +95,12 @@ private slots:
|
||||
|
||||
void copy();
|
||||
|
||||
void load();
|
||||
void loadFromData();
|
||||
#if !defined(QT_NO_DATASTREAM)
|
||||
void loadFromDataStream();
|
||||
#endif
|
||||
|
||||
void setPixel_data();
|
||||
void setPixel();
|
||||
|
||||
@ -1006,6 +1012,85 @@ void tst_QImage::copy()
|
||||
}
|
||||
}
|
||||
|
||||
void tst_QImage::load()
|
||||
{
|
||||
const QString prefix = QFINDTESTDATA("images/");
|
||||
if (prefix.isEmpty())
|
||||
QFAIL("can not find images directory!");
|
||||
const QString filePath = prefix + QLatin1String("image.jpg");
|
||||
|
||||
QImage dest(filePath);
|
||||
QVERIFY(!dest.isNull());
|
||||
QVERIFY(!dest.load("image_that_does_not_exist.png"));
|
||||
QVERIFY(dest.isNull());
|
||||
QVERIFY(dest.load(filePath));
|
||||
QVERIFY(!dest.isNull());
|
||||
}
|
||||
|
||||
void tst_QImage::loadFromData()
|
||||
{
|
||||
const QString prefix = QFINDTESTDATA("images/");
|
||||
if (prefix.isEmpty())
|
||||
QFAIL("can not find images directory!");
|
||||
const QString filePath = prefix + QLatin1String("image.jpg");
|
||||
|
||||
QImage original(filePath);
|
||||
QVERIFY(!original.isNull());
|
||||
|
||||
QByteArray ba;
|
||||
{
|
||||
QBuffer buf(&ba);
|
||||
QVERIFY(buf.open(QIODevice::WriteOnly));
|
||||
QVERIFY(original.save(&buf, "BMP"));
|
||||
}
|
||||
QVERIFY(!ba.isEmpty());
|
||||
|
||||
QImage dest;
|
||||
QVERIFY(dest.loadFromData(ba, "BMP"));
|
||||
QVERIFY(!dest.isNull());
|
||||
|
||||
QCOMPARE(original, dest);
|
||||
|
||||
QVERIFY(!dest.loadFromData(QByteArray()));
|
||||
QVERIFY(dest.isNull());
|
||||
}
|
||||
|
||||
#if !defined(QT_NO_DATASTREAM)
|
||||
void tst_QImage::loadFromDataStream()
|
||||
{
|
||||
const QString prefix = QFINDTESTDATA("images/");
|
||||
if (prefix.isEmpty())
|
||||
QFAIL("can not find images directory!");
|
||||
const QString filePath = prefix + QLatin1String("image.jpg");
|
||||
|
||||
QImage original(filePath);
|
||||
QVERIFY(!original.isNull());
|
||||
|
||||
QByteArray ba;
|
||||
{
|
||||
QDataStream s(&ba, QIODevice::WriteOnly);
|
||||
s << original;
|
||||
}
|
||||
QVERIFY(!ba.isEmpty());
|
||||
|
||||
QImage dest;
|
||||
{
|
||||
QDataStream s(&ba, QIODevice::ReadOnly);
|
||||
s >> dest;
|
||||
}
|
||||
QVERIFY(!dest.isNull());
|
||||
|
||||
QCOMPARE(original, dest);
|
||||
|
||||
{
|
||||
ba.clear();
|
||||
QDataStream s(&ba, QIODevice::ReadOnly);
|
||||
s >> dest;
|
||||
}
|
||||
QVERIFY(dest.isNull());
|
||||
}
|
||||
#endif // QT_NO_DATASTREAM
|
||||
|
||||
void tst_QImage::setPixel_data()
|
||||
{
|
||||
QTest::addColumn<int>("format");
|
||||
|
@ -139,6 +139,12 @@ private slots:
|
||||
|
||||
void fromImage_crash();
|
||||
|
||||
void load();
|
||||
void loadFromData();
|
||||
#if !defined(QT_NO_DATASTREAM)
|
||||
void loadFromDataStream();
|
||||
#endif
|
||||
|
||||
void fromData();
|
||||
void loadFromDataNullValues();
|
||||
|
||||
@ -1191,6 +1197,85 @@ void tst_QPixmap::transformed2()
|
||||
QVERIFY(lenientCompare(actual, expected));
|
||||
}
|
||||
|
||||
void tst_QPixmap::load()
|
||||
{
|
||||
const QString prefix = QFINDTESTDATA("images/");
|
||||
if (prefix.isEmpty())
|
||||
QFAIL("can not find images directory!");
|
||||
const QString filePath = prefix + QLatin1String("designer.png");
|
||||
|
||||
QPixmap dest(filePath);
|
||||
QVERIFY(!dest.isNull());
|
||||
QVERIFY(!dest.load("image_that_does_not_exist.png"));
|
||||
QVERIFY(dest.isNull());
|
||||
QVERIFY(dest.load(filePath));
|
||||
QVERIFY(!dest.isNull());
|
||||
}
|
||||
|
||||
void tst_QPixmap::loadFromData()
|
||||
{
|
||||
const QString prefix = QFINDTESTDATA("images/");
|
||||
if (prefix.isEmpty())
|
||||
QFAIL("can not find images directory!");
|
||||
const QString filePath = prefix + QLatin1String("designer.png");
|
||||
|
||||
QPixmap original(filePath);
|
||||
QVERIFY(!original.isNull());
|
||||
|
||||
QByteArray ba;
|
||||
{
|
||||
QBuffer buf(&ba);
|
||||
QVERIFY(buf.open(QIODevice::WriteOnly));
|
||||
QVERIFY(original.save(&buf, "BMP"));
|
||||
}
|
||||
QVERIFY(!ba.isEmpty());
|
||||
|
||||
QPixmap dest;
|
||||
QVERIFY(dest.loadFromData(ba, "BMP"));
|
||||
QVERIFY(!dest.isNull());
|
||||
|
||||
QCOMPARE(original, dest);
|
||||
|
||||
QVERIFY(!dest.loadFromData(QByteArray()));
|
||||
QVERIFY(dest.isNull());
|
||||
}
|
||||
|
||||
#if !defined(QT_NO_DATASTREAM)
|
||||
void tst_QPixmap::loadFromDataStream()
|
||||
{
|
||||
const QString prefix = QFINDTESTDATA("images/");
|
||||
if (prefix.isEmpty())
|
||||
QFAIL("can not find images directory!");
|
||||
const QString filePath = prefix + QLatin1String("designer.png");
|
||||
|
||||
QPixmap original(filePath);
|
||||
QVERIFY(!original.isNull());
|
||||
|
||||
QByteArray ba;
|
||||
{
|
||||
QDataStream s(&ba, QIODevice::WriteOnly);
|
||||
s << original;
|
||||
}
|
||||
QVERIFY(!ba.isEmpty());
|
||||
|
||||
QPixmap dest;
|
||||
{
|
||||
QDataStream s(&ba, QIODevice::ReadOnly);
|
||||
s >> dest;
|
||||
}
|
||||
QVERIFY(!dest.isNull());
|
||||
|
||||
QCOMPARE(original, dest);
|
||||
|
||||
{
|
||||
ba.clear();
|
||||
QDataStream s(&ba, QIODevice::ReadOnly);
|
||||
s >> dest;
|
||||
}
|
||||
QVERIFY(dest.isNull());
|
||||
}
|
||||
#endif // QT_NO_DATASTREAM
|
||||
|
||||
void tst_QPixmap::fromImage_crash()
|
||||
{
|
||||
QImage *img = new QImage(64, 64, QImage::Format_ARGB32_Premultiplied);
|
||||
|
Loading…
Reference in New Issue
Block a user