1/*
2 This file is part of the KDE project
3 SPDX-FileCopyrightText: 2025-2026 Mirco Miranda <mircomir@outlook.com>
4
5 SPDX-License-Identifier: LGPL-2.0-or-later
6*/
7
8/*
9 * Format specifications:
10 * - https://wiki.amigaos.net/wiki/IFF_FORM_and_Chunk_Registry
11 * - https://www.fileformat.info/format/iff/egff.htm
12 * - https://download.autodesk.com/us/maya/2010help/index.html (Developer resources -> File formats -> Maya IFF)
13 * - https://aminet.net/package/dev/misc/IFF-RGFX
14 */
15
16#ifndef KIMG_CHUNKS_P_H
17#define KIMG_CHUNKS_P_H
18
19#include <QByteArray>
20#include <QDateTime>
21#include <QHash>
22#include <QImage>
23#include <QIODevice>
24#include <QLoggingCategory>
25#include <QPoint>
26#include <QSize>
27#include <QSharedPointer>
28
29#include "microexif_p.h"
30
31Q_DECLARE_LOGGING_CATEGORY(LOG_IFFPLUGIN)
32
33// Main chunks (Standard)
34#define CAT__CHUNK QByteArray("CAT ")
35#define FILL_CHUNK QByteArray(" ")
36#define FORM_CHUNK QByteArray("FORM")
37#define LIST_CHUNK QByteArray("LIST")
38#define PROP_CHUNK QByteArray("PROP")
39
40// Main chunks (Maya)
41#define CAT4_CHUNK QByteArray("CAT4") // 4 byte alignment
42#define FOR4_CHUNK QByteArray("FOR4")
43#define LIS4_CHUNK QByteArray("LIS4")
44#define PRO4_CHUNK QByteArray("PRO4")
45
46#define CAT8_CHUNK QByteArray("CAT8") // 8 byte alignment (never seen)
47#define FOR8_CHUNK QByteArray("FOR8")
48#define LIS8_CHUNK QByteArray("LIS8")
49#define PRO8_CHUNK QByteArray("PRO8")
50
51// FORM ILBM IFF
52#define ABIT_CHUNK QByteArray("ABIT")
53#define BMHD_CHUNK QByteArray("BMHD")
54#define BODY_CHUNK QByteArray("BODY")
55#define CAMG_CHUNK QByteArray("CAMG")
56#define CMAP_CHUNK QByteArray("CMAP")
57#define CMYK_CHUNK QByteArray("CMYK") // https://wiki.amigaos.net/wiki/ILBM_IFF_Interleaved_Bitmap#ILBM.CMYK
58#define DPI__CHUNK QByteArray("DPI ")
59#define IDAT_CHUNK QByteArray("IDAT")
60#define IHDR_CHUNK QByteArray("IHDR")
61#define IPAR_CHUNK QByteArray("IPAR")
62#define PLTE_CHUNK QByteArray("PLTE")
63#define RBOD_CHUNK QByteArray("RBOD")
64#define RCOL_CHUNK QByteArray("RCOL")
65#define RFLG_CHUNK QByteArray("RFLG")
66#define RGHD_CHUNK QByteArray("RGHD")
67#define RSCM_CHUNK QByteArray("RSCM")
68#define XBMI_CHUNK QByteArray("XBMI")
69#define YUVS_CHUNK QByteArray("YUVS")
70
71// Different palette for scanline
72#define BEAM_CHUNK QByteArray("BEAM")
73#define CTBL_CHUNK QByteArray("CTBL") // same as BEAM
74#define PCHG_CHUNK QByteArray("PCHG") // encoded in a unknown way (to be investigated)
75#define RAST_CHUNK QByteArray("RAST") // Atari ST(E)
76#define SHAM_CHUNK QByteArray("SHAM")
77
78// FOR4 CIMG IFF (Maya)
79#define RGBA_CHUNK QByteArray("RGBA")
80#define TBHD_CHUNK QByteArray("TBHD")
81
82// FORx IFF (found on some IFF format specs)
83#define ANNO_CHUNK QByteArray("ANNO")
84#define AUTH_CHUNK QByteArray("AUTH")
85#define COPY_CHUNK QByteArray("(c) ")
86#define DATE_CHUNK QByteArray("DATE")
87#define EXIF_CHUNK QByteArray("EXIF") // https://aminet.net/package/docs/misc/IFF-metadata
88#define ICCN_CHUNK QByteArray("ICCN") // https://aminet.net/package/docs/misc/IFF-metadata
89#define ICCP_CHUNK QByteArray("ICCP") // https://aminet.net/package/docs/misc/IFF-metadata
90#define FVER_CHUNK QByteArray("FVER")
91#define HIST_CHUNK QByteArray("HIST")
92#define NAME_CHUNK QByteArray("NAME")
93#define VDAT_CHUNK QByteArray("VDAT")
94#define VERS_CHUNK QByteArray("VERS")
95#define XMP0_CHUNK QByteArray("XMP0") // https://aminet.net/package/docs/misc/IFF-metadata
96
97// FORM types
98#define ACBM_FORM_TYPE QByteArray("ACBM")
99#define ILBM_FORM_TYPE QByteArray("ILBM")
100#define IMAG_FORM_TYPE QByteArray("IMAG")
101#define PBM__FORM_TYPE QByteArray("PBM ")
102#define RGB8_FORM_TYPE QByteArray("RGB8")
103#define RGBN_FORM_TYPE QByteArray("RGBN")
104#define RGFX_FORM_TYPE QByteArray("RGFX")
105
106#define CIMG_FOR4_TYPE QByteArray("CIMG")
107#define TBMP_FOR4_TYPE QByteArray("TBMP")
108
109#define CHUNKID_DEFINE(a) static QByteArray defaultChunkId() { return a; }
110
111// The 8-bit RGB format must be consistent. If you change it here, you have also to use the same
112// when converting an image with BEAM/CTBL/SHAM chunks otherwise the option(QImageIOHandler::ImageFormat)
113// could returns a wrong value.
114// Warning: Changing it requires changing the algorithms. Se, don't touch! :)
115#define FORMAT_RGB_8BIT QImage::Format_RGB888 // default one
116
117#define FORMAT_RGBA_8BIT QImage::Format_RGBA8888 // used by PCHG chunk
118
119/*!
120 * \brief The IFFChunk class
121 */
122class IFFChunk
123{
124 friend class IFFHandlerPrivate;
125public:
126 using ChunkList = QList<QSharedPointer<IFFChunk>>;
127
128 virtual ~IFFChunk();
129
130 /*!
131 * \brief IFFChunk
132 * Creates invalid chunk.
133 * \sa isValid
134 */
135 IFFChunk();
136
137 IFFChunk(const IFFChunk& other) = default;
138 IFFChunk& operator =(const IFFChunk& other) = default;
139
140 bool operator ==(const IFFChunk& other) const;
141
142 /*!
143 * \brief isValid
144 * \return True if the chunk is valid, otherwise false.
145 * \note The default implementation checks that chunkId() contains only valid characters.
146 */
147 virtual bool isValid() const;
148
149 /*!
150 * \brief alignBytes
151 * \return The chunk alignment bytes. By default returns bytes set using setAlignBytes().
152 */
153 virtual qint32 alignBytes() const;
154
155 /*!
156 * \brief chunkId
157 * \return The chunk Id of this chunk.
158 */
159 QByteArray chunkId() const;
160
161 /*!
162 * \brief bytes
163 * \return The size (in bytes) of the chunk data.
164 */
165
166 quint32 bytes() const;
167
168 /*!
169 * \brief data
170 * \return The data stored inside the class. If no data present, use readRawData().
171 * \sa readRawData
172 */
173 const QByteArray& data() const;
174
175 /*!
176 * \brief chunks
177 * \return The chunks inside this chunk.
178 */
179 const ChunkList& chunks() const;
180
181 /*!
182 * \brief chunkVersion
183 * \param cid Chunk Id to extract the version from.
184 * \return The version of the chunk. Zero means no valid chunk data.
185 */
186 static quint8 chunkVersion(const QByteArray& cid);
187
188 /*!
189 * \brief isChunkType
190 * Check if the chunkId is of type of cid (any version).
191 * \param cid Chunk Id to check.
192 * \return True on success, otherwise false.
193 */
194 bool isChunkType(const QByteArray& cid) const;
195
196 /*!
197 * \brief readInfo
198 * Reads chunkID, size and set the data position.
199 * \param d The device.
200 * \return True on success, otherwise false.
201 */
202 bool readInfo(QIODevice *d);
203
204 /*!
205 * \brief readStructure
206 * Read the internal structure using innerReadStructure() of the Chunk and set device the position to the next chunks.
207 * \param d The device.
208 * \return True on success, otherwise false.
209 */
210 bool readStructure(QIODevice *d);
211
212 /*!
213 * \brief readRawData
214 * \param d The device.
215 * \param relPos The position to read relative to the chunk position.
216 * \param size The size of the data to read (-1 means all chunk).
217 * \return The data read or empty array on error.
218 * \note Ignores any data already read and available with data().
219 * \sa data
220 */
221 QByteArray readRawData(QIODevice *d, qint64 relPos = 0, qint64 size = -1) const;
222
223 /*!
224 * \brief seek
225 * \param d The device.
226 * \param relPos The position to read relative to the chunk position.
227 * \return True on success, otherwise false.
228 */
229 bool seek(QIODevice *d, qint64 relPos = 0) const;
230
231 /*!
232 * \brief fromDevice
233 * \param d The device.
234 * \param ok Set to false if errors occurred.
235 * \return The chunk list found.
236 */
237 static ChunkList fromDevice(QIODevice *d, bool *ok = nullptr);
238
239 /*!
240 * \brief search
241 * Search for a chunk in the list of chunks.
242 * \param cid The chunkId to search.
243 * \param chunks The list of chunks to search for the requested chunk.
244 * \return The list of chunks with the given chunkId.
245 */
246 static ChunkList search(const QByteArray &cid, const ChunkList& chunks);
247
248 /*!
249 * \brief search
250 */
251 static ChunkList search(const QByteArray &cid, const QSharedPointer<IFFChunk>& chunk);
252
253 /*!
254 * \brief searchT
255 * Convenient search function to avoid casts.
256 * \param chunk The chunk to search for the requested chunk type.
257 * \return The list of chunks of T type.
258 */
259 template <class T>
260 static QList<const T*> searchT(const IFFChunk *chunk) {
261 QList<const T*> list;
262 if (chunk == nullptr) {
263 return list;
264 }
265 auto cid = T::defaultChunkId();
266 if (chunk->chunkId() == cid) {
267 if (auto c = dynamic_cast<const T*>(chunk))
268 list << c;
269 }
270 auto tmp = chunk->chunks();
271 for (auto &&c : tmp) {
272 list << searchT<T>(c.data());
273 }
274 return list;
275 }
276
277 /*!
278 * \brief searchT
279 * Convenient search function to avoid casts.
280 * \param chunks The list of chunks to search for the requested chunk.
281 * \return The list of chunks of T type.
282 */
283 template <class T>
284 static QList<const T*> searchT(const ChunkList& chunks) {
285 QList<const T*> list;
286 for (auto &&chunk : chunks) {
287 list << searchT<T>(chunk.data());
288 }
289 return list;
290 }
291
292 CHUNKID_DEFINE(QByteArray())
293
294protected:
295 /*!
296 * \brief innerReadStructure
297 * Reads data structure. Default implementation does nothing.
298 * \param d The device.
299 * \return True on success, otherwise false.
300 */
301 virtual bool innerReadStructure(QIODevice *d);
302
303 /*!
304 * \brief setAlignBytes
305 * \param bytes
306 */
307 void setAlignBytes(qint32 bytes);
308
309 /*!
310 * \brief nextChunkPos
311 * Calculates the position of the next chunk. The position is already aligned.
312 * \return The position of the next chunk from the beginning of the stream.
313 */
314 qint64 nextChunkPos() const;
315
316 /*!
317 * \brief cacheData
318 * Read all chunk data and store it on _data.
319 * \return True on success, otherwise false.
320 * \warning This function does not load anything if the chunk size is larger than 8MiB. For larger chunks, use direct data access.
321 */
322 bool cacheData(QIODevice *d);
323
324 /*!
325 * \brief setChunks
326 * \param chunks
327 */
328 void setChunks(const ChunkList &chunks);
329
330 /*!
331 * \brief recursionCounter
332 * Protection against stack overflow due to broken data.
333 * \return The current recursion counter.
334 */
335 qint32 recursionCounter() const;
336 void setRecursionCounter(qint32 cnt);
337
338 inline quint16 ui16(quint8 c1, quint8 c2) const {
339 return (quint16(c2) << 8) | quint16(c1);
340 }
341 inline quint16 ui16(const QByteArray &data, qint32 pos) const {
342 return ui16(c1: data.at(i: pos + 1), c2: data.at(i: pos));
343 }
344
345 inline qint16 i16(quint8 c1, quint8 c2) const {
346 return qint32(ui16(c1, c2));
347 }
348 inline qint16 i16(const QByteArray &data, qint32 pos) const {
349 return i16(c1: data.at(i: pos + 1), c2: data.at(i: pos));
350 }
351
352 inline quint32 ui32(quint8 c1, quint8 c2, quint8 c3, quint8 c4) const {
353 return (quint32(c4) << 24) | (quint32(c3) << 16) | (quint32(c2) << 8) | quint32(c1);
354 }
355 inline quint32 ui32(const QByteArray &data, qint32 pos) const {
356 return ui32(c1: data.at(i: pos + 3), c2: data.at(i: pos + 2), c3: data.at(i: pos + 1), c4: data.at(i: pos));
357 }
358
359 inline qint32 i32(quint8 c1, quint8 c2, quint8 c3, quint8 c4) const {
360 return qint32(ui32(c1, c2, c3, c4));
361 }
362 inline qint32 i32(const QByteArray &data, qint32 pos) const {
363 return i32(c1: data.at(i: pos + 3), c2: data.at(i: pos + 2), c3: data.at(i: pos + 1), c4: data.at(i: pos));
364 }
365
366 static ChunkList innerFromDevice(QIODevice *d, bool *ok, IFFChunk *parent = nullptr);
367
368 /*!
369 * \brief dataBytes
370 * \return Maximum usable cache data size.
371 */
372 quint32 dataBytes() const;
373
374private:
375 char _chunkId[4];
376
377 quint32 _size;
378
379 qint32 _align;
380
381 qint64 _dataPos;
382
383 QByteArray _data;
384
385 ChunkList _chunks;
386
387 qint32 _recursionCnt;
388};
389
390/*!
391 * \brief The IPALChunk class
392 * Interface for additional per-line palette.
393 */
394class IPALChunk : public IFFChunk
395{
396public:
397 virtual ~IPALChunk() override {}
398 IPALChunk() : IFFChunk() {}
399 IPALChunk(const IPALChunk& other) = default;
400 IPALChunk& operator =(const IPALChunk& other) = default;
401
402 /*!
403 * \brief hasAlpha
404 * \return True it the palette supports the alpha channel.
405 */
406 virtual bool hasAlpha() const { return false; }
407
408 /*!
409 * \brief clone
410 * \return A new instance of the class with all data.
411 */
412 virtual IPALChunk *clone() const = 0;
413
414 /*!
415 * \brief palette
416 * \param y The scanline.
417 * \return The modified palette.
418 */
419 virtual QList<QRgb> palette(qint32 y) const = 0;
420
421 /*!
422 * \brief initialize
423 * Initialize the palette changer.
424 * \param cmapPalette The palette as stored in the CMAP chunk.
425 * \param height The image height.
426 * \return True on success, otherwise false.
427 */
428 virtual bool initialize(const QList<QRgb>& cmapPalette, qint32 height) = 0;
429};
430
431
432/*!
433 * \brief The BMHDChunk class
434 * Bitmap Header
435 */
436class BMHDChunk: public IFFChunk
437{
438public:
439 enum Compression {
440 Uncompressed = 0, /**< Image data are uncompressed. */
441 Rle = 1, /**< Image data are RLE compressed. */
442 Vdat = 2, /**< Image data are VDAT compressed. */
443 RgbN8 = 4 /**< Image data are RGB8/RGBN compressed. */
444 };
445 enum Masking {
446 None = 0, /**< Designates an opaque rectangular image. */
447 HasMask = 1, /**< A "mask" is an optional "plane" of data the same size (w, h) as a bitplane.
448 It tells how to "cut out" part of the image when painting it onto another
449 image. "One" bits in the mask mean "copy the corresponding pixel to the
450 destination". "Zero" mask bits mean "leave this destination pixel alone". In
451 other words, "zero" bits designate transparent pixels.
452 The rows of the different bitplanes and mask are interleaved in the file.
453 This localizes all the information pertinent to each scan line. It
454 makes it much easier to transform the data while reading it to adjust the
455 image size or depth. It also makes it possible to scroll a big image by
456 swapping rows directly from the file without the need for random-access to
457 all the bitplanes. */
458 HasTransparentColor = 2, /**< Pixels in the source planes matching transparentColor
459 are to be considered “transparent”. (Actually, transparentColor
460 isn’t a “color number” since it’s matched with numbers formed
461 by the source bitmap rather than the possibly deeper destination
462 bitmap. Note that having a transparent color implies ignoring
463 one of the color registers. */
464 Lasso = 3 /**< The reader may construct a mask by lassoing the image as in MacPaint.
465 To do this, put a 1 pixel border of transparentColor around the image rectangle.
466 Then do a seed fill from this border. Filled pixels are to be transparent. */
467 };
468
469 virtual ~BMHDChunk() override;
470
471 BMHDChunk();
472 BMHDChunk(const BMHDChunk& other) = default;
473 BMHDChunk& operator =(const BMHDChunk& other) = default;
474
475 virtual bool isValid() const override;
476
477 /*!
478 * \brief width
479 * \return Width of the bitmap in pixels.
480 */
481 qint32 width() const;
482
483 /*!
484 * \brief height
485 * \return Height of the bitmap in pixels.
486 */
487 qint32 height() const;
488
489 /*!
490 * \brief size
491 * \return Size in pixels.
492 */
493 QSize size() const;
494
495 /*!
496 * \brief left
497 * \return The left position of the image.
498 */
499 qint32 left() const;
500
501 /*!
502 * \brief top
503 * \return The top position of the image.
504 */
505 qint32 top() const;
506
507 /*!
508 * \brief bitplanes
509 * \return The number of bit planes.
510 */
511 quint8 bitplanes() const;
512
513 /*!
514 * \brief masking
515 * \return Kind of masking is to be used for this image.
516 */
517 Masking masking() const;
518
519 /*!
520 * \brief compression
521 * \return The type of compression used.
522 */
523 Compression compression() const;
524
525 /*!
526 * \brief transparency
527 * \return Transparent "color number".
528 */
529 qint16 transparency() const;
530
531 /*!
532 * \brief xAspectRatio
533 * \return X pixel aspect.
534 */
535 quint8 xAspectRatio() const;
536
537 /*!
538 * \brief yAspectRatio
539 * \return Y pixel aspect.
540 */
541 quint8 yAspectRatio() const;
542
543 /*!
544 * \brief pageWidth
545 * \return Source "page" width in pixels.
546 */
547 quint16 pageWidth() const;
548
549 /*!
550 * \brief pageHeight
551 * \return Source "page" height in pixels.
552 */
553 quint16 pageHeight() const;
554
555 /*!
556 * \brief rowLen
557 * \return The row len of a plane.
558 */
559 quint32 rowLen() const;
560
561 CHUNKID_DEFINE(BMHD_CHUNK)
562
563protected:
564 virtual bool innerReadStructure(QIODevice *d) override;
565};
566
567/*!
568 * \brief The CMAPChunk class
569 */
570class CMAPChunk : public IFFChunk
571{
572public:
573 virtual ~CMAPChunk() override;
574 CMAPChunk();
575 CMAPChunk(const CMAPChunk& other) = default;
576 CMAPChunk& operator =(const CMAPChunk& other) = default;
577
578 virtual bool isValid() const override;
579
580 /*!
581 * \brief count
582 * \return The number of color in the palette.
583 */
584 virtual qint32 count() const;
585
586 /*!
587 * \brief palette
588 * \param halfbride When True, the new palette values are appended using the halfbride method.
589 * \return The color palette.
590 * \note If \a halfbride is true, the returned palette size is count() * 2.
591 */
592 QList<QRgb> palette(bool halfbride = false) const;
593
594 CHUNKID_DEFINE(CMAP_CHUNK)
595
596protected:
597 virtual QList<QRgb> innerPalette() const;
598
599 virtual bool innerReadStructure(QIODevice *d) override;
600};
601
602/*!
603 * \brief The CMYKChunk class
604 *
605 * This chunk would allow color specification in terms of Cyan,
606 * Magenta, Yellow, and Black as opposed to the current CMAP which uses RGB.
607 * The format would be the same as the CMAP chunk with the exception that this
608 * chunk uses four color components as opposed to three. The number of colors
609 * contained within would be chunk length/4. This chunk would be used in addition
610 * to the CMAP chunk.
611 */
612class CMYKChunk : public CMAPChunk
613{
614public:
615 virtual ~CMYKChunk() override;
616 CMYKChunk();
617 CMYKChunk(const CMYKChunk& other) = default;
618 CMYKChunk& operator =(const CMYKChunk& other) = default;
619
620 virtual bool isValid() const override;
621
622 /*!
623 * \brief count
624 * \return The number of color in the palette.
625 */
626 virtual qint32 count() const override;
627
628 CHUNKID_DEFINE(CMYK_CHUNK)
629
630protected:
631 /*!
632 * \brief palette
633 * \return The CMYK color palette converted to RGB one.
634 */
635 virtual QList<QRgb> innerPalette() const override;
636};
637
638/*!
639 * \brief The CAMGChunk class
640 */
641class CAMGChunk : public IFFChunk
642{
643public:
644 enum ModeId {
645 LoResLace = 0x0004,
646 HalfBrite = 0x0080,
647 LoResDpf = 0x0400,
648 Ham = 0x0800,
649 HiRes = 0x8000
650 };
651
652 Q_DECLARE_FLAGS(ModeIds, ModeId)
653
654 virtual ~CAMGChunk() override;
655 CAMGChunk();
656 CAMGChunk(const CAMGChunk& other) = default;
657 CAMGChunk& operator =(const CAMGChunk& other) = default;
658
659 virtual bool isValid() const override;
660
661 ModeIds modeId() const;
662
663 CHUNKID_DEFINE(CAMG_CHUNK)
664
665protected:
666 virtual bool innerReadStructure(QIODevice *d) override;
667};
668
669/*!
670 * \brief The DPIChunk class
671 */
672class DPIChunk : public IFFChunk
673{
674public:
675 virtual ~DPIChunk() override;
676 DPIChunk();
677 DPIChunk(const DPIChunk& other) = default;
678 DPIChunk& operator =(const DPIChunk& other) = default;
679
680 virtual bool isValid() const override;
681
682 /*!
683 * \brief dpiX
684 * \return The horizontal resolution in DPI.
685 */
686 virtual quint16 dpiX() const;
687
688 /*!
689 * \brief dpiY
690 * \return The vertical resolution in DPI.
691 */
692 virtual quint16 dpiY() const;
693
694 /*!
695 * \brief dotsPerMeterX
696 * \return X resolution as wanted by QImage.
697 */
698 qint32 dotsPerMeterX() const;
699
700 /*!
701 * \brief dotsPerMeterY
702 * \return Y resolution as wanted by QImage.
703 */
704 qint32 dotsPerMeterY() const;
705
706 CHUNKID_DEFINE(DPI__CHUNK)
707
708protected:
709 virtual bool innerReadStructure(QIODevice *d) override;
710};
711
712/*!
713 * \brief The XBMIChunk class
714 */
715class XBMIChunk : public DPIChunk
716{
717public:
718 enum PictureType : quint16 {
719 Indexed = 0,
720 Grayscale = 1,
721 Rgb = 2,
722 RgbA = 3,
723 Cmyk = 4,
724 CmykA = 5,
725 Bitmap = 6
726 };
727
728 virtual ~XBMIChunk() override;
729 XBMIChunk();
730 XBMIChunk(const XBMIChunk& other) = default;
731 XBMIChunk& operator =(const XBMIChunk& other) = default;
732
733 virtual bool isValid() const override;
734
735 /*!
736 * \brief dpiX
737 * \return The horizontal resolution in DPI.
738 */
739 virtual quint16 dpiX() const override;
740
741 /*!
742 * \brief dpiY
743 * \return The vertical resolution in DPI.
744 */
745 virtual quint16 dpiY() const override;
746
747 /*!
748 * \brief pictureType
749 * \return The picture type
750 */
751 PictureType pictureType() const;
752
753 CHUNKID_DEFINE(XBMI_CHUNK)
754};
755
756
757/*!
758 * \brief The BODYChunk class
759 */
760class BODYChunk : public IFFChunk
761{
762public:
763 virtual ~BODYChunk() override;
764 BODYChunk();
765 BODYChunk(const BODYChunk& other) = default;
766 BODYChunk& operator =(const BODYChunk& other) = default;
767
768 virtual bool isValid() const override;
769
770 CHUNKID_DEFINE(BODY_CHUNK)
771
772 /*!
773 * \brief readStride
774 * \param d The device.
775 * \param y The current scanline.
776 * \param header The bitmap header.
777 * \param camg The CAMG chunk (optional)
778 * \param cmap The CMAP chunk (optional)
779 * \param ipal The per-line palette chunk (optional)
780 * \param formType The type of the current form chunk.
781 * \return The scanline as requested for QImage.
782 * \warning Call resetStrideRead() once before this one.
783 */
784 virtual QByteArray strideRead(QIODevice *d,
785 qint32 y,
786 const BMHDChunk *header,
787 const CAMGChunk *camg = nullptr,
788 const CMAPChunk *cmap = nullptr,
789 const IPALChunk *ipal = nullptr,
790 const QByteArray& formType = ILBM_FORM_TYPE) const;
791
792 /*!
793 * \brief resetStrideRead
794 * Reset the stride read set the position at the beginning of the data and reset all buffers.
795 * \param d The device.
796 * \return True on success, otherwise false.
797 * \sa strideRead
798 * \note Must be called once before strideRead().
799 */
800 virtual bool resetStrideRead(QIODevice *d) const;
801
802 /*!
803 * \brief safeModeId
804 * \param header The header.
805 * \param camg The CAMG chunk.
806 * \param cmap The CMAP chunk.
807 * \return The most likely ModeId if not explicitly specified.
808 */
809 static CAMGChunk::ModeIds safeModeId(const BMHDChunk *header, const CAMGChunk *camg, const CMAPChunk *cmap = nullptr);
810
811protected:
812 /*!
813 * \brief strideSize
814 * \param formType The type of the current form chunk.
815 * \return The size of data to have to decode an image row.
816 */
817 quint32 strideSize(const BMHDChunk *header, const QByteArray& formType) const;
818
819 QByteArray deinterleave(const QByteArray &planes, qint32 y, const BMHDChunk *header, const CAMGChunk *camg = nullptr, const CMAPChunk *cmap = nullptr, const IPALChunk *ipal = nullptr) const;
820
821 QByteArray pbm(const QByteArray &planes, qint32 y, const BMHDChunk *header, const CAMGChunk *camg = nullptr, const CMAPChunk *cmap = nullptr, const IPALChunk *ipal = nullptr) const;
822
823 QByteArray rgb8(const QByteArray &planes, qint32 y, const BMHDChunk *header, const CAMGChunk *camg = nullptr, const CMAPChunk *cmap = nullptr, const IPALChunk *ipal = nullptr) const;
824
825 QByteArray rgbN(const QByteArray &planes, qint32 y, const BMHDChunk *header, const CAMGChunk *camg = nullptr, const CMAPChunk *cmap = nullptr, const IPALChunk *ipal = nullptr) const;
826
827 virtual bool innerReadStructure(QIODevice *d) override;
828
829private:
830 mutable QByteArray _readBuffer;
831};
832
833
834/*!
835 * \brief The ABITChunk class
836 */
837class ABITChunk : public BODYChunk
838{
839public:
840 virtual ~ABITChunk() override;
841 ABITChunk();
842 ABITChunk(const ABITChunk& other) = default;
843 ABITChunk& operator =(const ABITChunk& other) = default;
844
845 virtual bool isValid() const override;
846
847 CHUNKID_DEFINE(ABIT_CHUNK)
848
849 virtual QByteArray strideRead(QIODevice *d,
850 qint32 y,
851 const BMHDChunk *header,
852 const CAMGChunk *camg = nullptr,
853 const CMAPChunk *cmap = nullptr,
854 const IPALChunk *ipal = nullptr,
855 const QByteArray& formType = ACBM_FORM_TYPE) const override;
856
857 virtual bool resetStrideRead(QIODevice *d) const override;
858};
859
860/*!
861 * \brief The IFOR_Chunk class
862 * Interface for FORM chunks.
863 */
864class IFOR_Chunk : public IFFChunk
865{
866public:
867 virtual ~IFOR_Chunk() override;
868 IFOR_Chunk();
869
870 /*!
871 * \brief isSupported
872 * \return True if the form is supported by the plugin.
873 */
874 virtual bool isSupported() const = 0;
875
876 /*!
877 * \brief formType
878 * \return The type of image data contained in the form.
879 */
880 virtual QByteArray formType() const = 0;
881
882 /*!
883 * \brief format
884 * \return The Qt image format the form is converted to.
885 */
886 virtual QImage::Format format() const = 0;
887
888 /*!
889 * \brief transformation
890 * \return The image transformation.
891 * \note The Default implementation returns the transformation of EXIF chunk (if any).
892 */
893 virtual QImageIOHandler::Transformation transformation() const;
894
895 /*!
896 * \brief size
897 * \return The image size in pixels.
898 */
899 virtual QSize size() const = 0;
900
901 /*!
902 * \brief optionformat
903 * \return The format retuned by the plugin after all conversions.
904 */
905 QImage::Format optionformat() const;
906
907 /*!
908 * \brief searchIPal
909 * Search the palett per line chunk.
910 * \return The per line palette (BEAM, CTBL, SHAM, etc....).
911 */
912 const IPALChunk *searchIPal() const;
913};
914
915/*!
916 * \brief The FORMChunk class
917 */
918class FORMChunk : public IFOR_Chunk
919{
920 QByteArray _type;
921
922public:
923 virtual ~FORMChunk() override;
924 FORMChunk();
925 FORMChunk(const FORMChunk& other) = default;
926 FORMChunk& operator =(const FORMChunk& other) = default;
927
928 virtual bool isValid() const override;
929
930 virtual bool isSupported() const override;
931
932 virtual QByteArray formType() const override;
933
934 virtual QImage::Format format() const override;
935
936 virtual QSize size() const override;
937
938 CHUNKID_DEFINE(FORM_CHUNK)
939
940protected:
941 virtual bool innerReadStructure(QIODevice *d) override;
942
943private:
944 QImage::Format iffFormat() const;
945
946 QImage::Format cdiFormat() const;
947
948 QImage::Format rgfxFormat() const;
949};
950
951
952/*!
953 * \brief The FOR4Chunk class
954 */
955class FOR4Chunk : public IFOR_Chunk
956{
957 QByteArray _type;
958
959public:
960 virtual ~FOR4Chunk() override;
961 FOR4Chunk();
962 FOR4Chunk(const FOR4Chunk& other) = default;
963 FOR4Chunk& operator =(const FOR4Chunk& other) = default;
964
965 virtual bool isValid() const override;
966
967 virtual qint32 alignBytes() const override;
968
969 virtual bool isSupported() const override;
970
971 virtual QByteArray formType() const override;
972
973 virtual QImage::Format format() const override;
974
975 virtual QSize size() const override;
976
977 CHUNKID_DEFINE(FOR4_CHUNK)
978
979protected:
980 virtual bool innerReadStructure(QIODevice *d) override;
981};
982
983/*!
984 * \brief The CATChunk class
985 */
986class CATChunk : public IFFChunk
987{
988 QByteArray _type;
989
990public:
991 virtual ~CATChunk() override;
992 CATChunk();
993 CATChunk(const CATChunk& other) = default;
994 CATChunk& operator =(const CATChunk& other) = default;
995
996 virtual bool isValid() const override;
997
998 QByteArray catType() const;
999
1000 CHUNKID_DEFINE(CAT__CHUNK)
1001
1002protected:
1003 virtual bool innerReadStructure(QIODevice *d) override;
1004};
1005
1006/*!
1007 * \brief The TBHDChunk class
1008 */
1009class TBHDChunk : public IFFChunk
1010{
1011public:
1012 enum Flag {
1013 Rgb = 0x01, /**< RGB image */
1014 Alpha = 0x02, /**< Image contains alpha channel */
1015 ZBuffer = 0x04, /**< If the image has a z-buffer, it is described by ZBUF blocks with the same structure as the RGBA blocks, RLE encoded. */
1016
1017 RgbA = Rgb | Alpha /**< RGBA image */
1018 };
1019 Q_DECLARE_FLAGS(Flags, Flag)
1020
1021 enum Compression {
1022 Uncompressed = 0,
1023 Rle = 1
1024 };
1025
1026 virtual ~TBHDChunk() override;
1027
1028 TBHDChunk();
1029 TBHDChunk(const TBHDChunk& other) = default;
1030 TBHDChunk& operator =(const TBHDChunk& other) = default;
1031
1032 virtual bool isValid() const override;
1033
1034 virtual qint32 alignBytes() const override;
1035
1036 /*!
1037 * \brief width
1038 * \return Image width in pixels.
1039 */
1040 qint32 width() const;
1041
1042 /*!
1043 * \brief height
1044 * \return Image height in pixels.
1045 */
1046 qint32 height() const;
1047
1048 /*!
1049 * \brief size
1050 * \return Image size in pixels.
1051 */
1052 QSize size() const;
1053
1054 /*!
1055 * \brief left
1056 * \return
1057 */
1058 qint32 left() const;
1059
1060 /*!
1061 * \brief top
1062 * \return
1063 */
1064 qint32 top() const;
1065
1066 /*!
1067 * \brief flags
1068 * \return Image flags.
1069 */
1070 Flags flags() const;
1071
1072 /*!
1073 * \brief bpc
1074 * \return Byte per channel (1 or 2)
1075 */
1076 qint32 bpc() const;
1077
1078 /*!
1079 * \brief channels
1080 * \return
1081 */
1082 qint32 channels() const;
1083
1084 /*!
1085 * \brief tiles
1086 * \return The number of tiles of the image.
1087 */
1088 quint16 tiles() const;
1089
1090 /*!
1091 * \brief compression
1092 * \return The data compression.
1093 */
1094 Compression compression() const;
1095
1096 /*!
1097 * \brief format
1098 * \return
1099 */
1100 QImage::Format format() const;
1101
1102 CHUNKID_DEFINE(TBHD_CHUNK)
1103
1104protected:
1105 virtual bool innerReadStructure(QIODevice *d) override;
1106};
1107
1108/*!
1109 * \brief The RGBAChunk class
1110 */
1111class RGBAChunk : public IFFChunk
1112{
1113public:
1114 virtual ~RGBAChunk() override;
1115 RGBAChunk();
1116 RGBAChunk(const RGBAChunk& other) = default;
1117 RGBAChunk& operator =(const RGBAChunk& other) = default;
1118
1119 virtual bool isValid() const override;
1120
1121 virtual qint32 alignBytes() const override;
1122
1123 /*!
1124 * \brief isTileCompressed
1125 * \param header The image header.
1126 * \return True if the tile is compressed, otherwise false.
1127 */
1128 bool isTileCompressed(const TBHDChunk *header) const;
1129
1130 /*!
1131 * \brief pos
1132 * \return The tile position (top-left corner) in the final image.
1133 */
1134 QPoint pos() const;
1135
1136 /*!
1137 * \brief size
1138 * \return The tile size in pixels.
1139 */
1140 QSize size() const;
1141
1142 /*!
1143 * \brief tile
1144 * Create the tile by reading the data from the device.
1145 * \param d The device.
1146 * \param header The image header.
1147 * \return The image tile.
1148 */
1149 QImage tile(QIODevice *d, const TBHDChunk *header) const;
1150
1151 CHUNKID_DEFINE(RGBA_CHUNK)
1152
1153protected:
1154 virtual bool innerReadStructure(QIODevice *d) override;
1155
1156private:
1157 QImage compressedTile(QIODevice *d, const TBHDChunk *header) const;
1158
1159 QImage uncompressedTile(QIODevice *d, const TBHDChunk *header) const;
1160
1161 QByteArray readStride(QIODevice *d, const TBHDChunk *header) const;
1162
1163private:
1164 QPoint _posPx;
1165
1166 QSize _sizePx;
1167
1168 mutable QByteArray _readBuffer;
1169};
1170
1171/*!
1172 * \brief The ANNOChunk class
1173 */
1174class ANNOChunk : public IFFChunk
1175{
1176public:
1177 virtual ~ANNOChunk() override;
1178 ANNOChunk();
1179 ANNOChunk(const ANNOChunk& other) = default;
1180 ANNOChunk& operator =(const ANNOChunk& other) = default;
1181
1182 virtual bool isValid() const override;
1183
1184 QString value() const;
1185
1186 CHUNKID_DEFINE(ANNO_CHUNK)
1187
1188protected:
1189 virtual bool innerReadStructure(QIODevice *d) override;
1190};
1191
1192/*!
1193 * \brief The AUTHChunk class
1194 */
1195class AUTHChunk : public IFFChunk
1196{
1197public:
1198 virtual ~AUTHChunk() override;
1199 AUTHChunk();
1200 AUTHChunk(const AUTHChunk& other) = default;
1201 AUTHChunk& operator =(const AUTHChunk& other) = default;
1202
1203 virtual bool isValid() const override;
1204
1205 QString value() const;
1206
1207 CHUNKID_DEFINE(AUTH_CHUNK)
1208
1209protected:
1210 virtual bool innerReadStructure(QIODevice *d) override;
1211};
1212
1213/*!
1214 * \brief The COPYChunk class
1215 */
1216class COPYChunk : public IFFChunk
1217{
1218public:
1219 virtual ~COPYChunk() override;
1220 COPYChunk();
1221 COPYChunk(const COPYChunk& other) = default;
1222 COPYChunk& operator =(const COPYChunk& other) = default;
1223
1224 virtual bool isValid() const override;
1225
1226 QString value() const;
1227
1228 CHUNKID_DEFINE(COPY_CHUNK)
1229
1230protected:
1231 virtual bool innerReadStructure(QIODevice *d) override;
1232};
1233
1234/*!
1235 * \brief The DATEChunk class
1236 */
1237class DATEChunk : public IFFChunk
1238{
1239public:
1240 virtual ~DATEChunk() override;
1241 DATEChunk();
1242 DATEChunk(const DATEChunk& other) = default;
1243 DATEChunk& operator =(const DATEChunk& other) = default;
1244
1245 virtual bool isValid() const override;
1246
1247 QDateTime value() const;
1248
1249 CHUNKID_DEFINE(DATE_CHUNK)
1250
1251protected:
1252 virtual bool innerReadStructure(QIODevice *d) override;
1253};
1254
1255/*!
1256 * \brief The EXIFChunk class
1257 */
1258class EXIFChunk : public IFFChunk
1259{
1260public:
1261 virtual ~EXIFChunk() override;
1262 EXIFChunk();
1263 EXIFChunk(const EXIFChunk& other) = default;
1264 EXIFChunk& operator =(const EXIFChunk& other) = default;
1265
1266 virtual bool isValid() const override;
1267
1268 MicroExif value() const;
1269
1270 CHUNKID_DEFINE(EXIF_CHUNK)
1271
1272protected:
1273 virtual bool innerReadStructure(QIODevice *d) override;
1274};
1275
1276
1277/*!
1278 * \brief The NAMEChunk class
1279 */
1280class ICCNChunk : public IFFChunk
1281{
1282public:
1283 virtual ~ICCNChunk() override;
1284 ICCNChunk();
1285 ICCNChunk(const ICCNChunk& other) = default;
1286 ICCNChunk& operator =(const ICCNChunk& other) = default;
1287
1288 virtual bool isValid() const override;
1289
1290 QString value() const;
1291
1292 CHUNKID_DEFINE(ICCN_CHUNK)
1293
1294protected:
1295 virtual bool innerReadStructure(QIODevice *d) override;
1296};
1297
1298/*!
1299 * \brief The ICCPChunk class
1300 */
1301class ICCPChunk : public IFFChunk
1302{
1303public:
1304 virtual ~ICCPChunk() override;
1305 ICCPChunk();
1306 ICCPChunk(const ICCPChunk& other) = default;
1307 ICCPChunk& operator =(const ICCPChunk& other) = default;
1308
1309 virtual bool isValid() const override;
1310
1311 QColorSpace value() const;
1312
1313 CHUNKID_DEFINE(ICCP_CHUNK)
1314
1315protected:
1316 virtual bool innerReadStructure(QIODevice *d) override;
1317};
1318
1319
1320/*!
1321 * \brief The FVERChunk class
1322 *
1323 * \warning The specifications on wiki.amigaos.net differ from what I see in a file saved in Maya format. I do not interpret the data for now.
1324 */
1325class FVERChunk : public IFFChunk
1326{
1327public:
1328 virtual ~FVERChunk() override;
1329 FVERChunk();
1330 FVERChunk(const FVERChunk& other) = default;
1331 FVERChunk& operator =(const FVERChunk& other) = default;
1332
1333 virtual bool isValid() const override;
1334
1335 CHUNKID_DEFINE(FVER_CHUNK)
1336
1337protected:
1338 virtual bool innerReadStructure(QIODevice *d) override;
1339};
1340
1341
1342/*!
1343 * \brief The HISTChunk class
1344 */
1345class HISTChunk : public IFFChunk
1346{
1347public:
1348 virtual ~HISTChunk() override;
1349 HISTChunk();
1350 HISTChunk(const HISTChunk& other) = default;
1351 HISTChunk& operator =(const HISTChunk& other) = default;
1352
1353 virtual bool isValid() const override;
1354
1355 QString value() const;
1356
1357 CHUNKID_DEFINE(HIST_CHUNK)
1358
1359protected:
1360 virtual bool innerReadStructure(QIODevice *d) override;
1361};
1362
1363
1364/*!
1365 * \brief The NAMEChunk class
1366 */
1367class NAMEChunk : public IFFChunk
1368{
1369public:
1370 virtual ~NAMEChunk() override;
1371 NAMEChunk();
1372 NAMEChunk(const NAMEChunk& other) = default;
1373 NAMEChunk& operator =(const NAMEChunk& other) = default;
1374
1375 virtual bool isValid() const override;
1376
1377 QString value() const;
1378
1379 CHUNKID_DEFINE(NAME_CHUNK)
1380
1381protected:
1382 virtual bool innerReadStructure(QIODevice *d) override;
1383};
1384
1385
1386/*!
1387 * \brief The VDATChunk class
1388 */
1389class VDATChunk : public IFFChunk
1390{
1391public:
1392 virtual ~VDATChunk() override;
1393 VDATChunk();
1394 VDATChunk(const VDATChunk& other) = default;
1395 VDATChunk& operator =(const VDATChunk& other) = default;
1396
1397 virtual bool isValid() const override;
1398
1399 CHUNKID_DEFINE(VDAT_CHUNK)
1400
1401 const QByteArray &uncompressedData(const BMHDChunk *header) const;
1402
1403protected:
1404 virtual bool innerReadStructure(QIODevice *d) override;
1405
1406private:
1407 mutable QByteArray uncompressed;
1408};
1409
1410
1411/*!
1412 * \brief The VERSChunk class
1413 */
1414class VERSChunk : public IFFChunk
1415{
1416public:
1417 virtual ~VERSChunk() override;
1418 VERSChunk();
1419 VERSChunk(const VERSChunk& other) = default;
1420 VERSChunk& operator =(const VERSChunk& other) = default;
1421
1422 virtual bool isValid() const override;
1423
1424 QString value() const;
1425
1426 CHUNKID_DEFINE(VERS_CHUNK)
1427
1428protected:
1429 virtual bool innerReadStructure(QIODevice *d) override;
1430};
1431
1432
1433/*!
1434 * \brief The XMP0Chunk class
1435 */
1436class XMP0Chunk : public IFFChunk
1437{
1438public:
1439 virtual ~XMP0Chunk() override;
1440 XMP0Chunk();
1441 XMP0Chunk(const XMP0Chunk& other) = default;
1442 XMP0Chunk& operator =(const XMP0Chunk& other) = default;
1443
1444 virtual bool isValid() const override;
1445
1446 QString value() const;
1447
1448 CHUNKID_DEFINE(XMP0_CHUNK)
1449
1450protected:
1451 virtual bool innerReadStructure(QIODevice *d) override;
1452};
1453
1454/*!
1455 * *** I-CD IFF CHUNKS ***
1456 */
1457
1458/*!
1459 * \brief The IHDRChunk class
1460 * Image Header
1461 */
1462class IHDRChunk: public IFFChunk
1463{
1464public:
1465 enum Model {
1466 Invalid = 0, /**< Invalid model. */
1467 Rgb888 = 1, /**< red, green, blue - 8 bits per color. */
1468 Rgb555 = 2, /**< Green Book absolute RGB. */
1469 DYuv = 3, /**< Green Book Delta YUV. */
1470 CLut8 = 4, /**< Green Book 8 bit CLUT. */
1471 CLut7 = 5, /**< Green Book 7 bit CLUT. */
1472 CLut4 = 6, /**< Green Book 4 bit CLUT. */
1473 CLut3 = 7, /**< Green Book 3 bit CLUT. */
1474 Rle7 = 8, /**< Green Book runlength coded 7 bit CLUT. */
1475 Rle3 = 9, /**< Green Book runlength coded 3 bit CLUT. */
1476 PaletteOnly = 10 /**< color palette only. */
1477 };
1478
1479 enum DYuvKind {
1480 One = 0,
1481 Each = 1
1482 };
1483
1484 struct Yuv {
1485 Yuv(quint8 y0 = 0, quint8 u0 = 0, quint8 v0 = 0) : y(y0), u(u0), v(v0) {}
1486 quint8 y;
1487 quint8 u;
1488 quint8 v;
1489 };
1490
1491 virtual ~IHDRChunk() override;
1492
1493 IHDRChunk();
1494 IHDRChunk(const IHDRChunk& other) = default;
1495 IHDRChunk& operator =(const IHDRChunk& other) = default;
1496
1497 virtual bool isValid() const override;
1498
1499 /*!
1500 * \brief width
1501 * \return Width of the bitmap in pixels.
1502 */
1503 qint32 width() const;
1504
1505 /*!
1506 * \brief height
1507 * \return Height of the bitmap in pixels.
1508 */
1509 qint32 height() const;
1510
1511 /*!
1512 * \brief size
1513 * \return Size in pixels.
1514 */
1515 QSize size() const;
1516
1517 /*!
1518 * \brief lineSize
1519 * Physical width of image (number of bytes in each scan line, including any data required at
1520 * the end of each scan line for padding [see description of each model’s IDAT chunk for padding
1521 * rules]) This field is not used when model() = Rle7 or Rle3.
1522 * When model() = Rgb555, this field defines the size of one scan line of the upper
1523 * or lower portion of the pixel data, but not the size of them both together.
1524 */
1525 qint32 lineSize() const;
1526
1527 /*!
1528 * \brief model
1529 * Image model (coding method)
1530 */
1531 Model model() const;
1532
1533 /*!
1534 * \brief depth
1535 * Physical size of pixel (number of bits per pixel used in storing image data) When
1536 * model() = Rle7 or Rle3, this value only represents the size of a
1537 * single pixel; the size of a run of pixels is indeterminate.
1538 */
1539 quint16 depth() const;
1540
1541 /*!
1542 * \brief yuvKind
1543 * if model() = DYuv, indicates whether there is one DYUV start value for all
1544 * scan lines (in yuvStart()), or whether each scan line has its own start value in the
1545 * YUVS chunk which follows.
1546 */
1547 DYuvKind yuvKind() const;
1548
1549 /*!
1550 * \brief yuvStart
1551 * Start values for DYUV image if model() = DYuv and dYuvKind() = One
1552 */
1553 Yuv yuvStart() const;
1554
1555 CHUNKID_DEFINE(IHDR_CHUNK)
1556
1557protected:
1558 virtual bool innerReadStructure(QIODevice *d) override;
1559};
1560
1561
1562/*!
1563 * \brief The IHDRChunk class
1564 */
1565class IPARChunk: public IFFChunk
1566{
1567public:
1568 struct Rgb {
1569 Rgb(quint8 r0 = 0, quint8 g0 = 0, quint8 b0 = 0) : r(r0), g(g0), b(b0) {}
1570 quint8 r;
1571 quint8 g;
1572 quint8 b;
1573 };
1574
1575 virtual ~IPARChunk() override;
1576
1577 IPARChunk();
1578 IPARChunk(const IPARChunk& other) = default;
1579 IPARChunk& operator =(const IPARChunk& other) = default;
1580
1581 virtual bool isValid() const override;
1582
1583 /*!
1584 * \brief xOffset
1585 * X offset of origin in source image [0 < xOffset() < xPage()]
1586 */
1587 qint32 xOffset() const;
1588
1589 /*!
1590 * \brief yOffset
1591 * \returnX offset of origin in source image [0 < yOffset() < yPage()]
1592 */
1593 qint32 yOffset() const;
1594
1595 /*!
1596 * \brief aspectRatio
1597 * Aspect ratio of pixels in source image.
1598 */
1599 double aspectRatio() const;
1600
1601 /*!
1602 * \brief xPage
1603 * X size of source image.
1604 */
1605 qint32 xPage() const;
1606
1607 /*!
1608 * \brief yPage
1609 * Y size of source image.
1610 */
1611 qint32 yPage() const;
1612
1613 /*!
1614 * \brief xGrub
1615 * X location of hot spot within image.
1616 */
1617 qint32 xGrub() const;
1618
1619 /*!
1620 * \brief yGrub
1621 * Y location of hot spot within image.
1622 */
1623 qint32 yGrub() const;
1624
1625 /*!
1626 * \brief transparency
1627 * Transparent color.
1628 */
1629 Rgb transparency() const;
1630
1631 /*!
1632 * \brief mask
1633 * Mask color.
1634 */
1635 Rgb mask() const;
1636
1637 CHUNKID_DEFINE(IPAR_CHUNK)
1638
1639protected:
1640 virtual bool innerReadStructure(QIODevice *d) override;
1641};
1642
1643
1644/*!
1645 * \brief The PLTEChunk class
1646 */
1647class PLTEChunk : public CMAPChunk
1648{
1649public:
1650 virtual ~PLTEChunk() override;
1651 PLTEChunk();
1652 PLTEChunk(const PLTEChunk& other) = default;
1653 PLTEChunk& operator =(const PLTEChunk& other) = default;
1654
1655 virtual bool isValid() const override;
1656
1657 /*!
1658 * \brief count
1659 * \return The number of color in the palette.
1660 */
1661 virtual qint32 count() const override;
1662
1663 CHUNKID_DEFINE(PLTE_CHUNK)
1664
1665protected:
1666 qint32 offset() const;
1667
1668 qint32 total() const;
1669
1670 virtual QList<QRgb> innerPalette() const override;
1671};
1672
1673
1674/*!
1675 * \brief The YUVSChunk class
1676 */
1677class YUVSChunk : public IFFChunk
1678{
1679public:
1680 virtual ~YUVSChunk() override;
1681 YUVSChunk();
1682 YUVSChunk(const YUVSChunk& other) = default;
1683 YUVSChunk& operator =(const YUVSChunk& other) = default;
1684
1685 virtual bool isValid() const override;
1686
1687 qint32 count() const;
1688
1689 IHDRChunk::Yuv yuvStart(qint32 y) const;
1690
1691 CHUNKID_DEFINE(YUVS_CHUNK)
1692
1693protected:
1694 virtual bool innerReadStructure(QIODevice *d) override;
1695};
1696
1697
1698/*!
1699 * \brief The IDATChunk class
1700 */
1701class IDATChunk : public IFFChunk
1702{
1703public:
1704 virtual ~IDATChunk() override;
1705 IDATChunk();
1706 IDATChunk(const IDATChunk& other) = default;
1707 IDATChunk& operator =(const IDATChunk& other) = default;
1708
1709 virtual bool isValid() const override;
1710
1711 CHUNKID_DEFINE(IDAT_CHUNK)
1712
1713 /*!
1714 * \brief readStride
1715 * \param d The device.
1716 * \param y The current scanline.
1717 * \param header The bitmap header.
1718 * \param params The additional parameters (optional)
1719 * \return The scanline as requested for QImage.
1720 * \warning Call resetStrideRead() once before this one.
1721 */
1722 QByteArray strideRead(QIODevice *d,
1723 qint32 y,
1724 const IHDRChunk *header,
1725 const IPARChunk *params = nullptr,
1726 const YUVSChunk *yuvs = nullptr) const;
1727
1728 /*!
1729 * \brief resetStrideRead
1730 * Reset the stride read set the position at the beginning of the data and reset all buffers.
1731 * \param d The device.
1732 * \return True on success, otherwise false.
1733 * \sa strideRead
1734 * \note Must be called once before strideRead().
1735 */
1736 bool resetStrideRead(QIODevice *d) const;
1737
1738protected:
1739 quint32 strideSize(const IHDRChunk *header) const;
1740};
1741
1742
1743/*!
1744 * *** RGFX IFF CHUNKS ***
1745 */
1746
1747/*!
1748 * \brief The RGHDChunk class
1749 */
1750class RGHDChunk : public IFFChunk
1751{
1752public:
1753 enum Compression {
1754 Uncompressed = 0,
1755 Xpk = 1, /**< any XPK-packer */
1756 Zip = 2 /**< libzip (LZ77/ZIP) compression */
1757 };
1758
1759 enum BitmapType {
1760 Planar8 = 0x0000, /**< unaligned planar 8 bit bitmap */
1761 Chunky8 = 0x0001, /**< unaligned chunky 8 bit bitmap */
1762 Rgb24 = 0x0002, /**< 3-byte 24 bit RGB triples */
1763 Rgb32 = 0x0004, /**< 4-byte 32 bit ARGB quadruples */
1764 Rgb15 = 0x0010, /**< 2-byte 15 bit RGB (x+3x5 bit integer) */
1765 Rgb16 = 0x0020, /**< 2-byte 16 bit ARGB (1+3x5 bit integer) */
1766 Rgb48 = 0x0040, /**< 6-byte 48 bit RGB (3x 16 bit integer) */
1767 Rgb64 = 0x0080, /**< 8-byte 64 bit ARGB (4x 16 bit integer) */
1768 Rgb96 = 0x0100, /**< 12-byte 96 bit RGB (3x 32 bit float) */
1769 Rgb128 = 0x0200, /**< 16-byte 128 bit ARGB (4x 32 bit float) */
1770
1771 HasAlpha = (1 << 30), /**< set if A is meaningful */
1772 HasInvAlpha = (1 << 31) /**< set if A is meaningful but inversed (A = 255 - alpha) */
1773 };
1774 Q_DECLARE_FLAGS(BitmapTypes, BitmapType)
1775
1776 virtual ~RGHDChunk() override;
1777 RGHDChunk();
1778 RGHDChunk(const RGHDChunk&) = default;
1779 RGHDChunk& operator=(const RGHDChunk&) = default;
1780
1781 CHUNKID_DEFINE(RGHD_CHUNK)
1782
1783 virtual bool isValid() const override;
1784
1785 QSize size() const;
1786
1787 qint32 leftEdge() const;
1788
1789 qint32 topEdge() const;
1790
1791 qint32 width() const;
1792
1793 qint32 height() const;
1794
1795 qint32 pageWidth() const;
1796
1797 qint32 pageHeight() const;
1798
1799 quint32 depth() const;
1800
1801 quint32 pixelBits() const;
1802
1803 quint32 bytesPerLine() const;
1804
1805 Compression compression() const;
1806
1807 quint32 xAspect() const;
1808
1809 quint32 yAspect() const;
1810
1811 BitmapTypes bitmapType() const;
1812
1813 double aspectRatio() const;
1814
1815protected:
1816 virtual bool innerReadStructure(QIODevice *d) override;
1817};
1818
1819
1820/*!
1821 * \brief The RCOLChunk class
1822 */
1823class RCOLChunk : public CMAPChunk
1824{
1825public:
1826 virtual ~RCOLChunk() override;
1827 RCOLChunk();
1828 RCOLChunk(const RCOLChunk& other) = default;
1829 RCOLChunk& operator =(const RCOLChunk& other) = default;
1830
1831 virtual bool isValid() const override;
1832
1833 virtual qint32 count() const override;
1834
1835 CHUNKID_DEFINE(RCOL_CHUNK)
1836
1837protected:
1838 virtual QList<QRgb> innerPalette() const override;
1839};
1840
1841
1842/*!
1843 * \brief The RFLGChunk class
1844 */
1845class RFLGChunk : public IFFChunk
1846{
1847public:
1848 enum class Flag : quint32 {
1849 FromGray = 0x08, /**< created from 8/16 bit gray source so R==G==B */
1850 From8Bit = 0x10, /**< created from 8 bit source, so (R,G,B)&0xFF00 == ... & 0x00FF */
1851 From4Bit = 0x20, /**< created from 4 bit source, so (R,G,B)&0xF0 == ... & 0x0F */
1852 From8BitAlpha = 0x40, /**< 16/32 bit alpha created from 8 bit alpha source */
1853 From16BitAlpha = 0x80 /**< 32 bit alpha created from 16 bit alpha source */
1854 };
1855 Q_DECLARE_FLAGS(Flags, Flag)
1856
1857 virtual ~RFLGChunk() override;
1858 RFLGChunk();
1859 RFLGChunk(const RFLGChunk&) = default;
1860 RFLGChunk& operator=(const RFLGChunk&) = default;
1861
1862 CHUNKID_DEFINE(RFLG_CHUNK)
1863
1864 virtual bool isValid() const override;
1865
1866 Flags flags() const;
1867
1868protected:
1869 virtual bool innerReadStructure(QIODevice *d) override;
1870};
1871
1872
1873/*!
1874 * \brief The RSCMChunk class
1875 */
1876class RSCMChunk : public IFFChunk
1877{
1878public:
1879 virtual ~RSCMChunk() override;
1880 RSCMChunk();
1881 RSCMChunk(const RSCMChunk&) = default;
1882 RSCMChunk& operator=(const RSCMChunk&) = default;
1883
1884 CHUNKID_DEFINE(RSCM_CHUNK)
1885
1886 virtual bool isValid() const override;
1887
1888 /*!
1889 * \brief viewMode Default screenmode
1890 *
1891 * Since HAM modes only can be identified by their ID (or DIPF) you have to make sure,
1892 * that rcsm_ViewMode is OR'ed with HAM_KEY for these (same for EHB and EXTRAHALFBRITE_KEY).
1893 *
1894 * Specific RTG ViewModes will lose their meaning, as soon as graphics are transferred between
1895 * different systems, which is why the two LocalVM entries are considered obsolete.
1896 *
1897 * Always set the obsolete entries to 0xFFFFFFFF and avoid interpreting them.
1898 * \return default screenmode
1899 */
1900 quint32 viewMode() const;
1901
1902 /*!
1903 * \brief localVM0
1904 * \obsolete obsolete local RTG
1905 */
1906 quint32 localVM0() const;
1907
1908 /*!
1909 * \brief localVM1
1910 * \obsolete obsolete local RTG
1911 */
1912 quint32 localVM1() const;
1913
1914protected:
1915 virtual bool innerReadStructure(QIODevice *d) override;
1916};
1917
1918
1919/*!
1920 * \brief The RBODChunk class
1921 */
1922class RBODChunk : public IFFChunk
1923{
1924public:
1925 virtual ~RBODChunk() override;
1926 RBODChunk();
1927 RBODChunk(const RBODChunk&) = default;
1928 RBODChunk& operator=(const RBODChunk&) = default;
1929
1930 CHUNKID_DEFINE(RBOD_CHUNK)
1931
1932 virtual bool isValid() const override;
1933
1934 QByteArray strideRead(QIODevice *d,
1935 qint32 y,
1936 const RGHDChunk *header,
1937 const RSCMChunk *rcsm = nullptr,
1938 const RCOLChunk *rcol = nullptr) const;
1939
1940 bool resetStrideRead(QIODevice *d) const;
1941
1942private:
1943 QByteArray deinterleave(const QByteArray &planes, qint32 y, const RGHDChunk *header, const RSCMChunk *rcsm = nullptr, const RCOLChunk *rcol = nullptr) const;
1944
1945 quint32 strideSize(const RGHDChunk *header) const;
1946};
1947
1948
1949/*!
1950 * *** UNDOCUMENTED CHUNKS ***
1951 */
1952
1953/*!
1954 * \brief The BEAMChunk class
1955 */
1956class BEAMChunk : public IPALChunk
1957{
1958public:
1959 virtual ~BEAMChunk() override;
1960 BEAMChunk();
1961 BEAMChunk(const BEAMChunk& other) = default;
1962 BEAMChunk& operator =(const BEAMChunk& other) = default;
1963
1964 virtual bool isValid() const override;
1965
1966 virtual IPALChunk *clone() const override;
1967
1968 virtual QList<QRgb> palette(qint32 y) const override;
1969
1970 virtual bool initialize(const QList<QRgb>& cmapPalette, qint32 height) override;
1971
1972 CHUNKID_DEFINE(BEAM_CHUNK)
1973
1974protected:
1975 virtual bool innerReadStructure(QIODevice *d) override;
1976
1977private:
1978 qint32 _height;
1979};
1980
1981/*!
1982 * \brief The CTBLChunk class
1983 */
1984class CTBLChunk : public BEAMChunk
1985{
1986public:
1987 virtual ~CTBLChunk() override;
1988 CTBLChunk();
1989 CTBLChunk(const CTBLChunk& other) = default;
1990 CTBLChunk& operator =(const CTBLChunk& other) = default;
1991
1992 virtual bool isValid() const override;
1993
1994 CHUNKID_DEFINE(CTBL_CHUNK)
1995};
1996
1997/*!
1998 * \brief The SHAMChunk class
1999 */
2000class SHAMChunk : public IPALChunk
2001{
2002public:
2003 virtual ~SHAMChunk() override;
2004 SHAMChunk();
2005 SHAMChunk(const SHAMChunk& other) = default;
2006 SHAMChunk& operator =(const SHAMChunk& other) = default;
2007
2008 virtual bool isValid() const override;
2009
2010 virtual IPALChunk *clone() const override;
2011
2012 virtual QList<QRgb> palette(qint32 y) const override;
2013
2014 virtual bool initialize(const QList<QRgb>& cmapPalette, qint32 height) override;
2015
2016 CHUNKID_DEFINE(SHAM_CHUNK)
2017
2018protected:
2019 virtual bool innerReadStructure(QIODevice *d) override;
2020
2021private:
2022 qint32 _height;
2023};
2024
2025/*!
2026 * \brief The RASTChunk class
2027 * \note I found an Atari STE image with the RAST chunk outside
2028 * the form chunk (Fish.neo.iff). To support it the IFF parser
2029 * should be changed so, this kind of IFFs are shown wrong.
2030 */
2031class RASTChunk : public IPALChunk
2032{
2033public:
2034 virtual ~RASTChunk() override;
2035 RASTChunk();
2036 RASTChunk(const RASTChunk& other) = default;
2037 RASTChunk& operator =(const RASTChunk& other) = default;
2038
2039 virtual bool isValid() const override;
2040
2041 virtual IPALChunk *clone() const override;
2042
2043 virtual QList<QRgb> palette(qint32 y) const override;
2044
2045 virtual bool initialize(const QList<QRgb>& cmapPalette, qint32 height) override;
2046
2047 CHUNKID_DEFINE(RAST_CHUNK)
2048
2049protected:
2050 virtual bool innerReadStructure(QIODevice *d) override;
2051
2052private:
2053 qint32 _height;
2054};
2055
2056/*!
2057 * \brief The PCHGChunk class
2058 */
2059class PCHGChunk : public IPALChunk
2060{
2061public:
2062 enum Compression {
2063 Uncompressed,
2064 Huffman
2065 };
2066
2067 enum Flag {
2068 None = 0x00,
2069 F12Bit = 0x01,
2070 F32Bit = 0x02,
2071 UseAlpha = 0x04
2072 };
2073 Q_DECLARE_FLAGS(Flags, Flag)
2074
2075 virtual ~PCHGChunk() override;
2076 PCHGChunk();
2077 PCHGChunk(const PCHGChunk& other) = default;
2078 PCHGChunk& operator =(const PCHGChunk& other) = default;
2079
2080 Compression compression() const;
2081
2082 Flags flags() const;
2083
2084 qint16 startLine() const;
2085
2086 quint16 lineCount() const;
2087
2088 quint16 changedLines() const;
2089
2090 quint16 minReg() const;
2091
2092 quint16 maxReg() const;
2093
2094 quint16 maxChanges() const;
2095
2096 quint32 totalChanges() const;
2097
2098 virtual bool hasAlpha() const override;
2099
2100 virtual bool isValid() const override;
2101
2102 virtual IPALChunk *clone() const override;
2103
2104 virtual QList<QRgb> palette(qint32 y) const override;
2105
2106 virtual bool initialize(const QList<QRgb>& cmapPalette, qint32 height) override;
2107
2108 CHUNKID_DEFINE(PCHG_CHUNK)
2109
2110protected:
2111 virtual bool innerReadStructure(QIODevice *d) override;
2112
2113private:
2114 QHash<qint32, QHash<quint16, QRgb>> _paletteChanges;
2115
2116 QHash<qint32, QList<QRgb>> _palettes;
2117};
2118
2119#endif // KIMG_CHUNKS_P_H
2120

source code of kimageformats/src/imageformats/chunks_p.h