KImageFormats

pcx.cpp
1/*
2 This file is part of the KDE project
3 SPDX-FileCopyrightText: 2002-2005 Nadeem Hasan <nhasan@kde.org>
4
5 SPDX-License-Identifier: LGPL-2.0-or-later
6*/
7
8#include "pcx_p.h"
9#include "util_p.h"
10
11#include <QColor>
12#include <QDataStream>
13#include <QDebug>
14#include <QImage>
15
16#pragma pack(push, 1)
17class RGB
18{
19public:
20 quint8 r;
21 quint8 g;
22 quint8 b;
23
24 static RGB from(const QRgb color)
25 {
26 RGB c;
27 c.r = qRed(color);
28 c.g = qGreen(color);
29 c.b = qBlue(color);
30 return c;
31 }
32};
33
34class Palette
35{
36public:
37 void setColor(int i, const QRgb color)
38 {
39 RGB &c = rgb[i];
40 c.r = qRed(color);
41 c.g = qGreen(color);
42 c.b = qBlue(color);
43 }
44
45 QRgb color(int i) const
46 {
47 return qRgb(rgb[i].r, rgb[i].g, rgb[i].b);
48 }
49
50 class RGB rgb[16];
51};
52
53class PCXHEADER
54{
55public:
56 PCXHEADER();
57
58 inline int width() const
59 {
60 return (XMax - XMin) + 1;
61 }
62 inline int height() const
63 {
64 return (YMax - YMin) + 1;
65 }
66 inline bool isCompressed() const
67 {
68 return (Encoding == 1);
69 }
70 /*!
71 * \brief isValid
72 * Checks if the header data are valid for the PCX.
73 * \note Put here the header sanity checks.
74 * \return True if the header is a valid PCX header, otherwise false.
75 */
76 inline bool isValid() const
77 {
78 return Manufacturer == 10 && BytesPerLine != 0;
79 }
80 /*!
81 * \brief isSupported
82 * \return True if the header is valid and the PCX format is supported by the plugin. Otherwise false.
83 */
84 inline bool isSupported() const
85 {
86 return isValid() && format() != QImage::Format_Invalid;
87 }
88 inline QImage::Format format() const
89 {
90 auto fmt = QImage::Format_Invalid;
91 if (Bpp == 1 && NPlanes == 1) {
93 } else if (Bpp == 1 && NPlanes == 4) {
95 } else if (Bpp == 4 && NPlanes == 1) {
97 } else if (Bpp == 8 && NPlanes == 1) {
99 } else if (Bpp == 8 && NPlanes == 3) {
101 }
102 return fmt;
103 }
104
105 quint8 Manufacturer; // Constant Flag, 10 = ZSoft .pcx
106 quint8 Version; // Version information·
107 // 0 = Version 2.5 of PC Paintbrush·
108 // 2 = Version 2.8 w/palette information·
109 // 3 = Version 2.8 w/o palette information·
110 // 4 = PC Paintbrush for Windows(Plus for
111 // Windows uses Ver 5)·
112 // 5 = Version 3.0 and > of PC Paintbrush
113 // and PC Paintbrush +, includes
114 // Publisher's Paintbrush . Includes
115 // 24-bit .PCX files·
116 quint8 Encoding; // 1 = .PCX run length encoding
117 quint8 Bpp; // Number of bits to represent a pixel
118 // (per Plane) - 1, 2, 4, or 8·
119 quint16 XMin;
120 quint16 YMin;
121 quint16 XMax;
122 quint16 YMax;
123 quint16 HDpi;
124 quint16 YDpi;
125 Palette ColorMap;
126 quint8 Reserved; // Should be set to 0.
127 quint8 NPlanes; // Number of color planes
128 quint16 BytesPerLine; // Number of bytes to allocate for a scanline
129 // plane. MUST be an EVEN number. Do NOT
130 // calculate from Xmax-Xmin.·
131 quint16 PaletteInfo; // How to interpret palette- 1 = Color/BW,
132 // 2 = Grayscale ( ignored in PB IV/ IV + )·
133 quint16 HScreenSize; // Horizontal screen size in pixels. New field
134 // found only in PB IV/IV Plus
135 quint16 VScreenSize; // Vertical screen size in pixels. New field
136 // found only in PB IV/IV Plus
137
138 quint8 unused[54];
139};
140
141#pragma pack(pop)
142
143static QDataStream &operator>>(QDataStream &s, RGB &rgb)
144{
145 quint8 r;
146 quint8 g;
147 quint8 b;
148
149 s >> r >> g >> b;
150 rgb.r = r;
151 rgb.g = g;
152 rgb.b = b;
153
154 return s;
155}
156
158{
159 for (int i = 0; i < 16; ++i) {
160 s >> pal.rgb[i];
161 }
162
163 return s;
164}
165
166static QDataStream &operator>>(QDataStream &s, PCXHEADER &ph)
167{
168 quint8 m;
169 quint8 ver;
170 quint8 enc;
171 quint8 bpp;
172 s >> m >> ver >> enc >> bpp;
173 ph.Manufacturer = m;
174 ph.Version = ver;
175 ph.Encoding = enc;
176 ph.Bpp = bpp;
177 quint16 xmin;
178 quint16 ymin;
179 quint16 xmax;
180 quint16 ymax;
181 s >> xmin >> ymin >> xmax >> ymax;
182 ph.XMin = xmin;
183 ph.YMin = ymin;
184 ph.XMax = xmax;
185 ph.YMax = ymax;
186 quint16 hdpi;
187 quint16 ydpi;
188 s >> hdpi >> ydpi;
189 ph.HDpi = hdpi;
190 ph.YDpi = ydpi;
191 Palette colorMap;
192 quint8 res;
193 quint8 np;
194 s >> colorMap >> res >> np;
195 ph.ColorMap = colorMap;
196 ph.Reserved = res;
197 ph.NPlanes = np;
198 quint16 bytesperline;
199 s >> bytesperline;
200 ph.BytesPerLine = bytesperline;
201 quint16 paletteinfo;
202 s >> paletteinfo;
203 ph.PaletteInfo = paletteinfo;
204 quint16 hscreensize;
205 quint16 vscreensize;
206 s >> hscreensize;
207 ph.HScreenSize = hscreensize;
208 s >> vscreensize;
209 ph.VScreenSize = vscreensize;
210
211 // Skip the rest of the header
212 for (size_t i = 0, n = sizeof(ph.unused); i < n; ++i) {
213 s >> ph.unused[i];
214 }
215
216 return s;
217}
218
219static QDataStream &operator<<(QDataStream &s, const RGB rgb)
220{
221 s << rgb.r << rgb.g << rgb.b;
222
223 return s;
224}
225
226static QDataStream &operator<<(QDataStream &s, const Palette &pal)
227{
228 for (int i = 0; i < 16; ++i) {
229 s << pal.rgb[i];
230 }
231
232 return s;
233}
234
235static QDataStream &operator<<(QDataStream &s, const PCXHEADER &ph)
236{
237 s << ph.Manufacturer;
238 s << ph.Version;
239 s << ph.Encoding;
240 s << ph.Bpp;
241 s << ph.XMin << ph.YMin << ph.XMax << ph.YMax;
242 s << ph.HDpi << ph.YDpi;
243 s << ph.ColorMap;
244 s << ph.Reserved;
245 s << ph.NPlanes;
246 s << ph.BytesPerLine;
247 s << ph.PaletteInfo;
248 s << ph.HScreenSize;
249 s << ph.VScreenSize;
250
251 for (size_t i = 0, n = sizeof(ph.unused); i < n; ++i) {
252 s << ph.unused[i];
253 }
254
255 return s;
256}
257
258PCXHEADER::PCXHEADER()
259{
260 // Initialize all data to zero
261 QByteArray dummy(128, 0);
262 dummy.fill(0);
264 s >> *this;
265}
266
267bool peekHeader(QIODevice *d, PCXHEADER& h)
268{
269 auto head = d->peek(sizeof(PCXHEADER));
270 if (size_t(head.size()) < sizeof(PCXHEADER)) {
271 return false;
272 }
273
274 QDataStream ds(head);
275 ds.setByteOrder(QDataStream::LittleEndian);
276 ds >> h;
277
278 return ds.status() == QDataStream::Ok && h.isValid();
279}
280
281static bool readLine(QDataStream &s, QByteArray &buf, const PCXHEADER &header)
282{
283 quint32 i = 0;
284 quint32 size = buf.size();
285 quint8 byte;
286 quint8 count;
287
288 if (header.isCompressed()) {
289 // Uncompress the image data
290 while (i < size) {
291 count = 1;
292 s >> byte;
293 if (byte > 0xc0) {
294 count = byte - 0xc0;
295 s >> byte;
296 }
297 while (count-- && i < size) {
298 buf[i++] = byte;
299 }
300 }
301 } else {
302 // Image is not compressed (possible?)
303 while (i < size) {
304 s >> byte;
305 buf[i++] = byte;
306 }
307 }
308
309 return (s.status() == QDataStream::Ok);
310}
311
312static bool readImage1(QImage &img, QDataStream &s, const PCXHEADER &header)
313{
314 QByteArray buf(header.BytesPerLine, 0);
315
316 img = imageAlloc(header.width(), header.height(), header.format());
317 img.setColorCount(2);
318
319 if (img.isNull()) {
320 qWarning() << "Failed to allocate image, invalid dimensions?" << QSize(header.width(), header.height());
321 return false;
322 }
323
324 for (int y = 0; y < header.height(); ++y) {
325 if (s.atEnd()) {
326 return false;
327 }
328
329 if (!readLine(s, buf, header)) {
330 return false;
331 }
332
333 uchar *p = img.scanLine(y);
334 unsigned int bpl = qMin((quint16)((header.width() + 7) / 8), header.BytesPerLine);
335 for (unsigned int x = 0; x < bpl; ++x) {
336 p[x] = buf[x];
337 }
338 }
339
340 // Set the color palette
341 img.setColor(0, qRgb(0, 0, 0));
342 img.setColor(1, qRgb(255, 255, 255));
343
344 return true;
345}
346
347static bool readImage4(QImage &img, QDataStream &s, const PCXHEADER &header)
348{
349 QByteArray buf(header.BytesPerLine * 4, 0);
350 QByteArray pixbuf(header.width(), 0);
351
352 img = imageAlloc(header.width(), header.height(), header.format());
353 img.setColorCount(16);
354 if (img.isNull()) {
355 qWarning() << "Failed to allocate image, invalid dimensions?" << QSize(header.width(), header.height());
356 return false;
357 }
358
359 if (header.BytesPerLine < (header.width() + 7) / 8) {
360 qWarning() << "PCX image has invalid BytesPerLine value";
361 return false;
362 }
363
364 for (int y = 0; y < header.height(); ++y) {
365 if (s.atEnd()) {
366 return false;
367 }
368
369 pixbuf.fill(0);
370 if (!readLine(s, buf, header)) {
371 return false;
372 }
373
374 for (int i = 0; i < 4; i++) {
375 quint32 offset = i * header.BytesPerLine;
376 for (int x = 0; x < header.width(); ++x) {
377 if (buf[offset + (x / 8)] & (128 >> (x % 8))) {
378 pixbuf[x] = (int)(pixbuf[x]) + (1 << i);
379 }
380 }
381 }
382
383 uchar *p = img.scanLine(y);
384 if (!p) {
385 qWarning() << "Failed to get scanline for" << y << "might be out of bounds";
386 }
387 for (int x = 0; x < header.width(); ++x) {
388 p[x] = pixbuf[x];
389 }
390 }
391
392 // Read the palette
393 for (int i = 0; i < 16; ++i) {
394 img.setColor(i, header.ColorMap.color(i));
395 }
396
397 return true;
398}
399
400static bool readImage4v2(QImage &img, QDataStream &s, const PCXHEADER &header)
401{
402 QByteArray buf(header.BytesPerLine, 0);
403
404 img = imageAlloc(header.width(), header.height(), header.format());
405 img.setColorCount(16);
406
407 if (img.isNull()) {
408 qWarning() << "Failed to allocate image, invalid dimensions?" << QSize(header.width(), header.height());
409 return false;
410 }
411
412 for (int y = 0; y < header.height(); ++y) {
413 if (s.atEnd()) {
414 return false;
415 }
416
417 if (!readLine(s, buf, header)) {
418 return false;
419 }
420
421 uchar *p = img.scanLine(y);
422 if (!p) {
423 return false;
424 }
425
426 const unsigned int bpl = std::min(header.BytesPerLine, static_cast<quint16>(header.width() / 2));
427 for (unsigned int x = 0; x < bpl; ++x) {
428 p[x * 2] = (buf[x] & 240) >> 4;
429 p[x * 2 + 1] = buf[x] & 15;
430 }
431 }
432
433 // Read the palette
434 for (int i = 0; i < 16; ++i) {
435 img.setColor(i, header.ColorMap.color(i));
436 }
437
438 return (s.status() == QDataStream::Ok);
439}
440
441static bool readImage8(QImage &img, QDataStream &s, const PCXHEADER &header)
442{
443 QByteArray buf(header.BytesPerLine, 0);
444
445 img = imageAlloc(header.width(), header.height(), header.format());
446 img.setColorCount(256);
447
448 if (img.isNull()) {
449 qWarning() << "Failed to allocate image, invalid dimensions?" << QSize(header.width(), header.height());
450 return false;
451 }
452
453 for (int y = 0; y < header.height(); ++y) {
454 if (s.atEnd()) {
455 return false;
456 }
457
458 if (!readLine(s, buf, header)) {
459 return false;
460 }
461
462 uchar *p = img.scanLine(y);
463 if (!p) {
464 return false;
465 }
466
467 unsigned int bpl = qMin(header.BytesPerLine, (quint16)header.width());
468 for (unsigned int x = 0; x < bpl; ++x) {
469 p[x] = buf[x];
470 }
471 }
472
473 // by specification, the extended palette starts at file.size() - 769
474 quint8 flag = 0;
475 if (auto device = s.device()) {
476 if (device->isSequential()) {
477 while (flag != 12 && s.status() == QDataStream::Ok) {
478 s >> flag;
479 }
480 }
481 else {
482 device->seek(device->size() - 769);
483 s >> flag;
484 }
485 }
486
487 // qDebug() << "Palette Flag: " << flag;
488 if (flag == 12 && (header.Version == 5 || header.Version == 2)) {
489 // Read the palette
490 quint8 r;
491 quint8 g;
492 quint8 b;
493 for (int i = 0; i < 256; ++i) {
494 s >> r >> g >> b;
495 img.setColor(i, qRgb(r, g, b));
496 }
497 }
498
499 return (s.status() == QDataStream::Ok);
500}
501
502static bool readImage24(QImage &img, QDataStream &s, const PCXHEADER &header)
503{
504 QByteArray r_buf(header.BytesPerLine, 0);
505 QByteArray g_buf(header.BytesPerLine, 0);
506 QByteArray b_buf(header.BytesPerLine, 0);
507
508 img = imageAlloc(header.width(), header.height(), header.format());
509
510 if (img.isNull()) {
511 qWarning() << "Failed to allocate image, invalid dimensions?" << QSize(header.width(), header.height());
512 return false;
513 }
514
515 const unsigned int bpl = std::min(header.BytesPerLine, static_cast<quint16>(header.width()));
516
517 for (int y = 0; y < header.height(); ++y) {
518 if (s.atEnd()) {
519 return false;
520 }
521
522 if (!readLine(s, r_buf, header)) {
523 return false;
524 }
525 if (!readLine(s, g_buf, header)) {
526 return false;
527 }
528 if (!readLine(s, b_buf, header)) {
529 return false;
530 }
531
532 uint *p = (uint *)img.scanLine(y);
533
534 for (unsigned int x = 0; x < bpl; ++x) {
535 p[x] = qRgb(r_buf[x], g_buf[x], b_buf[x]);
536 }
537 }
538
539 return true;
540}
541
542static bool writeLine(QDataStream &s, QByteArray &buf)
543{
544 quint32 i = 0;
545 quint32 size = buf.size();
546 quint8 count;
547 quint8 data;
548 char byte;
549
550 while (i < size) {
551 count = 1;
552 byte = buf[i++];
553
554 while ((i < size) && (byte == buf[i]) && (count < 63)) {
555 ++i;
556 ++count;
557 }
558
559 data = byte;
560
561 if (count > 1 || data >= 0xc0) {
562 count |= 0xc0;
563 s << count;
564 }
565
566 s << data;
567 }
568 return (s.status() == QDataStream::Ok);
569}
570
571static bool writeImage1(QImage &img, QDataStream &s, PCXHEADER &header)
572{
573 if (img.format() != QImage::Format_Mono) {
575 }
576 if (img.isNull() || img.colorCount() < 1) {
577 return false;
578 }
579 auto rgb = img.color(0);
580 auto minIsBlack = (qRed(rgb) + qGreen(rgb) + qBlue(rgb)) / 3 < 127;
581
582 header.Bpp = 1;
583 header.NPlanes = 1;
584 header.BytesPerLine = img.bytesPerLine();
585 if (header.BytesPerLine == 0) {
586 return false;
587 }
588
589 s << header;
590
591 QByteArray buf(header.BytesPerLine, 0);
592
593 for (int y = 0; y < header.height(); ++y) {
594 quint8 *p = img.scanLine(y);
595
596 // Invert as QImage uses reverse palette for monochrome images?
597 for (int i = 0; i < header.BytesPerLine; ++i) {
598 buf[i] = minIsBlack ? p[i] : ~p[i];
599 }
600
601 if (!writeLine(s, buf)) {
602 return false;
603 }
604 }
605 return true;
606}
607
608static bool writeImage4(QImage &img, QDataStream &s, PCXHEADER &header)
609{
610 header.Bpp = 1;
611 header.NPlanes = 4;
612 header.BytesPerLine = header.width() / 8;
613 if (header.BytesPerLine == 0) {
614 return false;
615 }
616
617 for (int i = 0; i < 16; ++i) {
618 header.ColorMap.setColor(i, img.color(i));
619 }
620
621 s << header;
622
623 QByteArray buf[4];
624
625 for (int i = 0; i < 4; ++i) {
626 buf[i].resize(header.BytesPerLine);
627 }
628
629 for (int y = 0; y < header.height(); ++y) {
630 quint8 *p = img.scanLine(y);
631
632 for (int i = 0; i < 4; ++i) {
633 buf[i].fill(0);
634 }
635
636 for (int x = 0; x < header.width(); ++x) {
637 for (int i = 0; i < 4; ++i) {
638 if (*(p + x) & (1 << i)) {
639 buf[i][x / 8] = (int)(buf[i][x / 8]) | 1 << (7 - x % 8);
640 }
641 }
642 }
643
644 for (int i = 0; i < 4; ++i) {
645 if (!writeLine(s, buf[i])) {
646 return false;
647 }
648 }
649 }
650 return true;
651}
652
653static bool writeImage8(QImage &img, QDataStream &s, PCXHEADER &header)
654{
655 header.Bpp = 8;
656 header.NPlanes = 1;
657 header.BytesPerLine = img.bytesPerLine();
658 if (header.BytesPerLine == 0) {
659 return false;
660 }
661
662 s << header;
663
664 QByteArray buf(header.BytesPerLine, 0);
665
666 for (int y = 0; y < header.height(); ++y) {
667 quint8 *p = img.scanLine(y);
668
669 for (int i = 0; i < header.BytesPerLine; ++i) {
670 buf[i] = p[i];
671 }
672
673 if (!writeLine(s, buf)) {
674 return false;
675 }
676 }
677
678 // Write palette flag
679 quint8 byte = 12;
680 s << byte;
681
682 // Write palette
683 for (int i = 0; i < 256; ++i) {
684 s << RGB::from(img.color(i));
685 }
686
687 return (s.status() == QDataStream::Ok);
688}
689
690static bool writeImage24(QImage &img, QDataStream &s, PCXHEADER &header)
691{
692 header.Bpp = 8;
693 header.NPlanes = 3;
694 header.BytesPerLine = header.width();
695 if (header.BytesPerLine == 0) {
696 return false;
697 }
698
699 if (img.format() != QImage::Format_ARGB32 && img.format() != QImage::Format_RGB32) {
701 }
702 if (img.isNull()) {
703 return false;
704 }
705
706 s << header;
707
708 QByteArray r_buf(header.width(), 0);
709 QByteArray g_buf(header.width(), 0);
710 QByteArray b_buf(header.width(), 0);
711
712 for (int y = 0; y < header.height(); ++y) {
713 auto p = (QRgb*)img.scanLine(y);
714
715 for (int x = 0; x < header.width(); ++x) {
716 QRgb rgb = *p++;
717 r_buf[x] = qRed(rgb);
718 g_buf[x] = qGreen(rgb);
719 b_buf[x] = qBlue(rgb);
720 }
721
722 if (!writeLine(s, r_buf)) {
723 return false;
724 }
725 if (!writeLine(s, g_buf)) {
726 return false;
727 }
728 if (!writeLine(s, b_buf)) {
729 return false;
730 }
731 }
732
733 return true;
734}
735
736class PCXHandlerPrivate
737{
738public:
739 PCXHandlerPrivate() {}
740 ~PCXHandlerPrivate() {}
741
742 PCXHEADER m_header;
743};
744
745PCXHandler::PCXHandler()
747 , d(new PCXHandlerPrivate)
748{
749}
750
751bool PCXHandler::canRead() const
752{
753 if (canRead(device())) {
754 setFormat("pcx");
755 return true;
756 }
757 return false;
758}
759
760bool PCXHandler::read(QImage *outImage)
761{
762 QDataStream s(device());
764
765 if (s.device()->size() < 128) {
766 return false;
767 }
768
769 auto&& header = d->m_header;
770 s >> header;
771
772 if (s.status() != QDataStream::Ok || s.atEnd()) {
773 return false;
774 }
775
776 if (!header.isSupported()) {
777 return false;
778 }
779
780 auto ok = false;
781 QImage img;
782 if (header.Bpp == 1 && header.NPlanes == 1) {
783 ok = readImage1(img, s, header);
784 } else if (header.Bpp == 1 && header.NPlanes == 4) {
785 ok = readImage4(img, s, header);
786 } else if (header.Bpp == 4 && header.NPlanes == 1) {
787 ok = readImage4v2(img, s, header);
788 } else if (header.Bpp == 8 && header.NPlanes == 1) {
789 ok = readImage8(img, s, header);
790 } else if (header.Bpp == 8 && header.NPlanes == 3) {
791 ok = readImage24(img, s, header);
792 }
793
794 if (img.isNull() || !ok) {
795 return false;
796 }
797
798 img.setDotsPerMeterX(qRound(header.HDpi / 25.4 * 1000));
799 img.setDotsPerMeterY(qRound(header.YDpi / 25.4 * 1000));
800 *outImage = img;
801 return true;
802}
803
804bool PCXHandler::write(const QImage &image)
805{
806 QDataStream s(device());
808
809 QImage img = image;
810
811 const int w = img.width();
812 const int h = img.height();
813
814 if (w > 65536 || h > 65536) {
815 return false;
816 }
817
818 PCXHEADER header;
819
820 header.Manufacturer = 10;
821 header.Version = 5;
822 header.Encoding = 1;
823 header.XMin = 0;
824 header.YMin = 0;
825 header.XMax = w - 1;
826 header.YMax = h - 1;
827 header.HDpi = qRound(image.dotsPerMeterX() * 25.4 / 1000);
828 header.YDpi = qRound(image.dotsPerMeterY() * 25.4 / 1000);
829 header.Reserved = 0;
830 header.PaletteInfo = 1;
831
832 auto ok = false;
833 if (img.depth() == 1) {
834 ok = writeImage1(img, s, header);
835 } else if (img.depth() == 8 && img.colorCount() <= 16) {
836 ok = writeImage4(img, s, header);
837 } else if (img.depth() == 8) {
838 ok = writeImage8(img, s, header);
839 } else if (img.depth() >= 24) {
840 ok = writeImage24(img, s, header);
841 }
842
843 return ok;
844}
845
846bool PCXHandler::supportsOption(ImageOption option) const
847{
848 if (option == QImageIOHandler::Size) {
849 return true;
850 }
851 if (option == QImageIOHandler::ImageFormat) {
852 return true;
853 }
854 return false;
855}
856
857QVariant PCXHandler::option(ImageOption option) const
858{
859 QVariant v;
860
861 if (option == QImageIOHandler::Size) {
862 auto&& header = d->m_header;
863 if (header.isSupported()) {
864 v = QVariant::fromValue(QSize(header.width(), header.height()));
865 } else if (auto dev = device()) {
866 if (peekHeader(dev, header) && header.isSupported()) {
867 v = QVariant::fromValue(QSize(header.width(), header.height()));
868 }
869 }
870 }
871
872 if (option == QImageIOHandler::ImageFormat) {
873 auto&& header = d->m_header;
874 if (header.isSupported()) {
875 v = QVariant::fromValue(header.format());
876 } else if (auto dev = device()) {
877 if (peekHeader(dev, header) && header.isSupported()) {
878 v = QVariant::fromValue(header.format());
879 }
880 }
881 }
882
883 return v;
884}
885
886bool PCXHandler::canRead(QIODevice *device)
887{
888 if (!device) {
889 qWarning("PCXHandler::canRead() called with no device");
890 return false;
891 }
892
893 PCXHEADER header;
894 if (!peekHeader(device, header)) {
895 return false;
896 }
897 return header.isSupported();
898}
899
900QImageIOPlugin::Capabilities PCXPlugin::capabilities(QIODevice *device, const QByteArray &format) const
901{
902 if (format == "pcx") {
903 return Capabilities(CanRead | CanWrite);
904 }
905 if (!format.isEmpty()) {
906 return {};
907 }
908 if (!device->isOpen()) {
909 return {};
910 }
911
912 Capabilities cap;
913 if (device->isReadable() && PCXHandler::canRead(device)) {
914 cap |= CanRead;
915 }
916 if (device->isWritable()) {
917 cap |= CanWrite;
918 }
919 return cap;
920}
921
922QImageIOHandler *PCXPlugin::create(QIODevice *device, const QByteArray &format) const
923{
924 QImageIOHandler *handler = new PCXHandler;
925 handler->setDevice(device);
926 handler->setFormat(format);
927 return handler;
928}
929
930#include "moc_pcx_p.cpp"
KCALENDARCORE_EXPORT QDataStream & operator>>(QDataStream &in, const KCalendarCore::Alarm::Ptr &)
QFlags< Capability > Capabilities
KTEXTEDITOR_EXPORT QDebug operator<<(QDebug s, const MovingCursor &cursor)
QByteArray & fill(char ch, qsizetype size)
bool isEmpty() const const
void resize(qsizetype newSize, char c)
qsizetype size() const const
bool atEnd() const const
QIODevice * device() const const
void setByteOrder(ByteOrder bo)
Status status() const const
qsizetype bytesPerLine() const const
QRgb color(int i) const const
int colorCount() const const
QImage convertToFormat(Format format, Qt::ImageConversionFlags flags) &&
int depth() const const
int dotsPerMeterX() const const
int dotsPerMeterY() const const
Format format() const const
int height() const const
bool isNull() const const
uchar * scanLine(int i)
void setColor(int index, QRgb colorValue)
void setColorCount(int colorCount)
void setDotsPerMeterX(int x)
void setDotsPerMeterY(int y)
int width() const const
void setDevice(QIODevice *device)
void setFormat(const QByteArray &format)
bool isOpen() const const
bool isReadable() const const
bool isWritable() const const
QByteArray peek(qint64 maxSize)
virtual qint64 size() const const
QVariant fromValue(T &&value)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri Oct 11 2024 12:15:45 by doxygen 1.12.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.