1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39 
40 /*!
41     \class QImageWriter
42     \brief The QImageWriter class provides a format independent interface
43     for writing images to files or other devices.
44 
45     \inmodule QtGui
46     \reentrant
47     \ingroup painting
48     \ingroup io
49 
50     QImageWriter supports setting format specific options, such as
51     compression level and quality, prior to storing the
52     image. If you do not need such options, you can use QImage::save()
53     or QPixmap::save() instead.
54 
55     To store an image, you start by constructing a QImageWriter
56     object.  Pass either a file name or a device pointer, and the
57     image format to QImageWriter's constructor. You can then set
58     several options, such as quality (by calling setQuality()).
59     canWrite() returns \c true if QImageWriter can write the image
60     (i.e., the image format is supported and the device is open for
61     writing). Call write() to write the image to the device.
62 
63     If any error occurs when writing the image, write() will return
64     false. You can then call error() to find the type of error that
65     occurred, or errorString() to get a human readable description of
66     what went wrong.
67 
68     Call supportedImageFormats() for a list of formats that
69     QImageWriter can write. QImageWriter supports all built-in image
70     formats, in addition to any image format plugins that support
71     writing.
72 
73     \note QImageWriter assumes exclusive control over the file or
74     device that is assigned. Any attempts to modify the assigned file
75     or device during the lifetime of the QImageWriter object will
76     yield undefined results. If immediate access to a resource is
77     desired, the use of a scope is the recommended method.
78 
79     For example:
80 
81     \snippet qimagewriter/main.cpp 0
82 
83     \sa QImageReader, QImageIOHandler, QImageIOPlugin, QColorSpace
84 */
85 
86 /*!
87     \enum QImageWriter::ImageWriterError
88 
89     This enum describes errors that can occur when writing images with
90     QImageWriter.
91 
92     \value DeviceError QImageWriter encountered a device error when
93     writing the image data. Consult your device for more details on
94     what went wrong.
95 
96     \value UnsupportedFormatError Qt does not support the requested
97     image format.
98 
99     \value InvalidImageError An attempt was made to write an invalid QImage. An
100     example of an invalid image would be a null QImage.
101 
102     \value UnknownError An unknown error occurred. If you get this
103     value after calling write(), it is most likely caused by a bug in
104     QImageWriter.
105 */
106 
107 #include "qimagewriter.h"
108 
109 #include <qbytearray.h>
110 #include <qfile.h>
111 #include <qfileinfo.h>
112 #include <qimage.h>
113 #include <qimageiohandler.h>
114 #include <qset.h>
115 #include <qvariant.h>
116 
117 // factory loader
118 #include <qcoreapplication.h>
119 #include <private/qfactoryloader_p.h>
120 
121 // image handlers
122 #include <private/qbmphandler_p.h>
123 #include <private/qppmhandler_p.h>
124 #include <private/qxbmhandler_p.h>
125 #include <private/qxpmhandler_p.h>
126 #ifndef QT_NO_IMAGEFORMAT_PNG
127 #include <private/qpnghandler_p.h>
128 #endif
129 
130 #include <private/qimagereaderwriterhelpers_p.h>
131 
132 #include <algorithm>
133 
134 QT_BEGIN_NAMESPACE
135 
createWriteHandlerHelper(QIODevice * device,const QByteArray & format)136 static QImageIOHandler *createWriteHandlerHelper(QIODevice *device,
137     const QByteArray &format)
138 {
139     QByteArray form = format.toLower();
140     QByteArray suffix;
141     QImageIOHandler *handler = nullptr;
142 
143 #ifndef QT_NO_IMAGEFORMATPLUGIN
144     typedef QMultiMap<int, QString> PluginKeyMap;
145 
146     // check if any plugins can write the image
147     auto l = QImageReaderWriterHelpers::pluginLoader();
148     const PluginKeyMap keyMap = l->keyMap();
149     int suffixPluginIndex = -1;
150 #endif
151 
152     if (device && format.isEmpty()) {
153         // if there's no format, see if \a device is a file, and if so, find
154         // the file suffix and find support for that format among our plugins.
155         // this allows plugins to override our built-in handlers.
156         if (QFile *file = qobject_cast<QFile *>(device)) {
157             if (!(suffix = QFileInfo(file->fileName()).suffix().toLower().toLatin1()).isEmpty()) {
158 #ifndef QT_NO_IMAGEFORMATPLUGIN
159                 const int index = keyMap.key(QString::fromLatin1(suffix), -1);
160                 if (index != -1)
161                     suffixPluginIndex = index;
162 #endif
163             }
164         }
165     }
166 
167     QByteArray testFormat = !form.isEmpty() ? form : suffix;
168 
169 #ifndef QT_NO_IMAGEFORMATPLUGIN
170     if (suffixPluginIndex != -1) {
171         // when format is missing, check if we can find a plugin for the
172         // suffix.
173         const int index = keyMap.key(QString::fromLatin1(suffix), -1);
174         if (index != -1) {
175             QImageIOPlugin *plugin = qobject_cast<QImageIOPlugin *>(l->instance(index));
176             if (plugin && (plugin->capabilities(device, suffix) & QImageIOPlugin::CanWrite))
177                 handler = plugin->create(device, suffix);
178         }
179     }
180 #endif // QT_NO_IMAGEFORMATPLUGIN
181 
182     // check if any built-in handlers can write the image
183     if (!handler && !testFormat.isEmpty()) {
184         if (false) {
185 #ifndef QT_NO_IMAGEFORMAT_PNG
186         } else if (testFormat == "png") {
187             handler = new QPngHandler;
188 #endif
189 #ifndef QT_NO_IMAGEFORMAT_BMP
190         } else if (testFormat == "bmp") {
191             handler = new QBmpHandler;
192         } else if (testFormat == "dib") {
193             handler = new QBmpHandler(QBmpHandler::DibFormat);
194 #endif
195 #ifndef QT_NO_IMAGEFORMAT_XPM
196         } else if (testFormat == "xpm") {
197             handler = new QXpmHandler;
198 #endif
199 #ifndef QT_NO_IMAGEFORMAT_XBM
200         } else if (testFormat == "xbm") {
201             handler = new QXbmHandler;
202             handler->setOption(QImageIOHandler::SubType, testFormat);
203 #endif
204 #ifndef QT_NO_IMAGEFORMAT_PPM
205         } else if (testFormat == "pbm" || testFormat == "pbmraw" || testFormat == "pgm"
206                  || testFormat == "pgmraw" || testFormat == "ppm" || testFormat == "ppmraw") {
207             handler = new QPpmHandler;
208             handler->setOption(QImageIOHandler::SubType, testFormat);
209 #endif
210         }
211     }
212 
213 #ifndef QT_NO_IMAGEFORMATPLUGIN
214     if (!testFormat.isEmpty()) {
215         const int keyCount = keyMap.size();
216         for (int i = 0; i < keyCount; ++i) {
217             QImageIOPlugin *plugin = qobject_cast<QImageIOPlugin *>(l->instance(i));
218             if (plugin && (plugin->capabilities(device, testFormat) & QImageIOPlugin::CanWrite)) {
219                 delete handler;
220                 handler = plugin->create(device, testFormat);
221                 break;
222             }
223         }
224     }
225 #endif // QT_NO_IMAGEFORMATPLUGIN
226 
227     if (!handler)
228         return nullptr;
229 
230     handler->setDevice(device);
231     if (!testFormat.isEmpty())
232         handler->setFormat(testFormat);
233     return handler;
234 }
235 
236 class QImageWriterPrivate
237 {
238 public:
239     QImageWriterPrivate(QImageWriter *qq);
240 
241     bool canWriteHelper();
242 
243     // device
244     QByteArray format;
245     QIODevice *device;
246     bool deleteDevice;
247     QImageIOHandler *handler;
248 
249     // image options
250     int quality;
251     int compression;
252     float gamma;
253     QString description;
254     QString text;
255     QByteArray subType;
256     bool optimizedWrite;
257     bool progressiveScanWrite;
258     QImageIOHandler::Transformations transformation;
259 
260     // error
261     QImageWriter::ImageWriterError imageWriterError;
262     QString errorString;
263 
264     QImageWriter *q;
265 };
266 
267 /*!
268     \internal
269 */
QImageWriterPrivate(QImageWriter * qq)270 QImageWriterPrivate::QImageWriterPrivate(QImageWriter *qq)
271 {
272     device = nullptr;
273     deleteDevice = false;
274     handler = nullptr;
275     quality = -1;
276     compression = -1;
277     gamma = 0.0;
278     optimizedWrite = false;
279     progressiveScanWrite = false;
280     imageWriterError = QImageWriter::UnknownError;
281     errorString = QImageWriter::tr("Unknown error");
282     transformation = QImageIOHandler::TransformationNone;
283 
284     q = qq;
285 }
286 
canWriteHelper()287 bool QImageWriterPrivate::canWriteHelper()
288 {
289     if (!device) {
290         imageWriterError = QImageWriter::DeviceError;
291         errorString = QImageWriter::tr("Device is not set");
292         return false;
293     }
294     if (!device->isOpen()) {
295         if (!device->open(QIODevice::WriteOnly)) {
296             imageWriterError = QImageWriter::DeviceError;
297             errorString = QImageWriter::tr("Cannot open device for writing: %1").arg(device->errorString());
298             return false;
299         }
300     }
301     if (!device->isWritable()) {
302         imageWriterError = QImageWriter::DeviceError;
303         errorString = QImageWriter::tr("Device not writable");
304         return false;
305     }
306     if (!handler && (handler = createWriteHandlerHelper(device, format)) == nullptr) {
307         imageWriterError = QImageWriter::UnsupportedFormatError;
308         errorString = QImageWriter::tr("Unsupported image format");
309         return false;
310     }
311     return true;
312 }
313 
314 /*!
315     Constructs an empty QImageWriter object. Before writing, you must
316     call setFormat() to set an image format, then setDevice() or
317     setFileName().
318 */
QImageWriter()319 QImageWriter::QImageWriter()
320     : d(new QImageWriterPrivate(this))
321 {
322 }
323 
324 /*!
325     Constructs a QImageWriter object using the device \a device and
326     image format \a format.
327 */
QImageWriter(QIODevice * device,const QByteArray & format)328 QImageWriter::QImageWriter(QIODevice *device, const QByteArray &format)
329     : d(new QImageWriterPrivate(this))
330 {
331     d->device = device;
332     d->format = format;
333 }
334 
335 /*!
336     Constructs a QImageWriter objects that will write to a file with
337     the name \a fileName, using the image format \a format. If \a
338     format is not provided, QImageWriter will detect the image format
339     by inspecting the extension of \a fileName.
340 */
QImageWriter(const QString & fileName,const QByteArray & format)341 QImageWriter::QImageWriter(const QString &fileName, const QByteArray &format)
342     : QImageWriter(new QFile(fileName), format)
343 {
344     d->deleteDevice = true;
345 }
346 
347 /*!
348     Destructs the QImageWriter object.
349 */
~QImageWriter()350 QImageWriter::~QImageWriter()
351 {
352     if (d->deleteDevice)
353         delete d->device;
354     delete d->handler;
355     delete d;
356 }
357 
358 /*!
359     Sets the format QImageWriter will use when writing images, to \a
360     format. \a format is a case insensitive text string. Example:
361 
362     \snippet code/src_gui_image_qimagewriter.cpp 0
363 
364     You can call supportedImageFormats() for the full list of formats
365     QImageWriter supports.
366 
367     \sa format()
368 */
setFormat(const QByteArray & format)369 void QImageWriter::setFormat(const QByteArray &format)
370 {
371     d->format = format;
372 }
373 
374 /*!
375     Returns the format QImageWriter uses for writing images.
376 
377     \sa setFormat()
378 */
format() const379 QByteArray QImageWriter::format() const
380 {
381     return d->format;
382 }
383 
384 /*!
385     Sets QImageWriter's device to \a device. If a device has already
386     been set, the old device is removed from QImageWriter and is
387     otherwise left unchanged.
388 
389     If the device is not already open, QImageWriter will attempt to
390     open the device in \l QIODevice::WriteOnly mode by calling
391     open(). Note that this does not work for certain devices, such as
392     QProcess, QTcpSocket and QUdpSocket, where more logic is required
393     to open the device.
394 
395     \sa device(), setFileName()
396 */
setDevice(QIODevice * device)397 void QImageWriter::setDevice(QIODevice *device)
398 {
399     if (d->device && d->deleteDevice)
400         delete d->device;
401 
402     d->device = device;
403     d->deleteDevice = false;
404     delete d->handler;
405     d->handler = nullptr;
406 }
407 
408 /*!
409     Returns the device currently assigned to QImageWriter, or \nullptr
410     if no device has been assigned.
411 */
device() const412 QIODevice *QImageWriter::device() const
413 {
414     return d->device;
415 }
416 
417 /*!
418     Sets the file name of QImageWriter to \a fileName. Internally,
419     QImageWriter will create a QFile and open it in \l
420     QIODevice::WriteOnly mode, and use this file when writing images.
421 
422     \sa fileName(), setDevice()
423 */
setFileName(const QString & fileName)424 void QImageWriter::setFileName(const QString &fileName)
425 {
426     setDevice(new QFile(fileName));
427     d->deleteDevice = true;
428 }
429 
430 /*!
431     If the currently assigned device is a QFile, or if setFileName()
432     has been called, this function returns the name of the file
433     QImageWriter writes to. Otherwise (i.e., if no device has been
434     assigned or the device is not a QFile), an empty QString is
435     returned.
436 
437     \sa setFileName(), setDevice()
438 */
fileName() const439 QString QImageWriter::fileName() const
440 {
441     QFile *file = qobject_cast<QFile *>(d->device);
442     return file ? file->fileName() : QString();
443 }
444 
445 /*!
446     Sets the quality setting of the image format to \a quality.
447 
448     Some image formats, in particular lossy ones, entail a tradeoff between a)
449     visual quality of the resulting image, and b) encoding execution time and
450     compression level. This function sets the level of that tradeoff for image
451     formats that support it. For other formats, this value is ignored.
452 
453     The value range of \a quality depends on the image format. For example,
454     the "jpeg" format supports a quality range from 0 (low visual quality, high
455     compression) to 100 (high visual quality, low compression).
456 
457     \sa quality()
458 */
setQuality(int quality)459 void QImageWriter::setQuality(int quality)
460 {
461     d->quality = quality;
462 }
463 
464 /*!
465     Returns the quality setting of the image format.
466 
467     \sa setQuality()
468 */
quality() const469 int QImageWriter::quality() const
470 {
471     return d->quality;
472 }
473 
474 /*!
475     This is an image format specific function that set the compression
476     of an image. For image formats that do not support setting the
477     compression, this value is ignored.
478 
479     The value range of \a compression depends on the image format. For
480     example, the "tiff" format supports two values, 0(no compression) and
481     1(LZW-compression).
482 
483     \sa compression()
484 */
setCompression(int compression)485 void QImageWriter::setCompression(int compression)
486 {
487     d->compression = compression;
488 }
489 
490 /*!
491     Returns the compression of the image.
492 
493     \sa setCompression()
494 */
compression() const495 int QImageWriter::compression() const
496 {
497     return d->compression;
498 }
499 
500 #if QT_DEPRECATED_SINCE(5, 15)
501 /*!
502     \obsolete Use QColorSpace conversion on the QImage instead.
503 
504     This is an image format specific function that sets the gamma
505     level of the image to \a gamma. For image formats that do not
506     support setting the gamma level, this value is ignored.
507 
508     The value range of \a gamma depends on the image format. For
509     example, the "png" format supports a gamma range from 0.0 to 1.0.
510 
511     \sa quality()
512 */
setGamma(float gamma)513 void QImageWriter::setGamma(float gamma)
514 {
515     d->gamma = gamma;
516 }
517 
518 /*!
519     \obsolete Use QImage::colorSpace() and QColorSpace::gamma() instead.
520 
521     Returns the gamma level of the image.
522 
523     \sa setGamma()
524 */
gamma() const525 float QImageWriter::gamma() const
526 {
527     return d->gamma;
528 }
529 #endif
530 
531 /*!
532     \since 5.4
533 
534     This is an image format specific function that sets the
535     subtype of the image to \a type. Subtype can be used by
536     a handler to determine which format it should use while
537     saving the image.
538 
539     For example, saving an image in DDS format with A8R8G8R8 subtype:
540 
541     \snippet code/src_gui_image_qimagewriter.cpp 3
542 */
setSubType(const QByteArray & type)543 void QImageWriter::setSubType(const QByteArray &type)
544 {
545     d->subType = type;
546 }
547 
548 /*!
549     \since 5.4
550 
551     Returns the subtype of the image.
552 
553     \sa setSubType()
554 */
subType() const555 QByteArray QImageWriter::subType() const
556 {
557     return d->subType;
558 }
559 
560 /*!
561     \since 5.4
562 
563     Returns the list of subtypes supported by an image.
564 */
supportedSubTypes() const565 QList<QByteArray> QImageWriter::supportedSubTypes() const
566 {
567     if (!supportsOption(QImageIOHandler::SupportedSubTypes))
568         return QList<QByteArray>();
569     return qvariant_cast<QList<QByteArray> >(d->handler->option(QImageIOHandler::SupportedSubTypes));
570 }
571 
572 /*!
573     \since 5.5
574 
575     This is an image format-specific function which sets the \a optimize flags when
576     writing images. For image formats that do not support setting an \a optimize flag,
577     this value is ignored.
578 
579     The default is false.
580 
581     \sa optimizedWrite()
582 */
setOptimizedWrite(bool optimize)583 void QImageWriter::setOptimizedWrite(bool optimize)
584 {
585     d->optimizedWrite = optimize;
586 }
587 
588 /*!
589     \since 5.5
590 
591     Returns whether optimization has been turned on for writing the image.
592 
593     \sa setOptimizedWrite()
594 */
optimizedWrite() const595 bool QImageWriter::optimizedWrite() const
596 {
597     return d->optimizedWrite;
598 }
599 
600 /*!
601     \since 5.5
602 
603     This is an image format-specific function which turns on \a progressive scanning
604     when writing images. For image formats that do not support setting a \a progressive
605     scan flag, this value is ignored.
606 
607     The default is false.
608 
609     \sa progressiveScanWrite()
610 */
611 
setProgressiveScanWrite(bool progressive)612 void QImageWriter::setProgressiveScanWrite(bool progressive)
613 {
614     d->progressiveScanWrite = progressive;
615 }
616 
617 /*!
618     \since 5.5
619 
620     Returns whether the image should be written as a progressive image.
621 
622     \sa setProgressiveScanWrite()
623 */
progressiveScanWrite() const624 bool QImageWriter::progressiveScanWrite() const
625 {
626     return d->progressiveScanWrite;
627 }
628 
629 /*!
630     \since 5.5
631 
632     Sets the image transformations metadata including orientation to \a transform.
633 
634     If transformation metadata is not supported by the image format,
635     the transform is applied before writing.
636 
637     \sa transformation(), write()
638 */
setTransformation(QImageIOHandler::Transformations transform)639 void QImageWriter::setTransformation(QImageIOHandler::Transformations transform)
640 {
641     d->transformation = transform;
642 }
643 
644 /*!
645     \since 5.5
646 
647     Returns the transformation and orientation the image has been set to written with.
648 
649     \sa setTransformation()
650 */
transformation() const651 QImageIOHandler::Transformations QImageWriter::transformation() const
652 {
653     return d->transformation;
654 }
655 
656 #if QT_DEPRECATED_SINCE(5, 13)
657 /*!
658     \obsolete
659 
660     Use setText() instead.
661 
662     This is an image format specific function that sets the
663     description of the image to \a description. For image formats that
664     do not support setting the description, this value is ignored.
665 
666     The contents of \a description depends on the image format.
667 
668     \sa description()
669 */
setDescription(const QString & description)670 void QImageWriter::setDescription(const QString &description)
671 {
672     d->description = description;
673 }
674 
675 /*!
676     \obsolete
677 
678     Use QImageReader::text() instead.
679 
680     Returns the description of the image.
681 
682     \sa setDescription()
683 */
description() const684 QString QImageWriter::description() const
685 {
686     return d->description;
687 }
688 #endif
689 
690 /*!
691     \since 4.1
692 
693     Sets the image text associated with the key \a key to
694     \a text. This is useful for storing copyright information
695     or other information about the image. Example:
696 
697     \snippet code/src_gui_image_qimagewriter.cpp 1
698 
699     If you want to store a single block of data
700     (e.g., a comment), you can pass an empty key, or use
701     a generic key like "Description".
702 
703     The key and text will be embedded into the
704     image data after calling write().
705 
706     Support for this option is implemented through
707     QImageIOHandler::Description.
708 
709     \sa QImage::setText(), QImageReader::text()
710 */
setText(const QString & key,const QString & text)711 void QImageWriter::setText(const QString &key, const QString &text)
712 {
713     if (!d->description.isEmpty())
714         d->description += QLatin1String("\n\n");
715     d->description += key.simplified() + QLatin1String(": ") + text.simplified();
716 }
717 
718 /*!
719     Returns \c true if QImageWriter can write the image; i.e., the image
720     format is supported and the assigned device is open for reading.
721 
722     \sa write(), setDevice(), setFormat()
723 */
canWrite() const724 bool QImageWriter::canWrite() const
725 {
726     if (QFile *file = qobject_cast<QFile *>(d->device)) {
727         const bool remove = !file->isOpen() && !file->exists();
728         const bool result = d->canWriteHelper();
729 
730         // This looks strange (why remove if it doesn't exist?) but the issue
731         // here is that canWriteHelper will create the file in the process of
732         // checking if the write can succeed. If it subsequently fails, we
733         // should remove that empty file.
734         if (!result && remove)
735             file->remove();
736         return result;
737     }
738 
739     return d->canWriteHelper();
740 }
741 
742 extern void qt_imageTransform(QImage &src, QImageIOHandler::Transformations orient);
743 
744 /*!
745     Writes the image \a image to the assigned device or file
746     name. Returns \c true on success; otherwise returns \c false. If the
747     operation fails, you can call error() to find the type of error
748     that occurred, or errorString() to get a human readable
749     description of the error.
750 
751     \sa canWrite(), error(), errorString()
752 */
write(const QImage & image)753 bool QImageWriter::write(const QImage &image)
754 {
755     // Do this before canWrite, so it doesn't create a file if this fails.
756     if (Q_UNLIKELY(image.isNull())) {
757         d->imageWriterError = QImageWriter::InvalidImageError;
758         d->errorString = QImageWriter::tr("Image is empty");
759         return false;
760     }
761 
762     if (!canWrite())
763         return false;
764 
765     QImage img = image;
766     if (d->handler->supportsOption(QImageIOHandler::Quality))
767         d->handler->setOption(QImageIOHandler::Quality, d->quality);
768     if (d->handler->supportsOption(QImageIOHandler::CompressionRatio))
769         d->handler->setOption(QImageIOHandler::CompressionRatio, d->compression);
770     if (d->handler->supportsOption(QImageIOHandler::Gamma))
771         d->handler->setOption(QImageIOHandler::Gamma, d->gamma);
772     if (!d->description.isEmpty() && d->handler->supportsOption(QImageIOHandler::Description))
773         d->handler->setOption(QImageIOHandler::Description, d->description);
774     if (!d->subType.isEmpty() && d->handler->supportsOption(QImageIOHandler::SubType))
775         d->handler->setOption(QImageIOHandler::SubType, d->subType);
776     if (d->handler->supportsOption(QImageIOHandler::OptimizedWrite))
777         d->handler->setOption(QImageIOHandler::OptimizedWrite, d->optimizedWrite);
778     if (d->handler->supportsOption(QImageIOHandler::ProgressiveScanWrite))
779         d->handler->setOption(QImageIOHandler::ProgressiveScanWrite, d->progressiveScanWrite);
780     if (d->handler->supportsOption(QImageIOHandler::ImageTransformation))
781         d->handler->setOption(QImageIOHandler::ImageTransformation, int(d->transformation));
782     else
783         qt_imageTransform(img, d->transformation);
784 
785     if (!d->handler->write(img))
786         return false;
787     if (QFile *file = qobject_cast<QFile *>(d->device))
788         file->flush();
789     return true;
790 }
791 
792 /*!
793     Returns the type of error that last occurred.
794 
795     \sa ImageWriterError, errorString()
796 */
error() const797 QImageWriter::ImageWriterError QImageWriter::error() const
798 {
799     return d->imageWriterError;
800 }
801 
802 /*!
803     Returns a human readable description of the last error that occurred.
804 
805     \sa error()
806 */
errorString() const807 QString QImageWriter::errorString() const
808 {
809     return d->errorString;
810 }
811 
812 /*!
813     \since 4.2
814 
815     Returns \c true if the writer supports \a option; otherwise returns
816     false.
817 
818     Different image formats support different options. Call this function to
819     determine whether a certain option is supported by the current format. For
820     example, the PNG format allows you to embed text into the image's metadata
821     (see text()).
822 
823     \snippet code/src_gui_image_qimagewriter.cpp 2
824 
825     Options can be tested after the writer has been associated with a format.
826 
827     \sa QImageReader::supportsOption(), setFormat()
828 */
supportsOption(QImageIOHandler::ImageOption option) const829 bool QImageWriter::supportsOption(QImageIOHandler::ImageOption option) const
830 {
831     if (!d->handler && (d->handler = createWriteHandlerHelper(d->device, d->format)) == nullptr) {
832         d->imageWriterError = QImageWriter::UnsupportedFormatError;
833         d->errorString = QImageWriter::tr("Unsupported image format");
834         return false;
835     }
836 
837     return d->handler->supportsOption(option);
838 }
839 
840 /*!
841     Returns the list of image formats supported by QImageWriter.
842 
843     By default, Qt can write the following formats:
844 
845     \table
846     \header \li Format \li MIME type                    \li Description
847     \row    \li BMP    \li image/bmp                    \li Windows Bitmap
848     \row    \li JPG    \li image/jpeg                   \li Joint Photographic Experts Group
849     \row    \li PNG    \li image/png                    \li Portable Network Graphics
850     \row    \li PBM    \li image/x-portable-bitmap      \li Portable Bitmap
851     \row    \li PGM    \li image/x-portable-graymap     \li Portable Graymap
852     \row    \li PPM    \li image/x-portable-pixmap      \li Portable Pixmap
853     \row    \li XBM    \li image/x-xbitmap              \li X11 Bitmap
854     \row    \li XPM    \li image/x-xpixmap              \li X11 Pixmap
855     \endtable
856 
857     Reading and writing SVG files is supported through the \l{Qt SVG} module.
858     The \l{Qt Image Formats} module provides support for additional image formats.
859 
860     Note that the QApplication instance must be created before this function is
861     called.
862 
863     \sa setFormat(), QImageReader::supportedImageFormats(), QImageIOPlugin
864 */
supportedImageFormats()865 QList<QByteArray> QImageWriter::supportedImageFormats()
866 {
867     return QImageReaderWriterHelpers::supportedImageFormats(QImageReaderWriterHelpers::CanWrite);
868 }
869 
870 /*!
871     Returns the list of MIME types supported by QImageWriter.
872 
873     Note that the QApplication instance must be created before this function is
874     called.
875 
876     \sa supportedImageFormats(), QImageReader::supportedMimeTypes()
877 */
supportedMimeTypes()878 QList<QByteArray> QImageWriter::supportedMimeTypes()
879 {
880     return QImageReaderWriterHelpers::supportedMimeTypes(QImageReaderWriterHelpers::CanWrite);
881 }
882 
883 /*!
884     \since 5.12
885 
886     Returns the list of image formats corresponding to \a mimeType.
887 
888     Note that the QGuiApplication instance must be created before this function is
889     called.
890 
891     \sa supportedImageFormats(), supportedMimeTypes()
892 */
893 
imageFormatsForMimeType(const QByteArray & mimeType)894 QList<QByteArray> QImageWriter::imageFormatsForMimeType(const QByteArray &mimeType)
895 {
896     return QImageReaderWriterHelpers::imageFormatsForMimeType(mimeType,
897                                                               QImageReaderWriterHelpers::CanWrite);
898 }
899 
900 QT_END_NAMESPACE
901