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

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

trunk: Merged in qt 4.6.1 sources.

File size: 20.2 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
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 [email protected].
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 handler = plugin->create(device, testFormat);
201 break;
202 }
203 }
204 }
205#endif
206
207 if (!handler)
208 return 0;
209
210 handler->setDevice(device);
211 if (!testFormat.isEmpty())
212 handler->setFormat(testFormat);
213 return handler;
214}
215
216class QImageWriterPrivate
217{
218public:
219 QImageWriterPrivate(QImageWriter *qq);
220
221 // device
222 QByteArray format;
223 QIODevice *device;
224 bool deleteDevice;
225 QImageIOHandler *handler;
226
227 // image options
228 int quality;
229 int compression;
230 float gamma;
231 QString description;
232 QString text;
233
234 // error
235 QImageWriter::ImageWriterError imageWriterError;
236 QString errorString;
237
238 QImageWriter *q;
239};
240
241/*!
242 \internal
243*/
244QImageWriterPrivate::QImageWriterPrivate(QImageWriter *qq)
245{
246 device = 0;
247 deleteDevice = false;
248 handler = 0;
249 quality = -1;
250 compression = 0;
251 gamma = 0.0;
252 imageWriterError = QImageWriter::UnknownError;
253 errorString = QT_TRANSLATE_NOOP(QImageWriter, QLatin1String("Unknown error"));
254
255 q = qq;
256}
257
258/*!
259 Constructs an empty QImageWriter object. Before writing, you must
260 call setFormat() to set an image format, then setDevice() or
261 setFileName().
262*/
263QImageWriter::QImageWriter()
264 : d(new QImageWriterPrivate(this))
265{
266}
267
268/*!
269 Constructs a QImageWriter object using the device \a device and
270 image format \a format.
271*/
272QImageWriter::QImageWriter(QIODevice *device, const QByteArray &format)
273 : d(new QImageWriterPrivate(this))
274{
275 d->device = device;
276 d->format = format;
277}
278
279/*!
280 Constructs a QImageWriter objects that will write to a file with
281 the name \a fileName, using the image format \a format. If \a
282 format is not provided, QImageWriter will detect the image format
283 by inspecting the extension of \a fileName.
284*/
285QImageWriter::QImageWriter(const QString &fileName, const QByteArray &format)
286 : d(new QImageWriterPrivate(this))
287{
288 QFile *file = new QFile(fileName);
289 d->device = file;
290 d->deleteDevice = true;
291 d->format = format;
292}
293
294/*!
295 Destructs the QImageWriter object.
296*/
297QImageWriter::~QImageWriter()
298{
299 if (d->deleteDevice)
300 delete d->device;
301 delete d->handler;
302 delete d;
303}
304
305/*!
306 Sets the format QImageWriter will use when writing images, to \a
307 format. \a format is a case insensitive text string. Example:
308
309 \snippet doc/src/snippets/code/src_gui_image_qimagewriter.cpp 0
310
311 You can call supportedImageFormats() for the full list of formats
312 QImageWriter supports.
313
314 \sa format()
315*/
316void QImageWriter::setFormat(const QByteArray &format)
317{
318 d->format = format;
319}
320
321/*!
322 Returns the format QImageWriter uses for writing images.
323
324 \sa setFormat()
325*/
326QByteArray QImageWriter::format() const
327{
328 return d->format;
329}
330
331/*!
332 Sets QImageWriter's device to \a device. If a device has already
333 been set, the old device is removed from QImageWriter and is
334 otherwise left unchanged.
335
336 If the device is not already open, QImageWriter will attempt to
337 open the device in \l QIODevice::WriteOnly mode by calling
338 open(). Note that this does not work for certain devices, such as
339 QProcess, QTcpSocket and QUdpSocket, where more logic is required
340 to open the device.
341
342 \sa device(), setFileName()
343*/
344void QImageWriter::setDevice(QIODevice *device)
345{
346 if (d->device && d->deleteDevice)
347 delete d->device;
348
349 d->device = device;
350 d->deleteDevice = false;
351 delete d->handler;
352 d->handler = 0;
353}
354
355/*!
356 Returns the device currently assigned to QImageWriter, or 0 if no
357 device has been assigned.
358*/
359QIODevice *QImageWriter::device() const
360{
361 return d->device;
362}
363
364/*!
365 Sets the file name of QImageWriter to \a fileName. Internally,
366 QImageWriter will create a QFile and open it in \l
367 QIODevice::WriteOnly mode, and use this file when writing images.
368
369 \sa fileName(), setDevice()
370*/
371void QImageWriter::setFileName(const QString &fileName)
372{
373 setDevice(new QFile(fileName));
374 d->deleteDevice = true;
375}
376
377/*!
378 If the currently assigned device is a QFile, or if setFileName()
379 has been called, this function returns the name of the file
380 QImageWriter writes to. Otherwise (i.e., if no device has been
381 assigned or the device is not a QFile), an empty QString is
382 returned.
383
384 \sa setFileName(), setDevice()
385*/
386QString QImageWriter::fileName() const
387{
388 QFile *file = qobject_cast<QFile *>(d->device);
389 return file ? file->fileName() : QString();
390}
391
392/*!
393 This is an image format specific function that sets the quality
394 level of the image to \a quality. For image formats that do not
395 support setting the quality, this value is ignored.
396
397 The value range of \a quality depends on the image format. For
398 example, the "jpeg" format supports a quality range from 0 (low
399 quality, high compression) to 100 (high quality, low compression).
400
401 \sa quality()
402*/
403void QImageWriter::setQuality(int quality)
404{
405 d->quality = quality;
406}
407
408/*!
409 Returns the quality level of the image.
410
411 \sa setQuality()
412*/
413int QImageWriter::quality() const
414{
415 return d->quality;
416}
417
418/*!
419 This is an image format specific function that set the compression
420 of an image. For image formats that do not support setting the
421 compression, this value is ignored.
422
423 The value range of \a compression depends on the image format. For
424 example, the "tiff" format supports two values, 0(no compression) and
425 1(LZW-compression).
426
427 \sa compression()
428*/
429void QImageWriter::setCompression(int compression)
430{
431 d->compression = compression;
432}
433
434/*!
435 Returns the compression of the image.
436
437 \sa setCompression()
438*/
439int QImageWriter::compression() const
440{
441 return d->compression;
442}
443
444/*!
445 This is an image format specific function that sets the gamma
446 level of the image to \a gamma. For image formats that do not
447 support setting the gamma level, this value is ignored.
448
449 The value range of \a gamma depends on the image format. For
450 example, the "png" format supports a gamma range from 0.0 to 1.0.
451
452 \sa quality()
453*/
454void QImageWriter::setGamma(float gamma)
455{
456 d->gamma = gamma;
457}
458
459/*!
460 Returns the gamma level of the image.
461
462 \sa setGamma()
463*/
464float QImageWriter::gamma() const
465{
466 return d->gamma;
467}
468
469/*!
470 \obsolete
471
472 Use setText() instead.
473
474 This is an image format specific function that sets the
475 description of the image to \a description. For image formats that
476 do not support setting the description, this value is ignored.
477
478 The contents of \a description depends on the image format.
479
480 \sa description()
481*/
482void QImageWriter::setDescription(const QString &description)
483{
484 d->description = description;
485}
486
487/*!
488 \obsolete
489
490 Use QImageReader::text() instead.
491
492 Returns the description of the image.
493
494 \sa setDescription()
495*/
496QString QImageWriter::description() const
497{
498 return d->description;
499}
500
501/*!
502 \since 4.1
503
504 Sets the image text associated with the key \a key to
505 \a text. This is useful for storing copyright information
506 or other information about the image. Example:
507
508 \snippet doc/src/snippets/code/src_gui_image_qimagewriter.cpp 1
509
510 If you want to store a single block of data
511 (e.g., a comment), you can pass an empty key, or use
512 a generic key like "Description".
513
514 The key and text will be embedded into the
515 image data after calling write().
516
517 Support for this option is implemented through
518 QImageIOHandler::Description.
519
520 \sa QImage::setText(), QImageReader::text()
521*/
522void QImageWriter::setText(const QString &key, const QString &text)
523{
524 if (!d->description.isEmpty())
525 d->description += QLatin1String("\n\n");
526 d->description += key.simplified() + QLatin1String(": ") + text.simplified();
527}
528
529/*!
530 Returns true if QImageWriter can write the image; i.e., the image
531 format is supported and the assigned device is open for reading.
532
533 \sa write(), setDevice(), setFormat()
534*/
535bool QImageWriter::canWrite() const
536{
537 if (d->device && !d->handler && (d->handler = createWriteHandlerHelper(d->device, d->format)) == 0) {
538 d->imageWriterError = QImageWriter::UnsupportedFormatError;
539 d->errorString = QT_TRANSLATE_NOOP(QImageWriter,
540 QLatin1String("Unsupported image format"));
541 return false;
542 }
543 if (d->device && !d->device->isOpen())
544 d->device->open(QIODevice::WriteOnly);
545 if (!d->device || !d->device->isWritable()) {
546 d->imageWriterError = QImageWriter::DeviceError;
547 d->errorString = QT_TRANSLATE_NOOP(QImageWriter,
548 QLatin1String("Device not writable"));
549 return false;
550 }
551 return true;
552}
553
554/*!
555 Writes the image \a image to the assigned device or file
556 name. Returns true on success; otherwise returns false. If the
557 operation fails, you can call error() to find the type of error
558 that occurred, or errorString() to get a human readable
559 description of the error.
560
561 \sa canWrite(), error(), errorString()
562*/
563bool QImageWriter::write(const QImage &image)
564{
565 if (!canWrite())
566 return false;
567
568 if (d->handler->supportsOption(QImageIOHandler::Quality))
569 d->handler->setOption(QImageIOHandler::Quality, d->quality);
570 if (d->handler->supportsOption(QImageIOHandler::CompressionRatio))
571 d->handler->setOption(QImageIOHandler::CompressionRatio, d->compression);
572 if (d->handler->supportsOption(QImageIOHandler::Gamma))
573 d->handler->setOption(QImageIOHandler::Gamma, d->gamma);
574 if (!d->description.isEmpty() && d->handler->supportsOption(QImageIOHandler::Description))
575 d->handler->setOption(QImageIOHandler::Description, d->description);
576
577 if (!d->handler->write(image))
578 return false;
579 if (QFile *file = qobject_cast<QFile *>(d->device))
580 file->flush();
581 return true;
582}
583
584/*!
585 Returns the type of error that last occurred.
586
587 \sa ImageWriterError, errorString()
588*/
589QImageWriter::ImageWriterError QImageWriter::error() const
590{
591 return d->imageWriterError;
592}
593
594/*!
595 Returns a human readable description of the last error that occurred.
596
597 \sa error()
598*/
599QString QImageWriter::errorString() const
600{
601 return d->errorString;
602}
603
604/*!
605 \since 4.2
606
607 Returns true if the writer supports \a option; otherwise returns
608 false.
609
610 Different image formats support different options. Call this function to
611 determine whether a certain option is supported by the current format. For
612 example, the PNG format allows you to embed text into the image's metadata
613 (see text()).
614
615 \snippet doc/src/snippets/code/src_gui_image_qimagewriter.cpp 2
616
617 Options can be tested after the writer has been associated with a format.
618
619 \sa QImageReader::supportsOption(), setFormat()
620*/
621bool QImageWriter::supportsOption(QImageIOHandler::ImageOption option) const
622{
623 if (!d->handler && (d->handler = createWriteHandlerHelper(d->device, d->format)) == 0) {
624 d->imageWriterError = QImageWriter::UnsupportedFormatError;
625 d->errorString = QT_TRANSLATE_NOOP(QImageWriter,
626 QLatin1String("Unsupported image format"));
627 return false;
628 }
629
630 return d->handler->supportsOption(option);
631}
632
633/*!
634 Returns the list of image formats supported by QImageWriter.
635
636 By default, Qt can write the following formats:
637
638 \table
639 \header \o Format \o Description
640 \row \o BMP \o Windows Bitmap
641 \row \o JPG \o Joint Photographic Experts Group
642 \row \o JPEG \o Joint Photographic Experts Group
643 \row \o PNG \o Portable Network Graphics
644 \row \o PPM \o Portable Pixmap
645 \row \o TIFF \o Tagged Image File Format
646 \row \o XBM \o X11 Bitmap
647 \row \o XPM \o X11 Pixmap
648 \endtable
649
650 Reading and writing SVG files is supported through Qt's
651 \l{QtSvg Module}{SVG Module}.
652
653 \sa setFormat(), QImageReader::supportedImageFormats(), QImageIOPlugin
654*/
655QList<QByteArray> QImageWriter::supportedImageFormats()
656{
657 QSet<QByteArray> formats;
658 formats << "bmp";
659#ifndef QT_NO_IMAGEFORMAT_PPM
660 formats << "ppm";
661#endif
662#ifndef QT_NO_IMAGEFORMAT_XBM
663 formats << "xbm";
664#endif
665#ifndef QT_NO_IMAGEFORMAT_XPM
666 formats << "xpm";
667#endif
668#ifndef QT_NO_IMAGEFORMAT_PNG
669 formats << "png";
670#endif
671
672#if !defined (QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS)
673 QFactoryLoader *l = loader();
674 QStringList keys = l->keys();
675 for (int i = 0; i < keys.count(); ++i) {
676 QImageIOPlugin *plugin = qobject_cast<QImageIOPlugin *>(l->instance(keys.at(i)));
677 if (plugin && (plugin->capabilities(0, keys.at(i).toLatin1()) & QImageIOPlugin::CanWrite) != 0)
678 formats << keys.at(i).toLatin1();
679 }
680#endif // QT_NO_LIBRARY
681
682 QList<QByteArray> sortedFormats;
683 for (QSet<QByteArray>::ConstIterator it = formats.constBegin(); it != formats.constEnd(); ++it)
684 sortedFormats << *it;
685
686 qSort(sortedFormats);
687 return sortedFormats;
688}
689
690QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.