145 bool autoDetectImageFormat,
146 bool ignoresFormatAndExtension)
148 if (!autoDetectImageFormat && format.isEmpty())
152 QImageIOHandler *handler =
nullptr;
155 qCDebug(lcImageReader) <<
"Finding read handler for" << device <<
"and format" << format;
157#if QT_CONFIG(imageformatplugin)
158 Q_CONSTINIT
static QBasicMutex mutex;
159 const auto locker = qt_scoped_lock(mutex);
161 typedef QMultiMap<
int, QString> PluginKeyMap;
164 auto l = QImageReaderWriterHelpers::pluginLoader();
165 const PluginKeyMap keyMap = l->keyMap();
167 qCDebug(lcImageReader) << keyMap.uniqueKeys().size() <<
"plugins available:" << keyMap.values();
169 int testFormatPluginIndex = -1;
172 if (device && format.isEmpty() && autoDetectImageFormat && !ignoresFormatAndExtension) {
174 if (QFile *file = qobject_cast<QFile *>(device)) {
175 suffix = QFileInfo(file->fileName()).suffix().toLower().toLatin1();
176 qCDebug(lcImageReader) <<
"Resolved format" << suffix <<
"from file name suffix";
180 QByteArray testFormat = !form.isEmpty() ? form : suffix;
181 if (ignoresFormatAndExtension)
184#if QT_CONFIG(imageformatplugin)
185 if (!testFormat.isEmpty()) {
188 qCDebug(lcImageReader) <<
"Checking if any plugins have explicitly declared support"
189 <<
"for the format" << testFormat;
190 const qint64 pos = device ? device->pos() : 0;
191 const auto keyList = keyMap.keys(QLatin1StringView(testFormat));
192 for (
int testIndex : keyList) {
193 QImageIOPlugin *plugin = qobject_cast<QImageIOPlugin *>(l->instance(testIndex));
194 if (plugin && plugin->capabilities(device, testFormat) & QImageIOPlugin::CanRead) {
195 qCDebug(lcImageReader) << plugin <<
"can read the format" << testFormat;
196 handler = plugin->create(device, testFormat);
197 testFormatPluginIndex = testIndex;
201 if (device && !device->isSequential())
208 if (!handler && !testFormat.isEmpty()) {
209 qCDebug(lcImageReader) <<
"Checking if any built in handlers recognize the format"
212#ifndef QT_NO_IMAGEFORMAT_PNG
213 }
else if (testFormat ==
"png") {
214 handler =
new QPngHandler;
216#ifndef QT_NO_IMAGEFORMAT_BMP
217 }
else if (testFormat ==
"bmp") {
218 handler =
new QBmpHandler;
219 }
else if (testFormat ==
"dib") {
220 handler =
new QBmpHandler(QBmpHandler::DibFormat);
222#ifndef QT_NO_IMAGEFORMAT_XPM
223 }
else if (testFormat ==
"xpm") {
224 handler =
new QXpmHandler;
226#ifndef QT_NO_IMAGEFORMAT_XBM
227 }
else if (testFormat ==
"xbm") {
228 handler =
new QXbmHandler;
229 handler->setOption(QImageIOHandler::SubType, testFormat);
231#ifndef QT_NO_IMAGEFORMAT_PPM
232 }
else if (testFormat ==
"pbm" || testFormat ==
"pbmraw" || testFormat ==
"pgm"
233 || testFormat ==
"pgmraw" || testFormat ==
"ppm" || testFormat ==
"ppmraw") {
234 handler =
new QPpmHandler;
235 handler->setOption(QImageIOHandler::SubType, testFormat);
240 qCDebug(lcImageReader) <<
"Using the built-in handler for format" << testFormat;
243#if QT_CONFIG(imageformatplugin)
244 if (!handler && !testFormat.isEmpty() && autoDetectImageFormat) {
247 qCDebug(lcImageReader) <<
"Checking if any plugins recognize the format" << testFormat;
249 const qint64 pos = device ? device->pos() : 0;
251 const int keyCount = keyMap.size();
252 for (
int i = 0; i < keyCount; ++i) {
253 if (i != testFormatPluginIndex) {
254 QImageIOPlugin *plugin = qobject_cast<QImageIOPlugin *>(l->instance(i));
255 if (plugin && plugin->capabilities(device, testFormat) & QImageIOPlugin::CanRead) {
256 qCDebug(lcImageReader) << plugin <<
"can read the format" << testFormat;
257 handler = plugin->create(device, testFormat);
262 if (device && !device->isSequential())
267 if (handler && device && !suffix.isEmpty()) {
268 Q_ASSERT(qobject_cast<QFile *>(device));
271 const qint64 pos = device->pos();
272 handler->setDevice(device);
274 handler->setFormat(form);
275 bool canRead = handler->canRead();
281 qCDebug(lcImageReader) << handler <<
"claimed support for" << suffix
282 <<
"but could not read the file";
289#if QT_CONFIG(imageformatplugin)
290 if (!handler && (autoDetectImageFormat || ignoresFormatAndExtension)) {
292 qCDebug(lcImageReader) <<
"Checking if any plugins recognize the format"
293 <<
"based on the contents in" << device;
294 const qint64 pos = device ? device->pos() : 0;
295 const int keyCount = keyMap.size();
296 for (
int i = 0; i < keyCount; ++i) {
297 if (i != testFormatPluginIndex) {
298 QImageIOPlugin *plugin = qobject_cast<QImageIOPlugin *>(l->instance(i));
299 if (plugin && plugin->capabilities(device, QByteArray()) & QImageIOPlugin::CanRead) {
300 handler = plugin->create(device, testFormat);
301 qCDebug(lcImageReader) << plugin <<
"can read the data in" << device;
306 if (device && !device->isSequential())
311 if (!handler && (autoDetectImageFormat || ignoresFormatAndExtension)) {
314 qCDebug(lcImageReader) <<
"Checking if any built in handlers recognize the format"
315 <<
"based on the contents in" << device;
316 int currentFormat = 0;
317 if (!suffix.isEmpty()) {
320 for (
int i = 0; i < _qt_NumFormats; ++i) {
321 if (_qt_BuiltInFormats[i].extension == suffix) {
329 int numFormats = _qt_NumFormats;
330 while (device && numFormats >= 0) {
331 const qint64 pos = device->pos();
332 switch (currentFormat) {
333#ifndef QT_NO_IMAGEFORMAT_PNG
335 if (QPngHandler::canRead(device))
336 handler =
new QPngHandler;
339#ifndef QT_NO_IMAGEFORMAT_BMP
341 if (QBmpHandler::canRead(device))
342 handler =
new QBmpHandler;
345#ifndef QT_NO_IMAGEFORMAT_XPM
347 if (QXpmHandler::canRead(device))
348 handler =
new QXpmHandler;
351#ifndef QT_NO_IMAGEFORMAT_PPM
355 if (QPpmHandler::canRead(device, &subType)) {
356 handler =
new QPpmHandler;
357 handler->setOption(QImageIOHandler::SubType, subType);
361#ifndef QT_NO_IMAGEFORMAT_XBM
363 if (QXbmHandler::canRead(device))
364 handler =
new QXbmHandler;
370 if (!device->isSequential())
374 qCDebug(lcImageReader,
"The %s built-in handler can read this data",
375 _qt_BuiltInFormats[currentFormat].extension);
381 if (currentFormat >= _qt_NumFormats)
387 qCDebug(lcImageReader,
"No handlers found. Giving up.");
392 handler->setDevice(device);
394 handler->setFormat(form);
473 imageReaderError = QImageReader::DeviceError;
474 errorString = QImageReader::tr(
"Invalid device");
480 Q_ASSERT(qobject_cast<QFile*>(device) !=
nullptr);
481 QFile *file =
static_cast<QFile *>(device);
483 if (file->error() == QFileDevice::ResourceError) {
485 imageReaderError = QImageReader::DeviceError;
486 errorString = file->errorString();
491 if (!format.isEmpty()) {
493 int currentFormatIndex = extensions.indexOf(format.toLower());
494 if (currentFormatIndex > 0)
495 extensions.swapItemsAt(0, currentFormatIndex);
498 int currentExtension = 0;
500 QString fileName = file->fileName();
504 file->setFileName(fileName + u'.'
505 + QLatin1StringView(extensions.at(currentExtension++).constData()));
506 fileIsOpen = file->open(QIODevice::ReadOnly);
507 }
while (!fileIsOpen && currentExtension < extensions.size());
510 imageReaderError = QImageReader::FileNotFoundError;
511 errorString = QImageReader::tr(
"File not found");
512 file->setFileName(fileName);
518 if ((handler = createReadHandlerHelper(device, format, autoDetectImageFormat, ignoresFormatAndExtension)) ==
nullptr) {
519 imageReaderError = QImageReader::UnsupportedFormatError;
520 errorString = QImageReader::tr(
"Unsupported image format");
1152bool QImageReader::read(QImage *image)
1155 qWarning(
"QImageReader::read: cannot read into null pointer");
1159 if (!d->initHandler())
1162 QSize scaledSize = d->scaledSize;
1163 if ((scaledSize.width() <= 0 && scaledSize.height() > 0) ||
1164 (scaledSize.height() <= 0 && scaledSize.width() > 0)) {
1167 if (
const QSize originalSize = size(); !originalSize.isEmpty()) {
1168 if (scaledSize.width() <= 0) {
1169 const auto ratio = qreal(scaledSize.height()) / originalSize.height();
1170 scaledSize.setWidth(qRound(originalSize.width() * ratio));
1172 const auto ratio = qreal(scaledSize.width()) / originalSize.width();
1173 scaledSize.setHeight(qRound(originalSize.height() * ratio));
1178 const bool supportScaledSize = supportsOption(QImageIOHandler::ScaledSize) && scaledSize.isValid();
1179 const bool supportClipRect = supportsOption(QImageIOHandler::ClipRect) && !d->clipRect.isNull();
1180 const bool supportScaledClipRect = supportsOption(QImageIOHandler::ScaledClipRect) && !d->scaledClipRect.isNull();
1183 if (supportScaledSize) {
1184 if (supportClipRect || d->clipRect.isNull()) {
1187 d->handler->setOption(QImageIOHandler::ScaledSize, scaledSize);
1190 if (supportClipRect)
1191 d->handler->setOption(QImageIOHandler::ClipRect, d->clipRect);
1192 if (supportScaledClipRect)
1193 d->handler->setOption(QImageIOHandler::ScaledClipRect, d->scaledClipRect);
1194 if (supportsOption(QImageIOHandler::Quality))
1195 d->handler->setOption(QImageIOHandler::Quality, d->quality);
1198 QString filename = fileName();
1199 if (Q_TRACE_ENABLED(QImageReader_read_before_reading)) {
1200 Q_TRACE(QImageReader_read_before_reading,
this, filename.isEmpty() ? u"unknown"_s : filename);
1203 const bool result = d->handler->read(image);
1205 Q_TRACE(QImageReader_read_after_reading,
this, result);
1208 d->imageReaderError = InvalidDataError;
1209 d->errorString = QImageReader::tr(
"Unable to read image data");
1215 if (supportClipRect) {
1216 if (supportScaledSize) {
1217 if (supportScaledClipRect) {
1221 if (!d->scaledClipRect.isNull())
1222 *image = image->copy(d->scaledClipRect);
1225 if (supportScaledClipRect) {
1229 if (scaledSize.isValid()) {
1230 *image = image->scaled(scaledSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
1232 if (d->scaledClipRect.isValid()) {
1233 *image = image->copy(d->scaledClipRect);
1238 if (supportScaledSize && d->clipRect.isNull()) {
1239 if (supportScaledClipRect) {
1243 if (d->scaledClipRect.isValid()) {
1244 *image = image->copy(d->scaledClipRect);
1248 if (supportScaledClipRect) {
1254 if (d->clipRect.isValid())
1255 *image = image->copy(d->clipRect);
1256 if (scaledSize.isValid())
1257 *image = image->scaled(scaledSize, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
1258 if (d->scaledClipRect.isValid())
1259 *image = image->copy(d->scaledClipRect);
1265 static bool disableNxImageLoading = !qEnvironmentVariableIsEmpty(
"QT_HIGHDPI_DISABLE_2X_IMAGE_LOADING");
1266 if (!disableNxImageLoading) {
1267 const QByteArray suffix = QFileInfo(filename).baseName().right(3).toLatin1();
1268 if (suffix.size() == 3 && suffix[0] ==
'@' && suffix[1] >=
'2' && suffix[1] <=
'9' && suffix[2] ==
'x')
1269 image->setDevicePixelRatio(suffix[1] -
'0');
1271 if (autoTransform())
1272 qt_imageTransform(*image, transformation());