source: trunk/src/gui/image/qimagewriter.cpp@ 769

Last change on this file since 769 was 769, checked in by Dmitry A. Kuminov, 15 years ago

trunk: Merged in qt 4.6.3 sources from branches/vendor/nokia/qt.

File size: 20.2 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation (qt-info@nokia.com)
6**
7** This file is part of the QtGui module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at qt-info@nokia.com.
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42/*!
43 \class QImageWriter
44 \brief The QImageWriter class provides a format independent interface
45 for writing images to files or other devices.
46
47 \reentrant
48 \ingroup painting
49 \ingroup io
50
51 QImageWriter supports setting format specific options, such as the
52 gamma level, compression level and quality, prior to storing the
53 image. If you do not need such options, you can use QImage::save()
54 or QPixmap::save() instead.
55
56 To store an image, you start by constructing a QImageWriter
57 object. Pass either a file name or a device pointer, and the
58 image format to QImageWriter's constructor. You can then set
59 several options, such as the gamma level (by calling setGamma())
60 and quality (by calling setQuality()). canWrite() returns true if
61 QImageWriter can write the image (i.e., the image format is
62 supported and the device is open for writing). Call write() to
63 write the image to the device.
64
65 If any error occurs when writing the image, write() will return
66 false. You can then call error() to find the type of error that
67 occurred, or errorString() to get a human readable description of
68 what went wrong.
69
70 Call supportedImageFormats() for a list of formats that
71 QImageWriter can write. QImageWriter supports all built-in image
72 formats, in addition to any image format plugins that support
73 writing.
74
75 \sa QImageReader, QImageIOHandler, QImageIOPlugin
76*/
77
78/*!
79 \enum QImageWriter::ImageWriterError
80
81 This enum describes errors that can occur when writing images with
82 QImageWriter.
83
84 \value DeviceError QImageWriter encountered a device error when
85 writing the image data. Consult your device for more details on
86 what went wrong.
87
88 \value UnsupportedFormatError Qt does not support the requested
89 image format.
90
91 \value UnknownError An unknown error occurred. If you get this
92 value after calling write(), it is most likely caused by a bug in
93 QImageWriter.
94*/
95
96#include "qimagewriter.h"
97
98#include <qbytearray.h>
99#include <qfile.h>
100#include <qfileinfo.h>
101#include <qimageiohandler.h>
102#include <qset.h>
103#include <qvariant.h>
104
105// factory loader
106#include <qcoreapplication.h>
107#include <private/qfactoryloader_p.h>
108
109// image handlers
110#include <private/qbmphandler_p.h>
111#include <private/qppmhandler_p.h>
112#include <private/qxbmhandler_p.h>
113#include <private/qxpmhandler_p.h>
114#ifndef QT_NO_IMAGEFORMAT_PNG
115#include <private/qpnghandler_p.h>
116#endif
117
118QT_BEGIN_NAMESPACE
119
120#if !defined (QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS)
121Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader,
122 (QImageIOHandlerFactoryInterface_iid, QLatin1String("/imageformats")))
123#endif
124
125static QImageIOHandler *createWriteHandlerHelper(QIODevice *device,
126 const QByteArray &format)
127{
128 QByteArray form = format.toLower();
129 QByteArray suffix;
130 QImageIOHandler *handler = 0;
131
132#if !defined (QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS)
133 // check if any plugins can write the image
134 QFactoryLoader *l = loader();
135 QStringList keys = l->keys();
136 int suffixPluginIndex = -1;
137#endif
138
139 if (device && format.isEmpty()) {
140 // if there's no format, see if \a device is a file, and if so, find
141 // the file suffix and find support for that format among our plugins.
142 // this allows plugins to override our built-in handlers.
143 if (QFile *file = qobject_cast<QFile *>(device)) {
144 if (!(suffix = QFileInfo(file->fileName()).suffix().toLower().toLatin1()).isEmpty()) {
145#if !defined (QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS)
146 int index = keys.indexOf(QString::fromLatin1(suffix));
147 if (index != -1)
148 suffixPluginIndex = index;
149#endif
150 }
151 }
152 }
153
154 QByteArray testFormat = !form.isEmpty() ? form : suffix;
155
156#if !defined (QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS)
157 if (suffixPluginIndex != -1) {
158 // when format is missing, check if we can find a plugin for the
159 // suffix.
160 QImageIOPlugin *plugin = qobject_cast<QImageIOPlugin *>(l->instance(QString::fromLatin1(suffix)));
161 if (plugin && (plugin->capabilities(device, suffix) & QImageIOPlugin::CanWrite))
162 handler = plugin->create(device, suffix);
163 }
164#endif // Q_NO_LIBRARY
165
166 // check if any built-in handlers can write the image
167 if (!handler && !testFormat.isEmpty()) {
168 if (false) {
169#ifndef QT_NO_IMAGEFORMAT_PNG
170 } else if (testFormat == "png") {
171 handler = new QPngHandler;
172#endif
173#ifndef QT_NO_IMAGEFORMAT_BMP
174 } else if (testFormat == "bmp") {
175 handler = new QBmpHandler;
176#endif
177#ifndef QT_NO_IMAGEFORMAT_XPM
178 } else if (testFormat == "xpm") {
179 handler = new QXpmHandler;
180#endif
181#ifndef QT_NO_IMAGEFORMAT_XBM
182 } else if (testFormat == "xbm") {
183 handler = new QXbmHandler;
184 handler->setOption(QImageIOHandler::SubType, testFormat);
185#endif
186#ifndef QT_NO_IMAGEFORMAT_PPM
187 } else if (testFormat == "pbm" || testFormat == "pbmraw" || testFormat == "pgm"
188 || testFormat == "pgmraw" || testFormat == "ppm" || testFormat == "ppmraw") {
189 handler = new QPpmHandler;
190 handler->setOption(QImageIOHandler::SubType, testFormat);
191#endif
192 }
193 }
194
195#if !defined (QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS)
196 if (!testFormat.isEmpty()) {
197 for (int i = 0; i < keys.size(); ++i) {
198 QImageIOPlugin *plugin = qobject_cast<QImageIOPlugin *>(l->instance(keys.at(i)));
199 if (plugin && (plugin->capabilities(device, testFormat) & QImageIOPlugin::CanWrite)) {
200 delete handler;
201 handler = plugin->create(device, testFormat);
202 break;
203 }
204 }
205 }
206#endif
207
208 if (!handler)
209 return 0;
210
211 handler->setDevice(device);
212 if (!testFormat.isEmpty())
213 handler->setFormat(testFormat);
214 return handler;
215}
216
217class QImageWriterPrivate
218{
219public:
220 QImageWriterPrivate(QImageWriter *qq);
221
222 // device
223 QByteArray format;
224 QIODevice *device;
225 bool deleteDevice;
226 QImageIOHandler *handler;
227
228 // image options
229 int quality;
230 int compression;
231 float gamma;
232 QString description;
233 QString text;
234
235 // error
236 QImageWriter::ImageWriterError imageWriterError;
237 QString errorString;
238
239 QImageWriter *q;
240};
241
242/*!
243 \internal
244*/
245QImageWriterPrivate::QImageWriterPrivate(QImageWriter *qq)
246{
247 device = 0;
248 deleteDevice = false;
249 handler = 0;
250 quality = -1;
251 compression = 0;
252 gamma = 0.0;
253 imageWriterError = QImageWriter::UnknownError;
254 errorString = QT_TRANSLATE_NOOP(QImageWriter, QLatin1String("Unknown error"));
255
256 q = qq;
257}
258
259/*!
260 Constructs an empty QImageWriter object. Before writing, you must
261 call setFormat() to set an image format, then setDevice() or
262 setFileName().
263*/
264QImageWriter::QImageWriter()
265 : d(new QImageWriterPrivate(this))
266{
267}
268
269/*!
270 Constructs a QImageWriter object using the device \a device and
271 image format \a format.
272*/
273QImageWriter::QImageWriter(QIODevice *device, const QByteArray &format)
274 : d(new QImageWriterPrivate(this))
275{
276 d->device = device;
277 d->format = format;
278}
279
280/*!
281 Constructs a QImageWriter objects that will write to a file with
282 the name \a fileName, using the image format \a format. If \a
283 format is not provided, QImageWriter will detect the image format
284 by inspecting the extension of \a fileName.
285*/
286QImageWriter::QImageWriter(const QString &fileName, const QByteArray &format)
287 : d(new QImageWriterPrivate(this))
288{
289 QFile *file = new QFile(fileName);
290 d->device = file;
291 d->deleteDevice = true;
292 d->format = format;
293}
294
295/*!
296 Destructs the QImageWriter object.
297*/
298QImageWriter::~QImageWriter()
299{
300 if (d->deleteDevice)
301 delete d->device;
302 delete d->handler;
303 delete d;
304}
305
306/*!
307 Sets the format QImageWriter will use when writing images, to \a
308 format. \a format is a case insensitive text string. Example:
309
310 \snippet doc/src/snippets/code/src_gui_image_qimagewriter.cpp 0
311
312 You can call supportedImageFormats() for the full list of formats
313 QImageWriter supports.
314
315 \sa format()
316*/
317void QImageWriter::setFormat(const QByteArray &format)
318{
319 d->format = format;
320}
321
322/*!
323 Returns the format QImageWriter uses for writing images.
324
325 \sa setFormat()
326*/
327QByteArray QImageWriter::format() const
328{
329 return d->format;
330}
331
332/*!
333 Sets QImageWriter's device to \a device. If a device has already
334 been set, the old device is removed from QImageWriter and is
335 otherwise left unchanged.
336
337 If the device is not already open, QImageWriter will attempt to
338 open the device in \l QIODevice::WriteOnly mode by calling
339 open(). Note that this does not work for certain devices, such as
340 QProcess, QTcpSocket and QUdpSocket, where more logic is required
341 to open the device.
342
343 \sa device(), setFileName()
344*/
345void QImageWriter::setDevice(QIODevice *device)
346{
347 if (d->device && d->deleteDevice)
348 delete d->device;
349
350 d->device = device;
351 d->deleteDevice = false;
352 delete d->handler;
353 d->handler = 0;
354}
355
356/*!
357 Returns the device currently assigned to QImageWriter, or 0 if no
358 device has been assigned.
359*/
360QIODevice *QImageWriter::device() const
361{
362 return d->device;
363}
364
365/*!
366 Sets the file name of QImageWriter to \a fileName. Internally,
367 QImageWriter will create a QFile and open it in \l
368 QIODevice::WriteOnly mode, and use this file when writing images.
369
370 \sa fileName(), setDevice()
371*/
372void QImageWriter::setFileName(const QString &fileName)
373{
374 setDevice(new QFile(fileName));
375 d->deleteDevice = true;
376}
377
378/*!
379 If the currently assigned device is a QFile, or if setFileName()
380 has been called, this function returns the name of the file
381 QImageWriter writes to. Otherwise (i.e., if no device has been
382 assigned or the device is not a QFile), an empty QString is
383 returned.
384
385 \sa setFileName(), setDevice()
386*/
387QString QImageWriter::fileName() const
388{
389 QFile *file = qobject_cast<QFile *>(d->device);
390 return file ? file->fileName() : QString();
391}
392
393/*!
394 This is an image format specific function that sets the quality
395 level of the image to \a quality. For image formats that do not
396 support setting the quality, this value is ignored.
397
398 The value range of \a quality depends on the image format. For
399 example, the "jpeg" format supports a quality range from 0 (low
400 quality, high compression) to 100 (high quality, low compression).
401
402 \sa quality()
403*/
404void QImageWriter::setQuality(int quality)
405{
406 d->quality = quality;
407}
408
409/*!
410 Returns the quality level of the image.
411
412 \sa setQuality()
413*/
414int QImageWriter::quality() const
415{
416 return d->quality;
417}
418
419/*!
420 This is an image format specific function that set the compression
421 of an image. For image formats that do not support setting the
422 compression, this value is ignored.
423
424 The value range of \a compression depends on the image format. For
425 example, the "tiff" format supports two values, 0(no compression) and
426 1(LZW-compression).
427
428 \sa compression()
429*/
430void QImageWriter::setCompression(int compression)
431{
432 d->compression = compression;
433}
434
435/*!
436 Returns the compression of the image.
437
438 \sa setCompression()
439*/
440int QImageWriter::compression() const
441{
442 return d->compression;
443}
444
445/*!
446 This is an image format specific function that sets the gamma
447 level of the image to \a gamma. For image formats that do not
448 support setting the gamma level, this value is ignored.
449
450 The value range of \a gamma depends on the image format. For
451 example, the "png" format supports a gamma range from 0.0 to 1.0.
452
453 \sa quality()
454*/
455void QImageWriter::setGamma(float gamma)
456{
457 d->gamma = gamma;
458}
459
460/*!
461 Returns the gamma level of the image.
462
463 \sa setGamma()
464*/
465float QImageWriter::gamma() const
466{
467 return d->gamma;
468}
469
470/*!
471 \obsolete
472
473 Use setText() instead.
474
475 This is an image format specific function that sets the
476 description of the image to \a description. For image formats that
477 do not support setting the description, this value is ignored.
478
479 The contents of \a description depends on the image format.
480
481 \sa description()
482*/
483void QImageWriter::setDescription(const QString &description)
484{
485 d->description = description;
486}
487
488/*!
489 \obsolete
490
491 Use QImageReader::text() instead.
492
493 Returns the description of the image.
494
495 \sa setDescription()
496*/
497QString QImageWriter::description() const
498{
499 return d->description;
500}
501
502/*!
503 \since 4.1
504
505 Sets the image text associated with the key \a key to
506 \a text. This is useful for storing copyright information
507 or other information about the image. Example:
508
509 \snippet doc/src/snippets/code/src_gui_image_qimagewriter.cpp 1
510
511 If you want to store a single block of data
512 (e.g., a comment), you can pass an empty key, or use
513 a generic key like "Description".
514
515 The key and text will be embedded into the
516 image data after calling write().
517
518 Support for this option is implemented through
519 QImageIOHandler::Description.
520
521 \sa QImage::setText(), QImageReader::text()
522*/
523void QImageWriter::setText(const QString &key, const QString &text)
524{
525 if (!d->description.isEmpty())
526 d->description += QLatin1String("\n\n");
527 d->description += key.simplified() + QLatin1String(": ") + text.simplified();
528}
529
530/*!
531 Returns true if QImageWriter can write the image; i.e., the image
532 format is supported and the assigned device is open for reading.
533
534 \sa write(), setDevice(), setFormat()
535*/
536bool QImageWriter::canWrite() const
537{
538 if (d->device && !d->handler && (d->handler = createWriteHandlerHelper(d->device, d->format)) == 0) {
539 d->imageWriterError = QImageWriter::UnsupportedFormatError;
540 d->errorString = QT_TRANSLATE_NOOP(QImageWriter,
541 QLatin1String("Unsupported image format"));
542 return false;
543 }
544 if (d->device && !d->device->isOpen())
545 d->device->open(QIODevice::WriteOnly);
546 if (!d->device || !d->device->isWritable()) {
547 d->imageWriterError = QImageWriter::DeviceError;
548 d->errorString = QT_TRANSLATE_NOOP(QImageWriter,
549 QLatin1String("Device not writable"));
550 return false;
551 }
552 return true;
553}
554
555/*!
556 Writes the image \a image to the assigned device or file
557 name. Returns true on success; otherwise returns false. If the
558 operation fails, you can call error() to find the type of error
559 that occurred, or errorString() to get a human readable
560 description of the error.
561
562 \sa canWrite(), error(), errorString()
563*/
564bool QImageWriter::write(const QImage &image)
565{
566 if (!canWrite())
567 return false;
568
569 if (d->handler->supportsOption(QImageIOHandler::Quality))
570 d->handler->setOption(QImageIOHandler::Quality, d->quality);
571 if (d->handler->supportsOption(QImageIOHandler::CompressionRatio))
572 d->handler->setOption(QImageIOHandler::CompressionRatio, d->compression);
573 if (d->handler->supportsOption(QImageIOHandler::Gamma))
574 d->handler->setOption(QImageIOHandler::Gamma, d->gamma);
575 if (!d->description.isEmpty() && d->handler->supportsOption(QImageIOHandler::Description))
576 d->handler->setOption(QImageIOHandler::Description, d->description);
577
578 if (!d->handler->write(image))
579 return false;
580 if (QFile *file = qobject_cast<QFile *>(d->device))
581 file->flush();
582 return true;
583}
584
585/*!
586 Returns the type of error that last occurred.
587
588 \sa ImageWriterError, errorString()
589*/
590QImageWriter::ImageWriterError QImageWriter::error() const
591{
592 return d->imageWriterError;
593}
594
595/*!
596 Returns a human readable description of the last error that occurred.
597
598 \sa error()
599*/
600QString QImageWriter::errorString() const
601{
602 return d->errorString;
603}
604
605/*!
606 \since 4.2
607
608 Returns true if the writer supports \a option; otherwise returns
609 false.
610
611 Different image formats support different options. Call this function to
612 determine whether a certain option is supported by the current format. For
613 example, the PNG format allows you to embed text into the image's metadata
614 (see text()).
615
616 \snippet doc/src/snippets/code/src_gui_image_qimagewriter.cpp 2
617
618 Options can be tested after the writer has been associated with a format.
619
620 \sa QImageReader::supportsOption(), setFormat()
621*/
622bool QImageWriter::supportsOption(QImageIOHandler::ImageOption option) const
623{
624 if (!d->handler && (d->handler = createWriteHandlerHelper(d->device, d->format)) == 0) {
625 d->imageWriterError = QImageWriter::UnsupportedFormatError;
626 d->errorString = QT_TRANSLATE_NOOP(QImageWriter,
627 QLatin1String("Unsupported image format"));
628 return false;
629 }
630
631 return d->handler->supportsOption(option);
632}
633
634/*!
635 Returns the list of image formats supported by QImageWriter.
636
637 By default, Qt can write the following formats:
638
639 \table
640 \header \o Format \o Description
641 \row \o BMP \o Windows Bitmap
642 \row \o JPG \o Joint Photographic Experts Group
643 \row \o JPEG \o Joint Photographic Experts Group
644 \row \o PNG \o Portable Network Graphics
645 \row \o PPM \o Portable Pixmap
646 \row \o TIFF \o Tagged Image File Format
647 \row \o XBM \o X11 Bitmap
648 \row \o XPM \o X11 Pixmap
649 \endtable
650
651 Reading and writing SVG files is supported through Qt's
652 \l{QtSvg Module}{SVG Module}.
653
654 \sa setFormat(), QImageReader::supportedImageFormats(), QImageIOPlugin
655*/
656QList<QByteArray> QImageWriter::supportedImageFormats()
657{
658 QSet<QByteArray> formats;
659 formats << "bmp";
660#ifndef QT_NO_IMAGEFORMAT_PPM
661 formats << "ppm";
662#endif
663#ifndef QT_NO_IMAGEFORMAT_XBM
664 formats << "xbm";
665#endif
666#ifndef QT_NO_IMAGEFORMAT_XPM
667 formats << "xpm";
668#endif
669#ifndef QT_NO_IMAGEFORMAT_PNG
670 formats << "png";
671#endif
672
673#if !defined (QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS)
674 QFactoryLoader *l = loader();
675 QStringList keys = l->keys();
676 for (int i = 0; i < keys.count(); ++i) {
677 QImageIOPlugin *plugin = qobject_cast<QImageIOPlugin *>(l->instance(keys.at(i)));
678 if (plugin && (plugin->capabilities(0, keys.at(i).toLatin1()) & QImageIOPlugin::CanWrite) != 0)
679 formats << keys.at(i).toLatin1();
680 }
681#endif // QT_NO_LIBRARY
682
683 QList<QByteArray> sortedFormats;
684 for (QSet<QByteArray>::ConstIterator it = formats.constBegin(); it != formats.constEnd(); ++it)
685 sortedFormats << *it;
686
687 qSort(sortedFormats);
688 return sortedFormats;
689}
690
691QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.