summaryrefslogtreecommitdiffstats
path: root/src/gui/image/qimagereader.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/image/qimagereader.cpp')
-rw-r--r--src/gui/image/qimagereader.cpp118
1 files changed, 64 insertions, 54 deletions
diff --git a/src/gui/image/qimagereader.cpp b/src/gui/image/qimagereader.cpp
index f50dd8bdb7..9366e9cbb1 100644
--- a/src/gui/image/qimagereader.cpp
+++ b/src/gui/image/qimagereader.cpp
@@ -11,7 +11,6 @@
\inmodule QtGui
\reentrant
\ingroup painting
- \ingroup io
The most common way to read images is through QImage and QPixmap's
constructors, or by calling QImage::load() and
@@ -138,6 +137,9 @@ QT_BEGIN_NAMESPACE
using namespace QImageReaderWriterHelpers;
using namespace Qt::StringLiterals;
+Q_TRACE_POINT(qtgui, QImageReader_read_before_reading, QImageReader *reader, const QString &filename);
+Q_TRACE_POINT(qtgui, QImageReader_read_after_reading, QImageReader *reader, bool result);
+
static QImageIOHandler *createReadHandlerHelper(QIODevice *device,
const QByteArray &format,
bool autoDetectImageFormat,
@@ -461,7 +463,7 @@ public:
static int maxAlloc;
};
-int QImageReaderPrivate::maxAlloc = 128; // 128 MB is enough for an 8K 32bpp image
+int QImageReaderPrivate::maxAlloc = 256; // 256 MB is enough for an 8K 64bpp image
/*!
\internal
@@ -484,9 +486,9 @@ QImageReaderPrivate::QImageReaderPrivate(QImageReader *qq)
*/
QImageReaderPrivate::~QImageReaderPrivate()
{
+ delete handler;
if (deleteDevice)
delete device;
- delete handler;
}
/*!
@@ -527,14 +529,15 @@ bool QImageReaderPrivate::initHandler()
int currentExtension = 0;
QString fileName = file->fileName();
+ bool fileIsOpen;
do {
file->setFileName(fileName + u'.'
+ QLatin1StringView(extensions.at(currentExtension++).constData()));
- file->open(QIODevice::ReadOnly);
- } while (!file->isOpen() && currentExtension < extensions.size());
+ fileIsOpen = file->open(QIODevice::ReadOnly);
+ } while (!fileIsOpen && currentExtension < extensions.size());
- if (!device->isOpen()) {
+ if (!fileIsOpen) {
imageReaderError = QImageReader::FileNotFoundError;
errorString = QImageReader::tr("File not found");
file->setFileName(fileName); // restore the old file name
@@ -556,7 +559,7 @@ bool QImageReaderPrivate::initHandler()
*/
void QImageReaderPrivate::getText()
{
- if (text.isEmpty() && initHandler() && handler->supportsOption(QImageIOHandler::Description))
+ if (text.isEmpty() && q->supportsOption(QImageIOHandler::Description))
text = qt_getImageTextFromDescription(handler->option(QImageIOHandler::Description).toString());
}
@@ -746,12 +749,12 @@ bool QImageReader::decideFormatFromContent() const
*/
void QImageReader::setDevice(QIODevice *device)
{
+ delete d->handler;
+ d->handler = nullptr;
if (d->device && d->deleteDevice)
delete d->device;
d->device = device;
d->deleteDevice = false;
- delete d->handler;
- d->handler = nullptr;
d->text.clear();
}
@@ -846,10 +849,7 @@ int QImageReader::quality() const
*/
QSize QImageReader::size() const
{
- if (!d->initHandler())
- return QSize();
-
- if (d->handler->supportsOption(QImageIOHandler::Size))
+ if (supportsOption(QImageIOHandler::Size))
return d->handler->option(QImageIOHandler::Size).toSize();
return QSize();
@@ -869,10 +869,7 @@ QSize QImageReader::size() const
*/
QImage::Format QImageReader::imageFormat() const
{
- if (!d->initHandler())
- return QImage::Format_Invalid;
-
- if (d->handler->supportsOption(QImageIOHandler::ImageFormat))
+ if (supportsOption(QImageIOHandler::ImageFormat))
return (QImage::Format)d->handler->option(QImageIOHandler::ImageFormat).toInt();
return QImage::Format_Invalid;
@@ -944,6 +941,10 @@ QRect QImageReader::clipRect() const
support scaling), QImageReader will use QImage::scale() with
Qt::SmoothScaling.
+ If only one dimension is set in \a size, the other one will be
+ computed from the image's \l {size()} {natural size} so as to
+ maintain the aspect ratio.
+
\sa scaledSize(), setClipRect(), setScaledClipRect()
*/
void QImageReader::setScaledSize(const QSize &size)
@@ -994,9 +995,7 @@ QRect QImageReader::scaledClipRect() const
*/
void QImageReader::setBackgroundColor(const QColor &color)
{
- if (!d->initHandler())
- return;
- if (d->handler->supportsOption(QImageIOHandler::BackgroundColor))
+ if (supportsOption(QImageIOHandler::BackgroundColor))
d->handler->setOption(QImageIOHandler::BackgroundColor, color);
}
@@ -1011,9 +1010,7 @@ void QImageReader::setBackgroundColor(const QColor &color)
*/
QColor QImageReader::backgroundColor() const
{
- if (!d->initHandler())
- return QColor();
- if (d->handler->supportsOption(QImageIOHandler::BackgroundColor))
+ if (supportsOption(QImageIOHandler::BackgroundColor))
return qvariant_cast<QColor>(d->handler->option(QImageIOHandler::BackgroundColor));
return QColor();
}
@@ -1028,9 +1025,7 @@ QColor QImageReader::backgroundColor() const
*/
bool QImageReader::supportsAnimation() const
{
- if (!d->initHandler())
- return false;
- if (d->handler->supportsOption(QImageIOHandler::Animation))
+ if (supportsOption(QImageIOHandler::Animation))
return d->handler->option(QImageIOHandler::Animation).toBool();
return false;
}
@@ -1042,10 +1037,7 @@ bool QImageReader::supportsAnimation() const
*/
QByteArray QImageReader::subType() const
{
- if (!d->initHandler())
- return QByteArray();
-
- if (d->handler->supportsOption(QImageIOHandler::SubType))
+ if (supportsOption(QImageIOHandler::SubType))
return d->handler->option(QImageIOHandler::SubType).toByteArray();
return QByteArray();
}
@@ -1057,10 +1049,7 @@ QByteArray QImageReader::subType() const
*/
QList<QByteArray> QImageReader::supportedSubTypes() const
{
- if (!d->initHandler())
- return QList<QByteArray>();
-
- if (d->handler->supportsOption(QImageIOHandler::SupportedSubTypes))
+ if (supportsOption(QImageIOHandler::SupportedSubTypes))
return qvariant_cast<QList<QByteArray> >(d->handler->option(QImageIOHandler::SupportedSubTypes));
return QList<QByteArray>();
}
@@ -1076,7 +1065,7 @@ QList<QByteArray> QImageReader::supportedSubTypes() const
QImageIOHandler::Transformations QImageReader::transformation() const
{
int option = QImageIOHandler::TransformationNone;
- if (d->initHandler() && d->handler->supportsOption(QImageIOHandler::ImageTransformation))
+ if (supportsOption(QImageIOHandler::ImageTransformation))
option = d->handler->option(QImageIOHandler::ImageTransformation).toInt();
return QImageIOHandler::Transformations(option);
}
@@ -1194,20 +1183,39 @@ bool QImageReader::read(QImage *image)
if (!d->initHandler())
return false;
+ QSize scaledSize = d->scaledSize;
+ if ((scaledSize.width() <= 0 && scaledSize.height() > 0) ||
+ (scaledSize.height() <= 0 && scaledSize.width() > 0)) {
+ // if only one dimension is given, let's try to calculate the second one
+ // based on the original image size and maintaining the aspect ratio
+ if (const QSize originalSize = size(); !originalSize.isEmpty()) {
+ if (scaledSize.width() <= 0) {
+ const auto ratio = qreal(scaledSize.height()) / originalSize.height();
+ scaledSize.setWidth(qRound(originalSize.width() * ratio));
+ } else {
+ const auto ratio = qreal(scaledSize.width()) / originalSize.width();
+ scaledSize.setHeight(qRound(originalSize.height() * ratio));
+ }
+ }
+ }
+
+ const bool supportScaledSize = supportsOption(QImageIOHandler::ScaledSize) && scaledSize.isValid();
+ const bool supportClipRect = supportsOption(QImageIOHandler::ClipRect) && !d->clipRect.isNull();
+ const bool supportScaledClipRect = supportsOption(QImageIOHandler::ScaledClipRect) && !d->scaledClipRect.isNull();
+
// set the handler specific options.
- if (d->handler->supportsOption(QImageIOHandler::ScaledSize) && d->scaledSize.isValid()) {
- if ((d->handler->supportsOption(QImageIOHandler::ClipRect) && !d->clipRect.isNull())
- || d->clipRect.isNull()) {
+ if (supportScaledSize) {
+ if (supportClipRect || d->clipRect.isNull()) {
// Only enable the ScaledSize option if there is no clip rect, or
// if the handler also supports ClipRect.
- d->handler->setOption(QImageIOHandler::ScaledSize, d->scaledSize);
+ d->handler->setOption(QImageIOHandler::ScaledSize, scaledSize);
}
}
- if (d->handler->supportsOption(QImageIOHandler::ClipRect) && !d->clipRect.isNull())
+ if (supportClipRect)
d->handler->setOption(QImageIOHandler::ClipRect, d->clipRect);
- if (d->handler->supportsOption(QImageIOHandler::ScaledClipRect) && !d->scaledClipRect.isNull())
+ if (supportScaledClipRect)
d->handler->setOption(QImageIOHandler::ScaledClipRect, d->scaledClipRect);
- if (d->handler->supportsOption(QImageIOHandler::Quality))
+ if (supportsOption(QImageIOHandler::Quality))
d->handler->setOption(QImageIOHandler::Quality, d->quality);
// read the image
@@ -1228,9 +1236,9 @@ bool QImageReader::read(QImage *image)
// provide default implementations for any unsupported image
// options
- if (d->handler->supportsOption(QImageIOHandler::ClipRect) && !d->clipRect.isNull()) {
- if (d->handler->supportsOption(QImageIOHandler::ScaledSize) && d->scaledSize.isValid()) {
- if (d->handler->supportsOption(QImageIOHandler::ScaledClipRect) && !d->scaledClipRect.isNull()) {
+ if (supportClipRect) {
+ if (supportScaledSize) {
+ if (supportScaledClipRect) {
// all features are supported by the handler; nothing to do.
} else {
// the image is already scaled, so apply scaled clipping.
@@ -1238,12 +1246,12 @@ bool QImageReader::read(QImage *image)
*image = image->copy(d->scaledClipRect);
}
} else {
- if (d->handler->supportsOption(QImageIOHandler::ScaledClipRect) && !d->scaledClipRect.isNull()) {
+ if (supportScaledClipRect) {
// supports scaled clipping but not scaling, most
// likely a broken handler.
} else {
- if (d->scaledSize.isValid()) {
- *image = image->scaled(d->scaledSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
+ if (scaledSize.isValid()) {
+ *image = image->scaled(scaledSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
}
if (d->scaledClipRect.isValid()) {
*image = image->copy(d->scaledClipRect);
@@ -1251,8 +1259,8 @@ bool QImageReader::read(QImage *image)
}
}
} else {
- if (d->handler->supportsOption(QImageIOHandler::ScaledSize) && d->scaledSize.isValid() && d->clipRect.isNull()) {
- if (d->handler->supportsOption(QImageIOHandler::ScaledClipRect) && !d->scaledClipRect.isNull()) {
+ if (supportScaledSize && d->clipRect.isNull()) {
+ if (supportScaledClipRect) {
// nothing to do (ClipRect is ignored!)
} else {
// provide all workarounds.
@@ -1261,7 +1269,7 @@ bool QImageReader::read(QImage *image)
}
}
} else {
- if (d->handler->supportsOption(QImageIOHandler::ScaledClipRect) && !d->scaledClipRect.isNull()) {
+ if (supportScaledClipRect) {
// this makes no sense; a handler that supports
// ScaledClipRect but not ScaledSize is broken, and we
// can't work around it.
@@ -1269,8 +1277,8 @@ bool QImageReader::read(QImage *image)
// provide all workarounds.
if (d->clipRect.isValid())
*image = image->copy(d->clipRect);
- if (d->scaledSize.isValid())
- *image = image->scaled(d->scaledSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
+ if (scaledSize.isValid())
+ *image = image->scaled(scaledSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
if (d->scaledClipRect.isValid())
*image = image->copy(d->scaledClipRect);
}
@@ -1281,7 +1289,7 @@ bool QImageReader::read(QImage *image)
static bool disableNxImageLoading = !qEnvironmentVariableIsEmpty("QT_HIGHDPI_DISABLE_2X_IMAGE_LOADING");
if (!disableNxImageLoading) {
const QByteArray suffix = QFileInfo(filename).baseName().right(3).toLatin1();
- if (suffix.length() == 3 && suffix[0] == '@' && suffix[1] >= '2' && suffix[1] <= '9' && suffix[2] == 'x')
+ if (suffix.size() == 3 && suffix[0] == '@' && suffix[1] >= '2' && suffix[1] <= '9' && suffix[2] == 'x')
image->setDevicePixelRatio(suffix[1] - '0');
}
if (autoTransform())
@@ -1570,6 +1578,8 @@ int QImageReader::allocationLimit()
loading corrupt image files. It is normally not needed to change it. The
default limit is large enough for all commonly used image sizes.
+ At runtime, this value may be overridden by the environment variable \c QT_IMAGEIO_MAXALLOC.
+
\note The memory requirements are calculated for a minimum of 32 bits per pixel, since Qt will
typically convert an image to that depth when it is used in GUI. This means that the effective
allocation limit is significantly smaller than \a mbLimit when reading 1 bpp and 8 bpp images.