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#include "qpicture.h"
41#include <private/qpicture_p.h>
42
43#ifndef QT_NO_PICTURE
44
45#include <private/qfactoryloader_p.h>
46#include <private/qpaintengine_pic_p.h>
47#include <private/qfont_p.h>
48#include <qguiapplication.h>
49
50#include "qdatastream.h"
51#include "qfile.h"
52#include "qimage.h"
53#include "qmutex.h"
54#include "qpainter.h"
55#include "qpainterpath.h"
56#include "qpixmap.h"
57#include "qregexp.h"
58#include "qregion.h"
59#include "qdebug.h"
60#include <QtCore/private/qlocking_p.h>
61
62#include <algorithm>
63
64QT_BEGIN_NAMESPACE
65
66void qt_format_text(const QFont &fnt, const QRectF &_r,
67 int tf, const QTextOption *opt, const QString& str, QRectF *brect,
68 int tabstops, int *, int tabarraylen,
69 QPainter *painter);
70
71/*!
72 \class QPicture
73 \brief The QPicture class is a paint device that records and
74 replays QPainter commands.
75
76 \inmodule QtGui
77 \ingroup shared
78
79
80 A picture serializes painter commands to an IO device in a
81 platform-independent format. They are sometimes referred to as meta-files.
82
83 Qt pictures use a proprietary binary format. Unlike native picture
84 (meta-file) formats on many window systems, Qt pictures have no
85 limitations regarding their contents. Everything that can be
86 painted on a widget or pixmap (e.g., fonts, pixmaps, regions,
87 transformed graphics, etc.) can also be stored in a picture.
88
89 QPicture is resolution independent, i.e. a QPicture can be
90 displayed on different devices (for example svg, pdf, ps, printer
91 and screen) looking the same. This is, for instance, needed for
92 WYSIWYG print preview. QPicture runs in the default system dpi,
93 and scales the painter to match differences in resolution
94 depending on the window system.
95
96 Example of how to record a picture:
97 \snippet picture/picture.cpp 0
98
99 Note that the list of painter commands is reset on each call to
100 the QPainter::begin() function.
101
102 Example of how to replay a picture:
103 \snippet picture/picture.cpp 1
104
105 Pictures can also be drawn using play(). Some basic data about a
106 picture is available, for example, size(), isNull() and
107 boundingRect().
108
109 \sa QMovie
110*/
111
112/*!
113 \fn QPicture &QPicture::operator=(QPicture &&other)
114
115 Move-assigns \a other to this QPicture instance.
116
117 \since 5.2
118*/
119
120const char *qt_mfhdr_tag = "QPIC"; // header tag
121static const quint16 mfhdr_maj = QDataStream::Qt_DefaultCompiledVersion; // major version #
122static const quint16 mfhdr_min = 0; // minor version #
123
124/*!
125 Constructs an empty picture.
126
127 The \a formatVersion parameter may be used to \e create a QPicture
128 that can be read by applications that are compiled with earlier
129 versions of Qt.
130
131 Note that the default formatVersion is -1 which signifies the
132 current release, i.e. for Qt 4.0 a formatVersion of 7 is the same
133 as the default formatVersion of -1.
134
135 Reading pictures generated by earlier versions of Qt is not
136 supported in Qt 4.0.
137*/
138
139QPicture::QPicture(int formatVersion)
140 : QPaintDevice(),
141 d_ptr(new QPicturePrivate)
142{
143 Q_D(QPicture);
144
145 if (formatVersion == 0)
146 qWarning(msg: "QPicture: invalid format version 0");
147
148 // still accept the 0 default from before Qt 3.0.
149 if (formatVersion > 0 && formatVersion != (int)mfhdr_maj) {
150 d->formatMajor = formatVersion;
151 d->formatMinor = 0;
152 d->formatOk = false;
153 } else {
154 d->resetFormat();
155 }
156}
157
158/*!
159 Constructs a copy of \a pic.
160
161 This constructor is fast thanks to \l{implicit sharing}.
162*/
163
164QPicture::QPicture(const QPicture &pic)
165 : QPaintDevice(), d_ptr(pic.d_ptr)
166{
167}
168
169/*! \internal */
170QPicture::QPicture(QPicturePrivate &dptr)
171 : QPaintDevice(),
172 d_ptr(&dptr)
173{
174}
175
176/*!
177 Destroys the picture.
178*/
179QPicture::~QPicture()
180{
181}
182
183/*!
184 \internal
185*/
186int QPicture::devType() const
187{
188 return QInternal::Picture;
189}
190
191/*!
192 \fn bool QPicture::isNull() const
193
194 Returns \c true if the picture contains no data; otherwise returns
195 false.
196*/
197
198/*!
199 \fn uint QPicture::size() const
200
201 Returns the size of the picture data.
202
203 \sa data()
204*/
205
206/*!
207 \fn const char* QPicture::data() const
208
209 Returns a pointer to the picture data. The pointer is only valid
210 until the next non-const function is called on this picture. The
211 returned pointer is 0 if the picture contains no data.
212
213 \sa size(), isNull()
214*/
215
216
217bool QPicture::isNull() const
218{
219 return d_func()->pictb.buffer().isNull();
220}
221
222uint QPicture::size() const
223{
224 return d_func()->pictb.buffer().size();
225}
226
227const char* QPicture::data() const
228{
229 return d_func()->pictb.buffer();
230}
231
232void QPicture::detach()
233{
234 d_ptr.detach();
235}
236
237bool QPicture::isDetached() const
238{
239 return d_func()->ref.loadRelaxed() == 1;
240}
241
242/*!
243 Sets the picture data directly from \a data and \a size. This
244 function copies the input data.
245
246 \sa data(), size()
247*/
248
249void QPicture::setData(const char* data, uint size)
250{
251 detach();
252 d_func()->pictb.setData(adata: data, alen: size);
253 d_func()->resetFormat(); // we'll have to check
254}
255
256
257/*!
258 Loads a picture from the file specified by \a fileName and returns
259 true if successful; otherwise invalidates the picture and returns \c false.
260
261 Please note that the \a format parameter has been deprecated and
262 will have no effect.
263
264 \sa save()
265*/
266
267bool QPicture::load(const QString &fileName, const char *format)
268{
269 QFile f(fileName);
270 if (!f.open(flags: QIODevice::ReadOnly)) {
271 operator=(other: QPicture());
272 return false;
273 }
274 return load(dev: &f, format);
275}
276
277/*!
278 \overload
279
280 \a dev is the device to use for loading.
281*/
282
283bool QPicture::load(QIODevice *dev, const char *format)
284{
285 if(format) {
286#ifndef QT_NO_PICTUREIO
287 QPictureIO io(dev, format);
288 if (io.read()) {
289 operator=(p: io.picture());
290 return true;
291 }
292#endif
293 qWarning(msg: "QPicture::load: No such picture format: %s", format);
294 operator=(other: QPicture());
295 return false;
296 }
297
298 detach();
299 QByteArray a = dev->readAll();
300
301 d_func()->pictb.setData(a); // set byte array in buffer
302 return d_func()->checkFormat();
303}
304
305/*!
306 Saves a picture to the file specified by \a fileName and returns
307 true if successful; otherwise returns \c false.
308
309 Please note that the \a format parameter has been deprecated and
310 will have no effect.
311
312 \sa load()
313*/
314
315bool QPicture::save(const QString &fileName, const char *format)
316{
317 if (paintingActive()) {
318 qWarning(msg: "QPicture::save: still being painted on. "
319 "Call QPainter::end() first");
320 return false;
321 }
322
323
324 if(format) {
325#ifndef QT_NO_PICTUREIO
326 QPictureIO io(fileName, format);
327 bool result = io.write();
328 if (result) {
329 operator=(p: io.picture());
330 } else if (format)
331#else
332 bool result = false;
333#endif
334 {
335 qWarning(msg: "QPicture::save: No such picture format: %s", format);
336 }
337 return result;
338 }
339
340 QFile f(fileName);
341 if (!f.open(flags: QIODevice::WriteOnly))
342 return false;
343 return save(dev: &f, format);
344}
345
346/*!
347 \overload
348
349 \a dev is the device to use for saving.
350*/
351
352bool QPicture::save(QIODevice *dev, const char *format)
353{
354 if (paintingActive()) {
355 qWarning(msg: "QPicture::save: still being painted on. "
356 "Call QPainter::end() first");
357 return false;
358 }
359
360 if(format) {
361#ifndef QT_NO_PICTUREIO
362 QPictureIO io(dev, format);
363 bool result = io.write();
364 if (result) {
365 operator=(p: io.picture());
366 } else if (format)
367#else
368 bool result = false;
369#endif
370 {
371 qWarning(msg: "QPicture::save: No such picture format: %s", format);
372 }
373 return result;
374 }
375
376 dev->write(data: d_func()->pictb.buffer(), len: d_func()->pictb.buffer().size());
377 return true;
378}
379
380/*!
381 Returns the picture's bounding rectangle or an invalid rectangle
382 if the picture contains no data.
383*/
384
385QRect QPicture::boundingRect() const
386{
387 Q_D(const QPicture);
388 // Use override rect where possible.
389 if (!d->override_rect.isEmpty())
390 return d->override_rect;
391
392 if (!d->formatOk)
393 d_ptr->checkFormat();
394
395 return d->brect;
396}
397
398/*!
399 Sets the picture's bounding rectangle to \a r. The automatically
400 calculated value is overridden.
401*/
402
403void QPicture::setBoundingRect(const QRect &r)
404{
405 d_func()->override_rect = r;
406}
407
408/*!
409 Replays the picture using \a painter, and returns \c true if
410 successful; otherwise returns \c false.
411
412 This function does exactly the same as QPainter::drawPicture()
413 with (x, y) = (0, 0).
414*/
415
416bool QPicture::play(QPainter *painter)
417{
418 Q_D(QPicture);
419
420 if (d->pictb.size() == 0) // nothing recorded
421 return true;
422
423 if (!d->formatOk && !d->checkFormat())
424 return false;
425
426 d->pictb.open(openMode: QIODevice::ReadOnly); // open buffer device
427 QDataStream s;
428 s.setDevice(&d->pictb); // attach data stream to buffer
429 s.device()->seek(pos: 10); // go directly to the data
430 s.setVersion(d->formatMajor == 4 ? 3 : d->formatMajor);
431
432 quint8 c, clen;
433 quint32 nrecords;
434 s >> c >> clen;
435 Q_ASSERT(c == QPicturePrivate::PdcBegin);
436 // bounding rect was introduced in ver 4. Read in checkFormat().
437 if (d->formatMajor >= 4) {
438 qint32 dummy;
439 s >> dummy >> dummy >> dummy >> dummy;
440 }
441 s >> nrecords;
442 if (!exec(p: painter, ds&: s, i: nrecords)) {
443 qWarning(msg: "QPicture::play: Format error");
444 d->pictb.close();
445 return false;
446 }
447 d->pictb.close();
448 return true; // no end-command
449}
450
451
452//
453// QFakeDevice is used to create fonts with a custom DPI
454//
455class QFakeDevice : public QPaintDevice
456{
457public:
458 QFakeDevice() { dpi_x = qt_defaultDpiX(); dpi_y = qt_defaultDpiY(); }
459 void setDpiX(int dpi) { dpi_x = dpi; }
460 void setDpiY(int dpi) { dpi_y = dpi; }
461 QPaintEngine *paintEngine() const override { return nullptr; }
462 int metric(PaintDeviceMetric m) const override
463 {
464 switch(m) {
465 case PdmPhysicalDpiX:
466 case PdmDpiX:
467 return dpi_x;
468 case PdmPhysicalDpiY:
469 case PdmDpiY:
470 return dpi_y;
471 default:
472 return QPaintDevice::metric(metric: m);
473 }
474 }
475
476private:
477 int dpi_x;
478 int dpi_y;
479};
480
481/*!
482 \internal
483 Iterates over the internal picture data and draws the picture using
484 \a painter.
485*/
486
487bool QPicture::exec(QPainter *painter, QDataStream &s, int nrecords)
488{
489 Q_D(QPicture);
490#if defined(QT_DEBUG)
491 int strm_pos;
492#endif
493 quint8 c; // command id
494 quint8 tiny_len; // 8-bit length descriptor
495 qint32 len; // 32-bit length descriptor
496 qint16 i_16, i1_16, i2_16; // parameters...
497 qint8 i_8;
498 quint32 ul;
499 double dbl;
500 bool bl;
501 QByteArray str1;
502 QString str;
503 QPointF p, p1, p2;
504 QPoint ip, ip1, ip2;
505 QRect ir;
506 QRectF r;
507 QPolygonF a;
508 QPolygon ia;
509 QColor color;
510 QFont font;
511 QPen pen;
512 QBrush brush;
513 QRegion rgn;
514 QMatrix wmatrix;
515 QTransform matrix;
516
517 QTransform worldMatrix = painter->transform();
518 worldMatrix.scale(sx: qreal(painter->device()->logicalDpiX()) / qreal(qt_defaultDpiX()),
519 sy: qreal(painter->device()->logicalDpiY()) / qreal(qt_defaultDpiY()));
520 painter->setTransform(transform: worldMatrix);
521
522 while (nrecords-- && !s.atEnd()) {
523 s >> c; // read cmd
524 s >> tiny_len; // read param length
525 if (tiny_len == 255) // longer than 254 bytes
526 s >> len;
527 else
528 len = tiny_len;
529#if defined(QT_DEBUG)
530 strm_pos = s.device()->pos();
531#endif
532 switch (c) { // exec cmd
533 case QPicturePrivate::PdcNOP:
534 break;
535 case QPicturePrivate::PdcDrawPoint:
536 if (d->formatMajor <= 5) {
537 s >> ip;
538 painter->drawPoint(p: ip);
539 } else {
540 s >> p;
541 painter->drawPoint(p);
542 }
543 break;
544 case QPicturePrivate::PdcDrawPoints:
545// ## implement me in the picture paint engine
546// s >> a >> i1_32 >> i2_32;
547// painter->drawPoints(a.mid(i1_32, i2_32));
548 break;
549 case QPicturePrivate::PdcDrawPath: {
550 QPainterPath path;
551 s >> path;
552 painter->drawPath(path);
553 break;
554 }
555 case QPicturePrivate::PdcDrawLine:
556 if (d->formatMajor <= 5) {
557 s >> ip1 >> ip2;
558 painter->drawLine(p1: ip1, p2: ip2);
559 } else {
560 s >> p1 >> p2;
561 painter->drawLine(p1, p2);
562 }
563 break;
564 case QPicturePrivate::PdcDrawRect:
565 if (d->formatMajor <= 5) {
566 s >> ir;
567 painter->drawRect(r: ir);
568 } else {
569 s >> r;
570 painter->drawRect(rect: r);
571 }
572 break;
573 case QPicturePrivate::PdcDrawRoundRect:
574 if (d->formatMajor <= 5) {
575 s >> ir >> i1_16 >> i2_16;
576 painter->drawRoundedRect(rect: ir, xRadius: i1_16, yRadius: i2_16, mode: Qt::RelativeSize);
577 } else {
578 s >> r >> i1_16 >> i2_16;
579 painter->drawRoundedRect(rect: r, xRadius: i1_16, yRadius: i2_16, mode: Qt::RelativeSize);
580 }
581 break;
582 case QPicturePrivate::PdcDrawEllipse:
583 if (d->formatMajor <= 5) {
584 s >> ir;
585 painter->drawEllipse(r: ir);
586 } else {
587 s >> r;
588 painter->drawEllipse(r);
589 }
590 break;
591 case QPicturePrivate::PdcDrawArc:
592 if (d->formatMajor <= 5) {
593 s >> ir;
594 r = ir;
595 } else {
596 s >> r;
597 }
598 s >> i1_16 >> i2_16;
599 painter->drawArc(rect: r, a: i1_16, alen: i2_16);
600 break;
601 case QPicturePrivate::PdcDrawPie:
602 if (d->formatMajor <= 5) {
603 s >> ir;
604 r = ir;
605 } else {
606 s >> r;
607 }
608 s >> i1_16 >> i2_16;
609 painter->drawPie(rect: r, a: i1_16, alen: i2_16);
610 break;
611 case QPicturePrivate::PdcDrawChord:
612 if (d->formatMajor <= 5) {
613 s >> ir;
614 r = ir;
615 } else {
616 s >> r;
617 }
618 s >> i1_16 >> i2_16;
619 painter->drawChord(rect: r, a: i1_16, alen: i2_16);
620 break;
621 case QPicturePrivate::PdcDrawLineSegments:
622 s >> ia;
623 painter->drawLines(pointPairs: ia);
624 ia.clear();
625 break;
626 case QPicturePrivate::PdcDrawPolyline:
627 if (d->formatMajor <= 5) {
628 s >> ia;
629 painter->drawPolyline(polyline: ia);
630 ia.clear();
631 } else {
632 s >> a;
633 painter->drawPolyline(polyline: a);
634 a.clear();
635 }
636 break;
637 case QPicturePrivate::PdcDrawPolygon:
638 if (d->formatMajor <= 5) {
639 s >> ia >> i_8;
640 painter->drawPolygon(polygon: ia, fillRule: i_8 ? Qt::WindingFill : Qt::OddEvenFill);
641 ia.clear();
642 } else {
643 s >> a >> i_8;
644 painter->drawPolygon(polygon: a, fillRule: i_8 ? Qt::WindingFill : Qt::OddEvenFill);
645 a.clear();
646 }
647 break;
648 case QPicturePrivate::PdcDrawCubicBezier: {
649 s >> ia;
650 QPainterPath path;
651 Q_ASSERT(ia.size() == 4);
652 path.moveTo(p: ia.value(i: 0));
653 path.cubicTo(ctrlPt1: ia.value(i: 1), ctrlPt2: ia.value(i: 2), endPt: ia.value(i: 3));
654 painter->strokePath(path, pen: painter->pen());
655 ia.clear();
656 }
657 break;
658 case QPicturePrivate::PdcDrawText:
659 s >> ip >> str1;
660 painter->drawText(p: ip, s: QString::fromLatin1(str: str1));
661 break;
662 case QPicturePrivate::PdcDrawTextFormatted:
663 s >> ir >> i_16 >> str1;
664 painter->drawText(r: ir, flags: i_16, text: QString::fromLatin1(str: str1));
665 break;
666 case QPicturePrivate::PdcDrawText2:
667 if (d->formatMajor <= 5) {
668 s >> ip >> str;
669 painter->drawText(p: ip, s: str);
670 } else {
671 s >> p >> str;
672 painter->drawText(p, s: str);
673 }
674 break;
675 case QPicturePrivate::PdcDrawText2Formatted:
676 s >> ir;
677 s >> i_16;
678 s >> str;
679 painter->drawText(r: ir, flags: i_16, text: str);
680 break;
681 case QPicturePrivate::PdcDrawTextItem: {
682 s >> p >> str >> font >> ul;
683
684 // the text layout direction is not used here because it's already
685 // aligned when QPicturePaintEngine::drawTextItem() serializes the
686 // drawText() call, therefore ul is unsed in this context
687
688 if (d->formatMajor >= 9) {
689 s >> dbl;
690 QFont fnt(font);
691 if (dbl != 1.0) {
692 QFakeDevice fake;
693 fake.setDpiX(qRound(d: dbl*qt_defaultDpiX()));
694 fake.setDpiY(qRound(d: dbl*qt_defaultDpiY()));
695 fnt = QFont(font, &fake);
696 }
697
698 qreal justificationWidth;
699 s >> justificationWidth;
700
701 int flags = Qt::TextSingleLine | Qt::TextDontClip | Qt::TextForceLeftToRight;
702
703 QSizeF size(1, 1);
704 if (justificationWidth > 0) {
705 size.setWidth(justificationWidth);
706 flags |= Qt::TextJustificationForced;
707 flags |= Qt::AlignJustify;
708 }
709
710 QFontMetrics fm(fnt);
711 QPointF pt(p.x(), p.y() - fm.ascent());
712 qt_format_text(fnt, r: QRectF(pt, size), tf: flags, /*opt*/nullptr,
713 str, /*brect=*/nullptr, /*tabstops=*/0, /*...*/nullptr, /*tabarraylen=*/0, painter);
714 } else {
715 qt_format_text(fnt: font, r: QRectF(p, QSizeF(1, 1)), tf: Qt::TextSingleLine | Qt::TextDontClip, /*opt*/nullptr,
716 str, /*brect=*/nullptr, /*tabstops=*/0, /*...*/nullptr, /*tabarraylen=*/0, painter);
717 }
718
719 break;
720 }
721 case QPicturePrivate::PdcDrawPixmap: {
722 QPixmap pixmap;
723 if (d->formatMajor < 4) {
724 s >> ip >> pixmap;
725 painter->drawPixmap(p: ip, pm: pixmap);
726 } else if (d->formatMajor <= 5) {
727 s >> ir >> pixmap;
728 painter->drawPixmap(r: ir, pm: pixmap);
729 } else {
730 QRectF sr;
731 if (d->in_memory_only) {
732 int index;
733 s >> r >> index >> sr;
734 Q_ASSERT(index < d->pixmap_list.size());
735 pixmap = d->pixmap_list.value(i: index);
736 } else {
737 s >> r >> pixmap >> sr;
738 }
739 painter->drawPixmap(targetRect: r, pixmap, sourceRect: sr);
740 }
741 }
742 break;
743 case QPicturePrivate::PdcDrawTiledPixmap: {
744 QPixmap pixmap;
745 if (d->in_memory_only) {
746 int index;
747 s >> r >> index >> p;
748 Q_ASSERT(index < d->pixmap_list.size());
749 pixmap = d->pixmap_list.value(i: index);
750 } else {
751 s >> r >> pixmap >> p;
752 }
753 painter->drawTiledPixmap(rect: r, pm: pixmap, offset: p);
754 }
755 break;
756 case QPicturePrivate::PdcDrawImage: {
757 QImage image;
758 if (d->formatMajor < 4) {
759 s >> p >> image;
760 painter->drawImage(p, image);
761 } else if (d->formatMajor <= 5){
762 s >> ir >> image;
763 painter->drawImage(targetRect: ir, image, sourceRect: QRect(0, 0, ir.width(), ir.height()));
764 } else {
765 QRectF sr;
766 if (d->in_memory_only) {
767 int index;
768 s >> r >> index >> sr >> ul;
769 Q_ASSERT(index < d->image_list.size());
770 image = d->image_list.value(i: index);
771 } else {
772 s >> r >> image >> sr >> ul;
773 }
774 painter->drawImage(targetRect: r, image, sourceRect: sr, flags: Qt::ImageConversionFlags(ul));
775 }
776 }
777 break;
778 case QPicturePrivate::PdcBegin:
779 s >> ul; // number of records
780 if (!exec(painter, s, nrecords: ul))
781 return false;
782 break;
783 case QPicturePrivate::PdcEnd:
784 if (nrecords == 0)
785 return true;
786 break;
787 case QPicturePrivate::PdcSave:
788 painter->save();
789 break;
790 case QPicturePrivate::PdcRestore:
791 painter->restore();
792 break;
793 case QPicturePrivate::PdcSetBkColor:
794 s >> color;
795 painter->setBackground(color);
796 break;
797 case QPicturePrivate::PdcSetBkMode:
798 s >> i_8;
799 painter->setBackgroundMode((Qt::BGMode)i_8);
800 break;
801 case QPicturePrivate::PdcSetROP: // NOP
802 s >> i_8;
803 break;
804 case QPicturePrivate::PdcSetBrushOrigin:
805 if (d->formatMajor <= 5) {
806 s >> ip;
807 painter->setBrushOrigin(ip);
808 } else {
809 s >> p;
810 painter->setBrushOrigin(p);
811 }
812 break;
813 case QPicturePrivate::PdcSetFont:
814 s >> font;
815 painter->setFont(font);
816 break;
817 case QPicturePrivate::PdcSetPen:
818 if (d->in_memory_only) {
819 int index;
820 s >> index;
821 Q_ASSERT(index < d->pen_list.size());
822 pen = d->pen_list.value(i: index);
823 } else {
824 s >> pen;
825 }
826 painter->setPen(pen);
827 break;
828 case QPicturePrivate::PdcSetBrush:
829 if (d->in_memory_only) {
830 int index;
831 s >> index;
832 Q_ASSERT(index < d->brush_list.size());
833 brush = d->brush_list.value(i: index);
834 } else {
835 s >> brush;
836 }
837 painter->setBrush(brush);
838 break;
839 case QPicturePrivate::PdcSetVXform:
840 s >> i_8;
841 painter->setViewTransformEnabled(i_8);
842 break;
843 case QPicturePrivate::PdcSetWindow:
844 if (d->formatMajor <= 5) {
845 s >> ir;
846 painter->setWindow(ir);
847 } else {
848 s >> r;
849 painter->setWindow(r.toRect());
850 }
851 break;
852 case QPicturePrivate::PdcSetViewport:
853 if (d->formatMajor <= 5) {
854 s >> ir;
855 painter->setViewport(ir);
856 } else {
857 s >> r;
858 painter->setViewport(r.toRect());
859 }
860 break;
861 case QPicturePrivate::PdcSetWXform:
862 s >> i_8;
863 painter->setWorldMatrixEnabled(i_8);
864 break;
865 case QPicturePrivate::PdcSetWMatrix:
866 if (d->formatMajor >= 8) {
867 s >> matrix >> i_8;
868 } else {
869 s >> wmatrix >> i_8;
870 matrix = QTransform(wmatrix);
871 }
872 // i_8 is always false due to updateXForm() in qpaintengine_pic.cpp
873 painter->setTransform(transform: matrix * worldMatrix, combine: i_8);
874 break;
875 case QPicturePrivate::PdcSetClip:
876 s >> i_8;
877 painter->setClipping(i_8);
878 break;
879 case QPicturePrivate::PdcSetClipRegion:
880 s >> rgn >> i_8;
881 if (d->formatMajor >= 9) {
882 painter->setClipRegion(rgn, op: Qt::ClipOperation(i_8));
883 } else {
884 painter->setClipRegion(rgn);
885 }
886 break;
887 case QPicturePrivate::PdcSetClipPath:
888 {
889 QPainterPath path;
890 s >> path >> i_8;
891 painter->setClipPath(path, op: Qt::ClipOperation(i_8));
892 break;
893 }
894 case QPicturePrivate::PdcSetRenderHint:
895 s >> ul;
896 painter->setRenderHint(hint: QPainter::Antialiasing,
897 on: bool(ul & QPainter::Antialiasing));
898 painter->setRenderHint(hint: QPainter::SmoothPixmapTransform,
899 on: bool(ul & QPainter::SmoothPixmapTransform));
900 break;
901 case QPicturePrivate::PdcSetCompositionMode:
902 s >> ul;
903 painter->setCompositionMode((QPainter::CompositionMode)ul);
904 break;
905 case QPicturePrivate::PdcSetClipEnabled:
906 s >> bl;
907 painter->setClipping(bl);
908 break;
909 case QPicturePrivate::PdcSetOpacity:
910 s >> dbl;
911 painter->setOpacity(qreal(dbl));
912 break;
913 default:
914 qWarning(msg: "QPicture::play: Invalid command %d", c);
915 if (len > 0) // skip unknown command
916 s.device()->seek(pos: s.device()->pos()+len);
917 }
918#if defined(QT_DEBUG)
919 //qDebug("device->at(): %i, strm_pos: %i len: %i", (int)s.device()->pos(), strm_pos, len);
920 Q_ASSERT(qint32(s.device()->pos() - strm_pos) == len);
921#endif
922 }
923 return false;
924}
925
926/*!
927 \internal
928
929 Internal implementation of the virtual QPaintDevice::metric()
930 function.
931
932 A picture has the following hard-coded values: numcolors=16777216
933 and depth=24.
934
935 \a m is the metric to get.
936*/
937
938int QPicture::metric(PaintDeviceMetric m) const
939{
940 int val;
941 QRect brect = boundingRect();
942 switch (m) {
943 case PdmWidth:
944 val = brect.width();
945 break;
946 case PdmHeight:
947 val = brect.height();
948 break;
949 case PdmWidthMM:
950 val = int(25.4/qt_defaultDpiX()*brect.width());
951 break;
952 case PdmHeightMM:
953 val = int(25.4/qt_defaultDpiY()*brect.height());
954 break;
955 case PdmDpiX:
956 case PdmPhysicalDpiX:
957 val = qt_defaultDpiX();
958 break;
959 case PdmDpiY:
960 case PdmPhysicalDpiY:
961 val = qt_defaultDpiY();
962 break;
963 case PdmNumColors:
964 val = 16777216;
965 break;
966 case PdmDepth:
967 val = 24;
968 break;
969 case PdmDevicePixelRatio:
970 val = 1;
971 break;
972 case PdmDevicePixelRatioScaled:
973 val = 1 * QPaintDevice::devicePixelRatioFScale();
974 break;
975 default:
976 val = 0;
977 qWarning(msg: "QPicture::metric: Invalid metric command");
978 }
979 return val;
980}
981
982/*!
983 \fn void QPicture::detach()
984 \internal
985 Detaches from shared picture data and makes sure that this picture
986 is the only one referring to the data.
987
988 If multiple pictures share common data, this picture makes a copy
989 of the data and detaches itself from the sharing mechanism.
990 Nothing is done if there is just a single reference.
991*/
992
993/*! \fn bool QPicture::isDetached() const
994\internal
995*/
996
997/*!
998 Assigns picture \a p to this picture and returns a reference to
999 this picture.
1000*/
1001QPicture& QPicture::operator=(const QPicture &p)
1002{
1003 d_ptr = p.d_ptr;
1004 return *this;
1005}
1006
1007/*!
1008 \fn void QPicture::swap(QPicture &other)
1009 \since 4.8
1010
1011 Swaps picture \a other with this picture. This operation is very
1012 fast and never fails.
1013*/
1014
1015/*!
1016 \internal
1017
1018 Constructs a QPicturePrivate
1019*/
1020QPicturePrivate::QPicturePrivate()
1021 : in_memory_only(false)
1022{
1023}
1024
1025/*!
1026 \internal
1027
1028 Copy-Constructs a QPicturePrivate. Needed when detaching.
1029*/
1030QPicturePrivate::QPicturePrivate(const QPicturePrivate &other)
1031 : trecs(other.trecs),
1032 formatOk(other.formatOk),
1033 formatMinor(other.formatMinor),
1034 brect(other.brect),
1035 override_rect(other.override_rect),
1036 in_memory_only(false)
1037{
1038 pictb.setData(adata: other.pictb.data(), alen: other.pictb.size());
1039 if (other.pictb.isOpen()) {
1040 pictb.open(openMode: other.pictb.openMode());
1041 pictb.seek(off: other.pictb.pos());
1042 }
1043}
1044
1045/*!
1046 \internal
1047
1048 Sets formatOk to false and resets the format version numbers to default
1049*/
1050
1051void QPicturePrivate::resetFormat()
1052{
1053 formatOk = false;
1054 formatMajor = mfhdr_maj;
1055 formatMinor = mfhdr_min;
1056}
1057
1058
1059/*!
1060 \internal
1061
1062 Checks data integrity and format version number. Set formatOk to
1063 true on success, to false otherwise. Returns the resulting formatOk
1064 value.
1065*/
1066bool QPicturePrivate::checkFormat()
1067{
1068 resetFormat();
1069
1070 // can't check anything in an empty buffer
1071 if (pictb.size() == 0 || pictb.isOpen())
1072 return false;
1073
1074 pictb.open(openMode: QIODevice::ReadOnly); // open buffer device
1075 QDataStream s;
1076 s.setDevice(&pictb); // attach data stream to buffer
1077
1078 char mf_id[4]; // picture header tag
1079 s.readRawData(mf_id, len: 4); // read actual tag
1080 int bufSize = pictb.buffer().size();
1081 if (memcmp(s1: mf_id, s2: qt_mfhdr_tag, n: 4) != 0 || bufSize < 12) { // wrong header id or size
1082 qWarning(msg: "QPicturePaintEngine::checkFormat: Incorrect header");
1083 pictb.close();
1084 return false;
1085 }
1086
1087 int cs_start = sizeof(quint32); // pos of checksum word
1088 int data_start = cs_start + sizeof(quint16);
1089 quint16 cs,ccs;
1090 QByteArray buf = pictb.buffer(); // pointer to data
1091
1092 s >> cs; // read checksum
1093 ccs = (quint16) qChecksum(s: buf.constData() + data_start, len: buf.size() - data_start);
1094 if (ccs != cs) {
1095 qWarning(msg: "QPicturePaintEngine::checkFormat: Invalid checksum %x, %x expected",
1096 ccs, cs);
1097 pictb.close();
1098 return false;
1099 }
1100
1101 quint16 major, minor;
1102 s >> major >> minor; // read version number
1103 if (major > mfhdr_maj) { // new, incompatible version
1104 qWarning(msg: "QPicturePaintEngine::checkFormat: Incompatible version %d.%d",
1105 major, minor);
1106 pictb.close();
1107 return false;
1108 }
1109 s.setVersion(major != 4 ? major : 3);
1110
1111 quint8 c, clen;
1112 s >> c >> clen;
1113 if (c == QPicturePrivate::PdcBegin) {
1114 if (!(major >= 1 && major <= 3)) {
1115 qint32 l, t, w, h;
1116 s >> l >> t >> w >> h;
1117 brect = QRect(l, t, w, h);
1118 }
1119 } else {
1120 qWarning(msg: "QPicturePaintEngine::checkFormat: Format error");
1121 pictb.close();
1122 return false;
1123 }
1124 pictb.close();
1125
1126 formatOk = true; // picture seems to be ok
1127 formatMajor = major;
1128 formatMinor = minor;
1129 return true;
1130}
1131
1132/*! \internal */
1133QPaintEngine *QPicture::paintEngine() const
1134{
1135 if (!d_func()->paintEngine)
1136 const_cast<QPicture*>(this)->d_func()->paintEngine.reset(other: new QPicturePaintEngine);
1137 return d_func()->paintEngine.data();
1138}
1139
1140/*****************************************************************************
1141 QPicture stream functions
1142 *****************************************************************************/
1143
1144#ifndef QT_NO_DATASTREAM
1145/*!
1146 \relates QPicture
1147
1148 Writes picture \a r to the stream \a s and returns a reference to
1149 the stream.
1150*/
1151
1152QDataStream &operator<<(QDataStream &s, const QPicture &r)
1153{
1154 quint32 size = r.d_func()->pictb.buffer().size();
1155 s << size;
1156 // null picture ?
1157 if (size == 0)
1158 return s;
1159 // just write the whole buffer to the stream
1160 s.writeRawData (r.d_func()->pictb.buffer(), len: r.d_func()->pictb.buffer().size());
1161 return s;
1162}
1163
1164/*!
1165 \relates QPicture
1166
1167 Reads a picture from the stream \a s into picture \a r and returns
1168 a reference to the stream.
1169*/
1170
1171QDataStream &operator>>(QDataStream &s, QPicture &r)
1172{
1173 QDataStream sr;
1174
1175 // "init"; this code is similar to the beginning of QPicture::cmd()
1176 sr.setDevice(&r.d_func()->pictb);
1177 sr.setVersion(r.d_func()->formatMajor);
1178 quint32 len;
1179 s >> len;
1180 QByteArray data;
1181 if (len > 0) {
1182 data.resize(size: len);
1183 s.readRawData(data.data(), len);
1184 }
1185
1186 r.d_func()->pictb.setData(data);
1187 r.d_func()->resetFormat();
1188 return s;
1189}
1190#endif // QT_NO_DATASTREAM
1191
1192
1193#ifndef QT_NO_PICTUREIO
1194
1195QT_BEGIN_INCLUDE_NAMESPACE
1196#include "qregexp.h"
1197#include "qpictureformatplugin.h"
1198QT_END_INCLUDE_NAMESPACE
1199
1200#if QT_DEPRECATED_SINCE(5, 10)
1201/*!
1202 \obsolete
1203
1204 Returns a string that specifies the picture format of the file \a
1205 fileName, or \nullptr if the file cannot be read or if the format
1206 is not recognized.
1207
1208 \sa load(), save()
1209*/
1210
1211const char* QPicture::pictureFormat(const QString &fileName)
1212{
1213 const QByteArray format = QPictureIO::pictureFormat(fileName);
1214 // This function returns a const char * from a QByteArray.
1215 // Double check that the QByteArray is not detached, otherwise
1216 // we would return a dangling pointer.
1217 Q_ASSERT(!format.isDetached());
1218 return format;
1219}
1220
1221/*!
1222 \obsolete
1223
1224 Returns a list of picture formats that are supported for picture
1225 input.
1226
1227 \sa outputFormats(), inputFormatList(), QPictureIO
1228*/
1229QList<QByteArray> QPicture::inputFormats()
1230{
1231 return QPictureIO::inputFormats();
1232}
1233
1234static QStringList qToStringList(const QList<QByteArray> &arr)
1235{
1236 QStringList list;
1237 const int count = arr.count();
1238 list.reserve(alloc: count);
1239 for (int i = 0; i < count; ++i)
1240 list.append(t: QString::fromLatin1(str: arr.at(i)));
1241 return list;
1242}
1243
1244/*!
1245 \obsolete
1246
1247 Returns a list of picture formats that are supported for picture
1248 input.
1249
1250 Note that if you want to iterate over the list, you should iterate
1251 over a copy, e.g.
1252 \snippet picture/picture.cpp 2
1253
1254 \sa outputFormatList(), inputFormats(), QPictureIO
1255*/
1256QStringList QPicture::inputFormatList()
1257{
1258 return qToStringList(arr: QPictureIO::inputFormats());
1259}
1260
1261
1262/*!
1263 \obsolete
1264
1265 Returns a list of picture formats that are supported for picture
1266 output.
1267
1268 Note that if you want to iterate over the list, you should iterate
1269 over a copy, e.g.
1270 \snippet picture/picture.cpp 3
1271
1272 \sa inputFormatList(), outputFormats(), QPictureIO
1273*/
1274QStringList QPicture::outputFormatList()
1275{
1276 return qToStringList(arr: QPictureIO::outputFormats());
1277}
1278
1279/*!
1280 \obsolete
1281
1282 Returns a list of picture formats that are supported for picture
1283 output.
1284
1285 \sa inputFormats(), outputFormatList(), QPictureIO
1286*/
1287QList<QByteArray> QPicture::outputFormats()
1288{
1289 return QPictureIO::outputFormats();
1290}
1291#endif // QT_DEPRECATED_SINCE(5, 10)
1292
1293/*****************************************************************************
1294 QPictureIO member functions
1295 *****************************************************************************/
1296
1297/*!
1298 \obsolete
1299
1300 \class QPictureIO
1301
1302 \brief The QPictureIO class contains parameters for loading and
1303 saving pictures.
1304
1305 \ingroup painting
1306 \ingroup io
1307 \inmodule QtGui
1308
1309 QPictureIO contains a QIODevice object that is used for picture data
1310 I/O. The programmer can install new picture file formats in addition
1311 to those that Qt provides.
1312
1313 You don't normally need to use this class; QPicture::load(),
1314 QPicture::save().
1315
1316 \sa QPicture, QPixmap, QFile
1317*/
1318
1319struct QPictureIOData
1320{
1321 QPicture pi; // picture
1322 int iostat; // IO status
1323 QByteArray frmt; // picture format
1324 QIODevice *iodev; // IO device
1325 QString fname; // file name
1326 QString descr; // picture description
1327 const char *parameters;
1328 int quality;
1329 float gamma;
1330};
1331
1332/*!
1333 Constructs a QPictureIO object with all parameters set to zero.
1334*/
1335
1336QPictureIO::QPictureIO()
1337{
1338 init();
1339}
1340
1341/*!
1342 Constructs a QPictureIO object with the I/O device \a ioDevice and a
1343 \a format tag.
1344*/
1345
1346QPictureIO::QPictureIO(QIODevice *ioDevice, const char *format)
1347{
1348 init();
1349 d->iodev = ioDevice;
1350 d->frmt = format;
1351}
1352
1353/*!
1354 Constructs a QPictureIO object with the file name \a fileName and a
1355 \a format tag.
1356*/
1357
1358QPictureIO::QPictureIO(const QString &fileName, const char* format)
1359{
1360 init();
1361 d->frmt = format;
1362 d->fname = fileName;
1363}
1364
1365/*!
1366 Contains initialization common to all QPictureIO constructors.
1367*/
1368
1369void QPictureIO::init()
1370{
1371 d = new QPictureIOData();
1372 d->parameters = nullptr;
1373 d->quality = -1; // default quality of the current format
1374 d->gamma=0.0f;
1375 d->iostat = 0;
1376 d->iodev = nullptr;
1377}
1378
1379/*!
1380 Destroys the object and all related data.
1381*/
1382
1383QPictureIO::~QPictureIO()
1384{
1385 if (d->parameters)
1386 delete [] d->parameters;
1387 delete d;
1388}
1389
1390
1391/*****************************************************************************
1392 QPictureIO picture handler functions
1393 *****************************************************************************/
1394
1395class QPictureHandler
1396{
1397public:
1398 QPictureHandler(const char *f, const char *h, const QByteArray& fl,
1399 picture_io_handler r, picture_io_handler w);
1400 QByteArray format; // picture format
1401 QRegExp header; // picture header pattern
1402 enum TMode { Untranslated=0, TranslateIn, TranslateInOut } text_mode;
1403 picture_io_handler read_picture; // picture read function
1404 picture_io_handler write_picture; // picture write function
1405 bool obsolete; // support not "published"
1406};
1407
1408QPictureHandler::QPictureHandler(const char *f, const char *h, const QByteArray& fl,
1409 picture_io_handler r, picture_io_handler w)
1410 : format(f), header(QString::fromLatin1(str: h))
1411{
1412 text_mode = Untranslated;
1413 if (fl.contains(c: 't'))
1414 text_mode = TranslateIn;
1415 else if (fl.contains(c: 'T'))
1416 text_mode = TranslateInOut;
1417 obsolete = fl.contains(c: 'O');
1418 read_picture = r;
1419 write_picture = w;
1420}
1421
1422typedef QList<QPictureHandler *> QPHList;
1423Q_GLOBAL_STATIC(QPHList, pictureHandlers)
1424
1425void qt_init_picture_plugins()
1426{
1427 typedef QMultiMap<int, QString> PluginKeyMap;
1428 typedef PluginKeyMap::const_iterator PluginKeyMapConstIterator;
1429
1430 static QBasicMutex mutex;
1431 const auto locker = qt_scoped_lock(mutex);
1432 static QFactoryLoader loader(QPictureFormatInterface_iid,
1433 QStringLiteral("/pictureformats"));
1434
1435 const PluginKeyMap keyMap = loader.keyMap();
1436 const PluginKeyMapConstIterator cend = keyMap.constEnd();
1437 for (PluginKeyMapConstIterator it = keyMap.constBegin(); it != cend; ++it) {
1438 if (QPictureFormatPlugin *format = qobject_cast<QPictureFormatPlugin*>(object: loader.instance(index: it.key())))
1439 format->installIOHandler(format: it.value());
1440 }
1441}
1442
1443static void cleanup()
1444{
1445 // make sure that picture handlers are delete before plugin manager
1446 if (QPHList *list = pictureHandlers()) {
1447 qDeleteAll(c: *list);
1448 list->clear();
1449 }
1450}
1451
1452void qt_init_picture_handlers() // initialize picture handlers
1453{
1454 static QBasicAtomicInt done = Q_BASIC_ATOMIC_INITIALIZER(0);
1455 if (done.testAndSetRelaxed(expectedValue: 0, newValue: 1)) {
1456 qAddPostRoutine(cleanup);
1457 }
1458}
1459
1460static QPictureHandler *get_picture_handler(const char *format)
1461{ // get pointer to handler
1462 qt_init_picture_handlers();
1463 qt_init_picture_plugins();
1464 if (QPHList *list = pictureHandlers()) {
1465 for (int i = 0; i < list->size(); ++i) {
1466 if (list->at(i)->format == format)
1467 return list->at(i);
1468 }
1469 }
1470 return nullptr; // no such handler
1471}
1472
1473
1474/*!
1475 Defines a picture I/O handler for the picture format called \a
1476 format, which is recognized using the regular
1477 expression defined in \a header, read using \a readPicture and
1478 written using \a writePicture.
1479
1480 \a flags is a string of single-character flags for this format.
1481 The only flag defined currently is T (upper case), so the only
1482 legal value for \a flags are "T" and the empty string. The "T"
1483 flag means that the picture file is a text file, and Qt should treat
1484 all newline conventions as equivalent. (XPM files and some PPM
1485 files are text files for example.)
1486
1487 \a format is used to select a handler to write a QPicture; \a header
1488 is used to select a handler to read an picture file.
1489
1490 If \a readPicture is \nullptr, the QPictureIO will not be able
1491 to read pictures in \a format. If \a writePicture is \nullptr,
1492 the QPictureIO will not be able to write pictures in \a format. If
1493 both are null, the QPictureIO object is valid but useless.
1494
1495 Example:
1496 \snippet picture/picture.cpp 6
1497 \codeline
1498 \snippet picture/picture.cpp 7
1499 \codeline
1500 \snippet picture/picture.cpp 8
1501
1502 Before the regular expression test, all the 0 bytes in the file header are
1503 converted to 1 bytes. This is done because when Qt was ASCII-based, QRegExp
1504 could not handle 0 bytes in strings.
1505
1506 The regexp is only applied on the first 14 bytes of the file.
1507
1508 (Note that if one handlerIO supports writing a format and another
1509 supports reading it, Qt supports both reading and writing. If two
1510 handlers support the same operation, Qt chooses one arbitrarily.)
1511*/
1512
1513void QPictureIO::defineIOHandler(const char *format,
1514 const char *header,
1515 const char *flags,
1516 picture_io_handler readPicture,
1517 picture_io_handler writePicture)
1518{
1519 qt_init_picture_handlers();
1520 if (QPHList *list = pictureHandlers()) {
1521 QPictureHandler *p;
1522 p = new QPictureHandler(format, header, QByteArray(flags), readPicture, writePicture);
1523 list->prepend(t: p);
1524 }
1525}
1526
1527
1528/*****************************************************************************
1529 QPictureIO normal member functions
1530 *****************************************************************************/
1531
1532/*!
1533 Returns the picture currently set.
1534
1535 \sa setPicture()
1536*/
1537const QPicture &QPictureIO::picture() const { return d->pi; }
1538
1539/*!
1540 Returns the picture's IO status. A non-zero value indicates an
1541 error, whereas 0 means that the IO operation was successful.
1542
1543 \sa setStatus()
1544*/
1545int QPictureIO::status() const { return d->iostat; }
1546
1547/*!
1548 Returns the picture format string or \nullptr if no format has been
1549 explicitly set.
1550*/
1551const char *QPictureIO::format() const { return d->frmt; }
1552
1553/*!
1554 Returns the IO device currently set.
1555
1556 \sa setIODevice()
1557*/
1558QIODevice *QPictureIO::ioDevice() const { return d->iodev; }
1559
1560/*!
1561 Returns the file name currently set.
1562
1563 \sa setFileName()
1564*/
1565QString QPictureIO::fileName() const { return d->fname; }
1566
1567
1568/*!
1569 Returns the picture description string.
1570
1571 \sa setDescription()
1572*/
1573QString QPictureIO::description() const { return d->descr; }
1574
1575/*!
1576 Sets the picture to \a picture.
1577
1578 \sa picture()
1579*/
1580void QPictureIO::setPicture(const QPicture &picture)
1581{
1582 d->pi = picture;
1583}
1584
1585/*!
1586 Sets the picture IO status to \a status. A non-zero value indicates
1587 an error, whereas 0 means that the IO operation was successful.
1588
1589 \sa status()
1590*/
1591void QPictureIO::setStatus(int status)
1592{
1593 d->iostat = status;
1594}
1595
1596/*!
1597 Sets the picture format to \a format for the picture to be read or
1598 written.
1599
1600 It is necessary to specify a format before writing an picture, but
1601 it is not necessary to specify a format before reading an picture.
1602
1603 If no format has been set, Qt guesses the picture format before
1604 reading it. If a format is set the picture will only be read if it
1605 has that format.
1606
1607 \sa read(), write(), format()
1608*/
1609void QPictureIO::setFormat(const char *format)
1610{
1611 d->frmt = format;
1612}
1613
1614/*!
1615 Sets the IO device to be used for reading or writing an picture.
1616
1617 Setting the IO device allows pictures to be read/written to any
1618 block-oriented QIODevice.
1619
1620 If \a ioDevice is not null, this IO device will override file name
1621 settings.
1622
1623 \sa setFileName()
1624*/
1625void QPictureIO::setIODevice(QIODevice *ioDevice)
1626{
1627 d->iodev = ioDevice;
1628}
1629
1630/*!
1631 Sets the name of the file to read or write an picture from to \a
1632 fileName.
1633
1634 \sa setIODevice()
1635*/
1636void QPictureIO::setFileName(const QString &fileName)
1637{
1638 d->fname = fileName;
1639}
1640
1641/*!
1642 Returns the quality of the written picture, related to the
1643 compression ratio.
1644
1645 \sa setQuality(), QPicture::save()
1646*/
1647int QPictureIO::quality() const
1648{
1649 return d->quality;
1650}
1651
1652/*!
1653 Sets the quality of the written picture to \a q, related to the
1654 compression ratio.
1655
1656 \a q must be in the range -1..100. Specify 0 to obtain small
1657 compressed files, 100 for large uncompressed files. (-1 signifies
1658 the default compression.)
1659
1660 \sa quality(), QPicture::save()
1661*/
1662
1663void QPictureIO::setQuality(int q)
1664{
1665 d->quality = q;
1666}
1667
1668/*!
1669 Returns the picture's parameters string.
1670
1671 \sa setParameters()
1672*/
1673
1674const char *QPictureIO::parameters() const
1675{
1676 return d->parameters;
1677}
1678
1679/*!
1680 Sets the picture's parameter string to \a parameters. This is for
1681 picture handlers that require special parameters.
1682
1683 Although the current picture formats supported by Qt ignore the
1684 parameters string, it may be used in future extensions or by
1685 contributions (for example, JPEG).
1686
1687 \sa parameters()
1688*/
1689
1690void QPictureIO::setParameters(const char *parameters)
1691{
1692 if (d->parameters)
1693 delete [] d->parameters;
1694 d->parameters = qstrdup(parameters);
1695}
1696
1697/*!
1698 Sets the gamma value at which the picture will be viewed to \a
1699 gamma. If the picture format stores a gamma value for which the
1700 picture is intended to be used, then this setting will be used to
1701 modify the picture. Setting to 0.0 will disable gamma correction
1702 (i.e. any specification in the file will be ignored).
1703
1704 The default value is 0.0.
1705
1706 \sa gamma()
1707*/
1708void QPictureIO::setGamma(float gamma)
1709{
1710 d->gamma=gamma;
1711}
1712
1713/*!
1714 Returns the gamma value at which the picture will be viewed.
1715
1716 \sa setGamma()
1717*/
1718float QPictureIO::gamma() const
1719{
1720 return d->gamma;
1721}
1722
1723/*!
1724 Sets the picture description string for picture handlers that support
1725 picture descriptions to \a description.
1726
1727 Currently, no picture format supported by Qt uses the description
1728 string.
1729*/
1730
1731void QPictureIO::setDescription(const QString &description)
1732{
1733 d->descr = description;
1734}
1735
1736
1737/*!
1738 Returns a string that specifies the picture format of the file \a
1739 fileName, or null if the file cannot be read or if the format is
1740 not recognized.
1741*/
1742
1743QByteArray QPictureIO::pictureFormat(const QString &fileName)
1744{
1745 QFile file(fileName);
1746 QByteArray format;
1747 if (!file.open(flags: QIODevice::ReadOnly))
1748 return format;
1749 format = pictureFormat(&file);
1750 file.close();
1751 return format;
1752}
1753
1754/*!
1755 \overload
1756
1757 Returns a string that specifies the picture format of the picture read
1758 from IO device \a d, or 0 if the device cannot be read or if the
1759 format is not recognized.
1760
1761 Make sure that \a d is at the right position in the device (for
1762 example, at the beginning of the file).
1763
1764 \sa QIODevice::pos()
1765*/
1766
1767QByteArray QPictureIO::pictureFormat(QIODevice *d)
1768{
1769 // if you change this change the documentation for defineIOHandler()
1770 const int buflen = 14;
1771
1772 char buf[buflen];
1773 char buf2[buflen];
1774 qt_init_picture_handlers();
1775 qt_init_picture_plugins();
1776 int pos = d->pos(); // save position
1777 int rdlen = d->read(data: buf, maxlen: buflen); // read a few bytes
1778
1779 QByteArray format;
1780 if (rdlen != buflen)
1781 return format;
1782
1783 memcpy(dest: buf2, src: buf, n: buflen);
1784
1785 for (int n = 0; n < rdlen; n++)
1786 if (buf[n] == '\0')
1787 buf[n] = '\001';
1788 if (rdlen > 0) {
1789 buf[rdlen - 1] = '\0';
1790 QString bufStr = QString::fromLatin1(str: buf);
1791 if (QPHList *list = pictureHandlers()) {
1792 for (int i = 0; i < list->size(); ++i) {
1793 if (list->at(i)->header.indexIn(str: bufStr) != -1) { // try match with headers
1794 format = list->at(i)->format;
1795 break;
1796 }
1797 }
1798 }
1799 }
1800 d->seek(pos); // restore position
1801 return format;
1802}
1803
1804/*!
1805 Returns a sorted list of picture formats that are supported for
1806 picture input.
1807*/
1808QList<QByteArray> QPictureIO::inputFormats()
1809{
1810 QList<QByteArray> result;
1811
1812 qt_init_picture_handlers();
1813 qt_init_picture_plugins();
1814
1815 if (QPHList *list = pictureHandlers()) {
1816 for (int i = 0; i < list->size(); ++i) {
1817 QPictureHandler *p = list->at(i);
1818 if (p->read_picture && !p->obsolete && !result.contains(t: p->format))
1819 result.append(t: p->format);
1820 }
1821 }
1822 std::sort(first: result.begin(), last: result.end());
1823
1824 return result;
1825}
1826
1827/*!
1828 Returns a sorted list of picture formats that are supported for
1829 picture output.
1830*/
1831QList<QByteArray> QPictureIO::outputFormats()
1832{
1833 qt_init_picture_handlers();
1834 qt_init_picture_plugins();
1835
1836 QList<QByteArray> result;
1837 if (QPHList *list = pictureHandlers()) {
1838 for (int i = 0; i < list->size(); ++i) {
1839 QPictureHandler *p = list->at(i);
1840 if (p->write_picture && !p->obsolete && !result.contains(t: p->format))
1841 result.append(t: p->format);
1842 }
1843 }
1844 return result;
1845}
1846
1847
1848
1849/*!
1850 Reads an picture into memory and returns \c true if the picture was
1851 successfully read; otherwise returns \c false.
1852
1853 Before reading an picture you must set an IO device or a file name.
1854 If both an IO device and a file name have been set, the IO device
1855 will be used.
1856
1857 Setting the picture file format string is optional.
1858
1859 Note that this function does \e not set the \l{format()}{format} used to read the picture. If you need that
1860 information, use the pictureFormat() static functions.
1861
1862 Example:
1863
1864 \snippet picture/picture.cpp 4
1865
1866 \sa setIODevice(), setFileName(), setFormat(), write(), QPixmap::load()
1867*/
1868bool QPictureIO::read()
1869{
1870 QFile file;
1871 QByteArray picture_format;
1872 QPictureHandler *h;
1873
1874 if (d->iodev) { // read from io device
1875 // ok, already open
1876 } else if (!d->fname.isEmpty()) { // read from file
1877 file.setFileName(d->fname);
1878 if (!file.open(flags: QIODevice::ReadOnly))
1879 return false; // cannot open file
1880 d->iodev = &file;
1881 } else { // no file name or io device
1882 return false;
1883 }
1884 if (d->frmt.isEmpty()) {
1885 // Try to guess format
1886 picture_format = pictureFormat(d: d->iodev); // get picture format
1887 if (picture_format.isEmpty()) {
1888 if (file.isOpen()) { // unknown format
1889 file.close();
1890 d->iodev = nullptr;
1891 }
1892 return false;
1893 }
1894 } else {
1895 picture_format = d->frmt;
1896 }
1897
1898 h = get_picture_handler(format: picture_format);
1899 if (file.isOpen()) {
1900#if !defined(Q_OS_UNIX)
1901 if (h && h->text_mode) { // reopen in translated mode
1902 file.close();
1903 file.open(QIODevice::ReadOnly | QIODevice::Text);
1904 }
1905 else
1906#endif
1907 file.seek(offset: 0); // position to start
1908 }
1909 d->iostat = 1; // assume error
1910
1911 if (h && h->read_picture)
1912 (*h->read_picture)(this);
1913
1914 if (file.isOpen()) { // picture was read using file
1915 file.close();
1916 d->iodev = nullptr;
1917 }
1918 return d->iostat == 0; // picture successfully read?
1919}
1920
1921
1922/*!
1923 Writes an picture to an IO device and returns \c true if the picture was
1924 successfully written; otherwise returns \c false.
1925
1926 Before writing an picture you must set an IO device or a file name.
1927 If both an IO device and a file name have been set, the IO device
1928 will be used.
1929
1930 The picture will be written using the specified picture format.
1931
1932 Example:
1933 \snippet picture/picture.cpp 5
1934
1935 \sa setIODevice(), setFileName(), setFormat(), read(), QPixmap::save()
1936*/
1937bool QPictureIO::write()
1938{
1939 if (d->frmt.isEmpty())
1940 return false;
1941 QPictureHandler *h = get_picture_handler(format: d->frmt);
1942 if (!h || !h->write_picture) {
1943 qWarning(msg: "QPictureIO::write: No such picture format handler: %s",
1944 format());
1945 return false;
1946 }
1947 QFile file;
1948 if (!d->iodev && !d->fname.isEmpty()) {
1949 file.setFileName(d->fname);
1950 bool translate = h->text_mode==QPictureHandler::TranslateInOut;
1951 QIODevice::OpenMode fmode = translate ? QIODevice::WriteOnly | QIODevice::Text : QIODevice::OpenMode(QIODevice::WriteOnly);
1952 if (!file.open(flags: fmode)) // couldn't create file
1953 return false;
1954 d->iodev = &file;
1955 }
1956 d->iostat = 1;
1957 (*h->write_picture)(this);
1958 if (file.isOpen()) { // picture was written using file
1959 file.close();
1960 d->iodev = nullptr;
1961 }
1962 return d->iostat == 0; // picture successfully written?
1963}
1964#endif //QT_NO_PICTUREIO
1965
1966QT_END_NAMESPACE
1967
1968#endif // QT_NO_PICTURE
1969
1970/*!
1971 \typedef QPicture::DataPtr
1972 \internal
1973*/
1974
1975/*!
1976 \fn DataPtr &QPicture::data_ptr()
1977 \internal
1978*/
1979

source code of qtbase/src/gui/image/qpicture.cpp