1/*
2 This file is part of the KDE project
3 SPDX-FileCopyrightText: 2025 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 */
14
15#ifndef KIMG_CHUNKS_P_H
16#define KIMG_CHUNKS_P_H
17
18#include <QByteArray>
19#include <QDateTime>
20#include <QImage>
21#include <QIODevice>
22#include <QLoggingCategory>
23#include <QPoint>
24#include <QSize>
25#include <QSharedPointer>
26
27#include "microexif_p.h"
28
29Q_DECLARE_LOGGING_CATEGORY(LOG_IFFPLUGIN)
30
31// Main chunks (Standard)
32#define CAT__CHUNK QByteArray("CAT ")
33#define FILL_CHUNK QByteArray(" ")
34#define FORM_CHUNK QByteArray("FORM")
35#define LIST_CHUNK QByteArray("LIST")
36#define PROP_CHUNK QByteArray("PROP")
37
38// Main chuncks (Maya)
39#define CAT4_CHUNK QByteArray("CAT4") // 4 byte alignment
40#define FOR4_CHUNK QByteArray("FOR4")
41#define LIS4_CHUNK QByteArray("LIS4")
42#define PRO4_CHUNK QByteArray("PRO4")
43
44#define CAT8_CHUNK QByteArray("CAT8") // 8 byte alignment (never seen)
45#define FOR8_CHUNK QByteArray("FOR8")
46#define LIS8_CHUNK QByteArray("LIS8")
47#define PRO8_CHUNK QByteArray("PRO8")
48
49// FORM ILBM IFF
50#define ABIT_CHUNK QByteArray("ABIT")
51#define BMHD_CHUNK QByteArray("BMHD")
52#define BODY_CHUNK QByteArray("BODY")
53#define CAMG_CHUNK QByteArray("CAMG")
54#define CMAP_CHUNK QByteArray("CMAP")
55#define CMYK_CHUNK QByteArray("CMYK") // https://wiki.amigaos.net/wiki/ILBM_IFF_Interleaved_Bitmap#ILBM.CMYK
56#define DPI__CHUNK QByteArray("DPI ")
57
58// Different palette for scanline
59#define BEAM_CHUNK QByteArray("BEAM")
60#define CTBL_CHUNK QByteArray("CTBL") // same as BEAM
61#define PCHG_CHUNK QByteArray("PCHG") // encoded in a unknown way (to be investigated)
62#define RAST_CHUNK QByteArray("RAST") // Atari ST(E)
63#define SHAM_CHUNK QByteArray("SHAM")
64
65// FOR4 CIMG IFF (Maya)
66#define RGBA_CHUNK QByteArray("RGBA")
67#define TBHD_CHUNK QByteArray("TBHD")
68
69// FORx IFF (found on some IFF format specs)
70#define ANNO_CHUNK QByteArray("ANNO")
71#define AUTH_CHUNK QByteArray("AUTH")
72#define COPY_CHUNK QByteArray("(c) ")
73#define DATE_CHUNK QByteArray("DATE")
74#define EXIF_CHUNK QByteArray("EXIF") // https://aminet.net/package/docs/misc/IFF-metadata
75#define ICCN_CHUNK QByteArray("ICCN") // https://aminet.net/package/docs/misc/IFF-metadata
76#define ICCP_CHUNK QByteArray("ICCP") // https://aminet.net/package/docs/misc/IFF-metadata
77#define FVER_CHUNK QByteArray("FVER")
78#define HIST_CHUNK QByteArray("HIST")
79#define NAME_CHUNK QByteArray("NAME")
80#define VERS_CHUNK QByteArray("VERS")
81#define XMP0_CHUNK QByteArray("XMP0") // https://aminet.net/package/docs/misc/IFF-metadata
82
83#define ACBM_FORM_TYPE QByteArray("ACBM")
84#define ILBM_FORM_TYPE QByteArray("ILBM")
85#define PBM__FORM_TYPE QByteArray("PBM ")
86#define RGB8_FORM_TYPE QByteArray("RGB8")
87#define RGBN_FORM_TYPE QByteArray("RGBN")
88
89#define CIMG_FOR4_TYPE QByteArray("CIMG")
90#define TBMP_FOR4_TYPE QByteArray("TBMP")
91
92#define CHUNKID_DEFINE(a) static QByteArray defaultChunkId() { return a; }
93
94// The 8-bit RGB format must be one. If you change it here, you have also to use the same
95// when converting an image with BEAM/CTBL/SHAM chunks otherwise the option(QImageIOHandler::ImageFormat)
96// could returns a wrong value.
97// Warning: Changing it requires changing the algorithms. Se, don't touch! :)
98#define FORMAT_RGB_8BIT QImage::Format_RGB888
99
100/*!
101 * \brief The IFFChunk class
102 */
103class IFFChunk
104{
105public:
106 using ChunkList = QList<QSharedPointer<IFFChunk>>;
107
108 virtual ~IFFChunk();
109
110 /*!
111 * \brief IFFChunk
112 * Creates invalid chunk.
113 * \sa isValid
114 */
115 IFFChunk();
116
117 IFFChunk(const IFFChunk& other) = default;
118 IFFChunk& operator =(const IFFChunk& other) = default;
119
120 bool operator ==(const IFFChunk& other) const;
121
122 /*!
123 * \brief isValid
124 * \return True if the chunk is valid, otherwise false.
125 * \note The default implementation checks that chunkId() contains only valid characters.
126 */
127 virtual bool isValid() const;
128
129 /*!
130 * \brief alignBytes
131 * \return The chunk alignment bytes. By default returns bytes set using setAlignBytes().
132 */
133 virtual qint32 alignBytes() const;
134
135 /*!
136 * \brief chunkId
137 * \return The chunk Id of this chunk.
138 */
139 QByteArray chunkId() const;
140
141 /*!
142 * \brief bytes
143 * \return The size (in bytes) of the chunck data.
144 */
145
146 quint32 bytes() const;
147
148 /*!
149 * \brief data
150 * \return The data stored inside the class. If no data present, use readRawData().
151 * \sa readRawData
152 */
153 const QByteArray& data() const;
154
155 /*!
156 * \brief chunks
157 * \return The chunks inside this chunk.
158 */
159 const ChunkList& chunks() const;
160
161 /*!
162 * \brief chunkVersion
163 * \param cid Chunk Id to extract the version from.
164 * \return The version of the chunk. Zero means no valid chunk data.
165 */
166 static quint8 chunkVersion(const QByteArray& cid);
167
168 /*!
169 * \brief isChunkType
170 * Check if the chunkId is of type of cid (any version).
171 * \param cid Chunk Id to check.
172 * \return True on success, otherwise false.
173 */
174 bool isChunkType(const QByteArray& cid) const;
175
176 /*!
177 * \brief readInfo
178 * Reads chunkID, size and set the data position.
179 * \param d The device.
180 * \return True on success, otherwise false.
181 */
182 bool readInfo(QIODevice *d);
183
184 /*!
185 * \brief readStructure
186 * Read the internal structure using innerReadStructure() of the Chunk and set device the position to the next chunks.
187 * \param d The device.
188 * \return True on success, otherwise false.
189 */
190 bool readStructure(QIODevice *d);
191
192 /*!
193 * \brief readRawData
194 * \param d The device.
195 * \param relPos The position to read relative to the chunk position.
196 * \param size The size of the data to read (-1 means all chunk).
197 * \return The data read or empty array on error.
198 * \note Ignores any data already read and available with data().
199 * \sa data
200 */
201 QByteArray readRawData(QIODevice *d, qint64 relPos = 0, qint64 size = -1) const;
202
203 /*!
204 * \brief seek
205 * \param d The device.
206 * \param relPos The position to read relative to the chunk position.
207 * \return True on success, otherwise false.
208 */
209 bool seek(QIODevice *d, qint64 relPos = 0) const;
210
211 /*!
212 * \brief fromDevice
213 * \param d The device.
214 * \param ok Set to false if errors occurred.
215 * \return The chunk list found.
216 */
217 static ChunkList fromDevice(QIODevice *d, bool *ok = nullptr);
218
219 /*!
220 * \brief search
221 * Search for a chunk in the list of chunks.
222 * \param cid The chunkId to search.
223 * \param chunks The list of chunks to search for the requested chunk.
224 * \return The list of chunks with the given chunkId.
225 */
226 static ChunkList search(const QByteArray &cid, const ChunkList& chunks);
227
228 /*!
229 * \brief search
230 */
231 static ChunkList search(const QByteArray &cid, const QSharedPointer<IFFChunk>& chunk);
232
233 /*!
234 * \brief searchT
235 * Convenient search function to avoid casts.
236 * \param chunk The chunk to search for the requested chunk type.
237 * \return The list of chunks of T type.
238 */
239 template <class T>
240 static QList<const T*> searchT(const IFFChunk *chunk) {
241 QList<const T*> list;
242 if (chunk == nullptr) {
243 return list;
244 }
245 auto cid = T::defaultChunkId();
246 if (chunk->chunkId() == cid) {
247 if (auto c = dynamic_cast<const T*>(chunk))
248 list << c;
249 }
250 auto tmp = chunk->chunks();
251 for (auto &&c : tmp) {
252 list << searchT<T>(c.data());
253 }
254 return list;
255 }
256
257 /*!
258 * \brief searchT
259 * Convenient search function to avoid casts.
260 * \param chunks The list of chunks to search for the requested chunk.
261 * \return The list of chunks of T type.
262 */
263 template <class T>
264 static QList<const T*> searchT(const ChunkList& chunks) {
265 QList<const T*> list;
266 for (auto &&chunk : chunks) {
267 list << searchT<T>(chunk.data());
268 }
269 return list;
270 }
271
272 CHUNKID_DEFINE(QByteArray())
273
274protected:
275 /*!
276 * \brief innerReadStructure
277 * Reads data structure. Default implementation does nothing.
278 * \param d The device.
279 * \return True on success, otherwise false.
280 */
281 virtual bool innerReadStructure(QIODevice *d);
282
283 /*!
284 * \brief setAlignBytes
285 * \param bytes
286 */
287 void setAlignBytes(qint32 bytes);
288
289 /*!
290 * \brief nextChunkPos
291 * Calculates the position of the next chunk. The position is already aligned.
292 * \return The position of the next chunk from the beginning of the stream.
293 */
294 qint64 nextChunkPos() const;
295
296 /*!
297 * \brief cacheData
298 * Read all chunk data and store it on _data.
299 * \return True on success, otherwise false.
300 * \warning This function does not load anything if the chunk size is larger than 8MiB. For larger chunks, use direct data access.
301 */
302 bool cacheData(QIODevice *d);
303
304 /*!
305 * \brief setChunks
306 * \param chunks
307 */
308 void setChunks(const ChunkList &chunks);
309
310 /*!
311 * \brief recursionCounter
312 * Protection against stack overflow due to broken data.
313 * \return The current recursion counter.
314 */
315 qint32 recursionCounter() const;
316 void setRecursionCounter(qint32 cnt);
317
318 inline quint16 ui16(quint8 c1, quint8 c2) const {
319 return (quint16(c2) << 8) | quint16(c1);
320 }
321
322 inline qint16 i16(quint8 c1, quint8 c2) const {
323 return qint32(ui16(c1, c2));
324 }
325
326 inline quint32 ui32(quint8 c1, quint8 c2, quint8 c3, quint8 c4) const {
327 return (quint32(c4) << 24) | (quint32(c3) << 16) | (quint32(c2) << 8) | quint32(c1);
328 }
329
330 inline qint32 i32(quint8 c1, quint8 c2, quint8 c3, quint8 c4) const {
331 return qint32(ui32(c1, c2, c3, c4));
332 }
333
334 static ChunkList innerFromDevice(QIODevice *d, bool *ok, IFFChunk *parent = nullptr);
335
336private:
337 char _chunkId[4];
338
339 quint32 _size;
340
341 qint32 _align;
342
343 qint64 _dataPos;
344
345 QByteArray _data;
346
347 ChunkList _chunks;
348
349 qint32 _recursionCnt;
350};
351
352/*!
353 * \brief The IPALChunk class
354 * Interface for additional per-line palette.
355 */
356class IPALChunk : public IFFChunk
357{
358public:
359 virtual ~IPALChunk() override {}
360 IPALChunk() : IFFChunk() {}
361 virtual QList<QRgb> palette(qint32 y, qint32 height) const = 0;
362};
363
364
365/*!
366 * \brief The BMHDChunk class
367 * Bitmap Header
368 */
369class BMHDChunk: public IFFChunk
370{
371public:
372 enum Compression {
373 Uncompressed = 0, /**< Image data are uncompressed. */
374 Rle = 1, /**< Image data are RLE compressed. */
375 RgbN8 = 4 /**< RGB8/RGBN compresson. */
376 };
377 enum Masking {
378 None = 0, /**< Designates an opaque rectangular image. */
379 HasMask = 1, /**< A mask plane is interleaved with the bitplanes in the BODY chunk. */
380 HasTransparentColor = 2, /**< Pixels in the source planes matching transparentColor
381 are to be considered “transparent”. (Actually, transparentColor
382 isn’t a “color number” since it’s matched with numbers formed
383 by the source bitmap rather than the possibly deeper destination
384 bitmap. Note that having a transparent color implies ignoring
385 one of the color registers. */
386 Lasso = 3 /**< The reader may construct a mask by lassoing the image as in MacPaint.
387 To do this, put a 1 pixel border of transparentColor around the image rectangle.
388 Then do a seed fill from this border. Filled pixels are to be transparent. */
389 };
390
391 virtual ~BMHDChunk() override;
392
393 BMHDChunk();
394 BMHDChunk(const BMHDChunk& other) = default;
395 BMHDChunk& operator =(const BMHDChunk& other) = default;
396
397 virtual bool isValid() const override;
398
399 /*!
400 * \brief width
401 * \return Width of the bitmap in pixels.
402 */
403 qint32 width() const;
404
405 /*!
406 * \brief height
407 * \return Height of the bitmap in pixels.
408 */
409 qint32 height() const;
410
411 /*!
412 * \brief size
413 * \return Size in pixels.
414 */
415 QSize size() const;
416
417 /*!
418 * \brief left
419 * \return The left position of the image.
420 */
421 qint32 left() const;
422
423 /*!
424 * \brief top
425 * \return The top position of the image.
426 */
427 qint32 top() const;
428
429 /*!
430 * \brief bitplanes
431 * \return The number of bit planes.
432 */
433 quint8 bitplanes() const;
434
435 /*!
436 * \brief masking
437 * \return Kind of masking is to be used for this image.
438 */
439 Masking masking() const;
440
441 /*!
442 * \brief compression
443 * \return The type of compression used.
444 */
445 Compression compression() const;
446
447 /*!
448 * \brief transparency
449 * \return Transparent "color number".
450 */
451 qint16 transparency() const;
452
453 /*!
454 * \brief xAspectRatio
455 * \return X pixel aspect.
456 */
457 quint8 xAspectRatio() const;
458
459 /*!
460 * \brief yAspectRatio
461 * \return Y pixel aspect.
462 */
463 quint8 yAspectRatio() const;
464
465 /*!
466 * \brief pageWidth
467 * \return Source "page" width in pixels.
468 */
469 quint16 pageWidth() const;
470
471 /*!
472 * \brief pageHeight
473 * \return Source "page" height in pixels.
474 */
475 quint16 pageHeight() const;
476
477 /*!
478 * \brief rowLen
479 * \return The row len of a plane.
480 */
481 quint32 rowLen() const;
482
483 CHUNKID_DEFINE(BMHD_CHUNK)
484
485protected:
486 virtual bool innerReadStructure(QIODevice *d) override;
487};
488
489/*!
490 * \brief The CMAPChunk class
491 */
492class CMAPChunk : public IFFChunk
493{
494public:
495 virtual ~CMAPChunk() override;
496 CMAPChunk();
497 CMAPChunk(const CMAPChunk& other) = default;
498 CMAPChunk& operator =(const CMAPChunk& other) = default;
499
500 virtual bool isValid() const override;
501
502 /*!
503 * \brief count
504 * \return The number of color in the palette.
505 */
506 virtual qint32 count() const;
507
508 /*!
509 * \brief palette
510 * \param halfbride When True, the new palette values are appended using the halfbride method.
511 * \return The color palette.
512 * \note If \a halfbride is true, the returned palette size is count() * 2.
513 */
514 QList<QRgb> palette(bool halfbride = false) const;
515
516 CHUNKID_DEFINE(CMAP_CHUNK)
517
518protected:
519 virtual QList<QRgb> innerPalette() const;
520
521 virtual bool innerReadStructure(QIODevice *d) override;
522};
523
524/*!
525 * \brief The CMYKChunk class
526 *
527 * This chunk would allow color specification in terms of Cyan,
528 * Magenta, Yellow, and Black as opposed to the current CMAP which uses RGB.
529 * The format would be the same as the CMAP chunk with the exception that this
530 * chunk uses four color components as opposed to three. The number of colors
531 * contained within would be chunk length/4. This chunk would be used in addition
532 * to the CMAP chunk.
533 */
534class CMYKChunk : public CMAPChunk
535{
536public:
537 virtual ~CMYKChunk() override;
538 CMYKChunk();
539 CMYKChunk(const CMYKChunk& other) = default;
540 CMYKChunk& operator =(const CMYKChunk& other) = default;
541
542 virtual bool isValid() const override;
543
544 /*!
545 * \brief count
546 * \return The number of color in the palette.
547 */
548 virtual qint32 count() const override;
549
550 CHUNKID_DEFINE(CMYK_CHUNK)
551
552protected:
553 /*!
554 * \brief palette
555 * \return The CMYK color palette converted to RGB one.
556 */
557 virtual QList<QRgb> innerPalette() const override;
558};
559
560/*!
561 * \brief The CAMGChunk class
562 */
563class CAMGChunk : public IFFChunk
564{
565public:
566 enum ModeId {
567 LoResLace = 0x0004,
568 HalfBrite = 0x0080,
569 LoResDpf = 0x0400,
570 Ham = 0x0800,
571 HiRes = 0x8000
572 };
573
574 Q_DECLARE_FLAGS(ModeIds, ModeId)
575
576 virtual ~CAMGChunk() override;
577 CAMGChunk();
578 CAMGChunk(const CAMGChunk& other) = default;
579 CAMGChunk& operator =(const CAMGChunk& other) = default;
580
581 virtual bool isValid() const override;
582
583 ModeIds modeId() const;
584
585 CHUNKID_DEFINE(CAMG_CHUNK)
586
587protected:
588 virtual bool innerReadStructure(QIODevice *d) override;
589};
590
591/*!
592 * \brief The DPIChunk class
593 */
594class DPIChunk : public IFFChunk
595{
596public:
597 virtual ~DPIChunk() override;
598 DPIChunk();
599 DPIChunk(const DPIChunk& other) = default;
600 DPIChunk& operator =(const DPIChunk& other) = default;
601
602 virtual bool isValid() const override;
603
604 /*!
605 * \brief dpiX
606 * \return The horizontal resolution in DPI.
607 */
608 quint16 dpiX() const;
609
610 /*!
611 * \brief dpiY
612 * \return The vertical resolution in DPI.
613 */
614 quint16 dpiY() const;
615
616 /*!
617 * \brief dotsPerMeterX
618 * \return X resolution as wanted by QImage.
619 */
620 qint32 dotsPerMeterX() const;
621
622 /*!
623 * \brief dotsPerMeterY
624 * \return Y resolution as wanted by QImage.
625 */
626 qint32 dotsPerMeterY() const;
627
628 CHUNKID_DEFINE(DPI__CHUNK)
629
630protected:
631 virtual bool innerReadStructure(QIODevice *d) override;
632};
633
634
635/*!
636 * \brief The BODYChunk class
637 */
638class BODYChunk : public IFFChunk
639{
640public:
641 virtual ~BODYChunk() override;
642 BODYChunk();
643 BODYChunk(const BODYChunk& other) = default;
644 BODYChunk& operator =(const BODYChunk& other) = default;
645
646 virtual bool isValid() const override;
647
648 CHUNKID_DEFINE(BODY_CHUNK)
649
650 /*!
651 * \brief readStride
652 * \param d The device.
653 * \param header The bitmap header.
654 * \param y The current scanline.
655 * \param camg The CAMG chunk (optional)
656 * \param cmap The CMAP chunk (optional)
657 * \param formType The type of the current form chunk.
658 * \return The scanline as requested for QImage.
659 * \warning Call resetStrideRead() once before this one.
660 */
661 virtual QByteArray strideRead(QIODevice *d,
662 qint32 y,
663 const BMHDChunk *header,
664 const CAMGChunk *camg = nullptr,
665 const CMAPChunk *cmap = nullptr,
666 const IPALChunk *ipal = nullptr,
667 const QByteArray& formType = ILBM_FORM_TYPE) const;
668
669 /*!
670 * \brief resetStrideRead
671 * Reset the stride read set the position at the beginning of the data and reset all buffers.
672 * \param d The device.
673 * \param header The BMHDChunk chunk (mandatory)
674 * \param camg The CAMG chunk (optional)
675 * \return True on success, otherwise false.
676 * \sa strideRead
677 * \note Must be called once before strideRead().
678 */
679 virtual bool resetStrideRead(QIODevice *d) const;
680
681 /*!
682 * \brief safeModeId
683 * \param header The header.
684 * \param camg The CAMG chunk.
685 * \return The most likely ModeId if not explicitly specified.
686 */
687 static CAMGChunk::ModeIds safeModeId(const BMHDChunk *header, const CAMGChunk *camg, const CMAPChunk *cmap = nullptr);
688
689protected:
690 /*!
691 * \brief strideSize
692 * \param formType The type of the current form chunk.
693 * \return The size of data to have to decode an image row.
694 */
695 quint32 strideSize(const BMHDChunk *header, const QByteArray& formType) const;
696
697 QByteArray deinterleave(const QByteArray &planes, qint32 y, const BMHDChunk *header, const CAMGChunk *camg = nullptr, const CMAPChunk *cmap = nullptr, const IPALChunk *ipal = nullptr) const;
698
699 QByteArray pbm(const QByteArray &planes, qint32 y, const BMHDChunk *header, const CAMGChunk *camg = nullptr, const CMAPChunk *cmap = nullptr, const IPALChunk *ipal = nullptr) const;
700
701 QByteArray rgb8(const QByteArray &planes, qint32 y, const BMHDChunk *header, const CAMGChunk *camg = nullptr, const CMAPChunk *cmap = nullptr, const IPALChunk *ipal = nullptr) const;
702
703 QByteArray rgbN(const QByteArray &planes, qint32 y, const BMHDChunk *header, const CAMGChunk *camg = nullptr, const CMAPChunk *cmap = nullptr, const IPALChunk *ipal = nullptr) const;
704
705private:
706 mutable QByteArray _readBuffer;
707};
708
709
710/*!
711 * \brief The ABITChunk class
712 */
713class ABITChunk : public BODYChunk
714{
715public:
716 virtual ~ABITChunk() override;
717 ABITChunk();
718 ABITChunk(const ABITChunk& other) = default;
719 ABITChunk& operator =(const ABITChunk& other) = default;
720
721 virtual bool isValid() const override;
722
723 CHUNKID_DEFINE(ABIT_CHUNK)
724
725 virtual QByteArray strideRead(QIODevice *d,
726 qint32 y,
727 const BMHDChunk *header,
728 const CAMGChunk *camg = nullptr,
729 const CMAPChunk *cmap = nullptr,
730 const IPALChunk *ipal = nullptr,
731 const QByteArray& formType = ACBM_FORM_TYPE) const override;
732
733 virtual bool resetStrideRead(QIODevice *d) const override;
734};
735
736/*!
737 * \brief The IFOR_Chunk class
738 * Interface for FORM chunks.
739 */
740class IFOR_Chunk : public IFFChunk
741{
742public:
743 virtual ~IFOR_Chunk() override;
744 IFOR_Chunk();
745
746 /*!
747 * \brief isSupported
748 * \return True if the form is supported by the plugin.
749 */
750 virtual bool isSupported() const = 0;
751
752 /*!
753 * \brief formType
754 * \return The type of image data contained in the form.
755 */
756 virtual QByteArray formType() const = 0;
757
758 /*!
759 * \brief format
760 * \return The Qt image format the form is converted to.
761 */
762 virtual QImage::Format format() const = 0;
763
764 /*!
765 * \brief transformation
766 * \return The image transformation.
767 * \note The Default implentation returns the trasformation of EXIF chunk (if any).
768 */
769 virtual QImageIOHandler::Transformation transformation() const;
770
771 /*!
772 * \brief size
773 * \return The image size in pixels.
774 */
775 virtual QSize size() const = 0;
776
777 /*!
778 * \brief optionformat
779 * \return The format retuned by the plugin after all conversions.
780 */
781 QImage::Format optionformat() const;
782
783 /*!
784 * \brief searchIPal
785 * Search the palett per line chunk.
786 * \return The per line palette (BEAM, CTBL, SHAM, etc....).
787 */
788 const IPALChunk *searchIPal() const;
789};
790
791/*!
792 * \brief The FORMChunk class
793 */
794class FORMChunk : public IFOR_Chunk
795{
796 QByteArray _type;
797
798public:
799 virtual ~FORMChunk() override;
800 FORMChunk();
801 FORMChunk(const FORMChunk& other) = default;
802 FORMChunk& operator =(const FORMChunk& other) = default;
803
804 virtual bool isValid() const override;
805
806 virtual bool isSupported() const override;
807
808 virtual QByteArray formType() const override;
809
810 virtual QImage::Format format() const override;
811
812 virtual QSize size() const override;
813
814 CHUNKID_DEFINE(FORM_CHUNK)
815
816protected:
817 virtual bool innerReadStructure(QIODevice *d) override;
818};
819
820
821/*!
822 * \brief The FOR4Chunk class
823 */
824class FOR4Chunk : public IFOR_Chunk
825{
826 QByteArray _type;
827
828public:
829 virtual ~FOR4Chunk() override;
830 FOR4Chunk();
831 FOR4Chunk(const FOR4Chunk& other) = default;
832 FOR4Chunk& operator =(const FOR4Chunk& other) = default;
833
834 virtual bool isValid() const override;
835
836 virtual qint32 alignBytes() const override;
837
838 virtual bool isSupported() const override;
839
840 virtual QByteArray formType() const override;
841
842 virtual QImage::Format format() const override;
843
844 virtual QSize size() const override;
845
846 CHUNKID_DEFINE(FOR4_CHUNK)
847
848protected:
849 virtual bool innerReadStructure(QIODevice *d) override;
850};
851
852/*!
853 * \brief The CATChunk class
854 */
855class CATChunk : public IFFChunk
856{
857 QByteArray _type;
858
859public:
860 virtual ~CATChunk() override;
861 CATChunk();
862 CATChunk(const CATChunk& other) = default;
863 CATChunk& operator =(const CATChunk& other) = default;
864
865 virtual bool isValid() const override;
866
867 QByteArray catType() const;
868
869 CHUNKID_DEFINE(CAT__CHUNK)
870
871protected:
872 virtual bool innerReadStructure(QIODevice *d) override;
873};
874
875/*!
876 * \brief The TBHDChunk class
877 */
878class TBHDChunk : public IFFChunk
879{
880public:
881 enum Flag {
882 Rgb = 0x01, /**< RGB image */
883 Alpha = 0x02, /**< Image contains alpha channel */
884 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. */
885
886 RgbA = Rgb | Alpha /**< RGBA image */
887 };
888 Q_DECLARE_FLAGS(Flags, Flag)
889
890 enum Compression {
891 Uncompressed = 0,
892 Rle = 1
893 };
894
895 virtual ~TBHDChunk() override;
896
897 TBHDChunk();
898 TBHDChunk(const TBHDChunk& other) = default;
899 TBHDChunk& operator =(const TBHDChunk& other) = default;
900
901 virtual bool isValid() const override;
902
903 virtual qint32 alignBytes() const override;
904
905 /*!
906 * \brief width
907 * \return Image width in pixels.
908 */
909 qint32 width() const;
910
911 /*!
912 * \brief height
913 * \return Image height in pixels.
914 */
915 qint32 height() const;
916
917 /*!
918 * \brief size
919 * \return Image size in pixels.
920 */
921 QSize size() const;
922
923 /*!
924 * \brief left
925 * \return
926 */
927 qint32 left() const;
928
929 /*!
930 * \brief top
931 * \return
932 */
933 qint32 top() const;
934
935 /*!
936 * \brief flags
937 * \return Image flags.
938 */
939 Flags flags() const;
940
941 /*!
942 * \brief bpc
943 * \return Byte per channel (1 or 2)
944 */
945 qint32 bpc() const;
946
947 /*!
948 * \brief channels
949 * \return
950 */
951 qint32 channels() const;
952
953 /*!
954 * \brief tiles
955 * \return The number of tiles of the image.
956 */
957 quint16 tiles() const;
958
959 /*!
960 * \brief compression
961 * \return The data compression.
962 */
963 Compression compression() const;
964
965 /*!
966 * \brief format
967 * \return
968 */
969 QImage::Format format() const;
970
971 CHUNKID_DEFINE(TBHD_CHUNK)
972
973protected:
974 virtual bool innerReadStructure(QIODevice *d) override;
975};
976
977/*!
978 * \brief The RGBAChunk class
979 */
980class RGBAChunk : public IFFChunk
981{
982public:
983 virtual ~RGBAChunk() override;
984 RGBAChunk();
985 RGBAChunk(const RGBAChunk& other) = default;
986 RGBAChunk& operator =(const RGBAChunk& other) = default;
987
988 virtual bool isValid() const override;
989
990 virtual qint32 alignBytes() const override;
991
992 /*!
993 * \brief isTileCompressed
994 * \param header The image header.
995 * \return True if the tile is compressed, otherwise false.
996 */
997 bool isTileCompressed(const TBHDChunk *header) const;
998
999 /*!
1000 * \brief pos
1001 * \return The tile position (top-left corner) in the final image.
1002 */
1003 QPoint pos() const;
1004
1005 /*!
1006 * \brief size
1007 * \return The tile size in pixels.
1008 */
1009 QSize size() const;
1010
1011 /*!
1012 * \brief tile
1013 * Create the tile by reading the data from the device.
1014 * \param d The device.
1015 * \param header The image header.
1016 * \return The image tile.
1017 */
1018 QImage tile(QIODevice *d, const TBHDChunk *header) const;
1019
1020 CHUNKID_DEFINE(RGBA_CHUNK)
1021
1022protected:
1023 virtual bool innerReadStructure(QIODevice *d) override;
1024
1025private:
1026 QImage compressedTile(QIODevice *d, const TBHDChunk *header) const;
1027
1028 QImage uncompressedTile(QIODevice *d, const TBHDChunk *header) const;
1029
1030 QByteArray readStride(QIODevice *d, const TBHDChunk *header) const;
1031
1032private:
1033 QPoint _posPx;
1034
1035 QSize _sizePx;
1036
1037 mutable QByteArray _readBuffer;
1038};
1039
1040/*!
1041 * \brief The ANNOChunk class
1042 */
1043class ANNOChunk : public IFFChunk
1044{
1045public:
1046 virtual ~ANNOChunk() override;
1047 ANNOChunk();
1048 ANNOChunk(const ANNOChunk& other) = default;
1049 ANNOChunk& operator =(const ANNOChunk& other) = default;
1050
1051 virtual bool isValid() const override;
1052
1053 QString value() const;
1054
1055 CHUNKID_DEFINE(ANNO_CHUNK)
1056
1057protected:
1058 virtual bool innerReadStructure(QIODevice *d) override;
1059};
1060
1061/*!
1062 * \brief The AUTHChunk class
1063 */
1064class AUTHChunk : public IFFChunk
1065{
1066public:
1067 virtual ~AUTHChunk() override;
1068 AUTHChunk();
1069 AUTHChunk(const AUTHChunk& other) = default;
1070 AUTHChunk& operator =(const AUTHChunk& other) = default;
1071
1072 virtual bool isValid() const override;
1073
1074 QString value() const;
1075
1076 CHUNKID_DEFINE(AUTH_CHUNK)
1077
1078protected:
1079 virtual bool innerReadStructure(QIODevice *d) override;
1080};
1081
1082/*!
1083 * \brief The COPYChunk class
1084 */
1085class COPYChunk : public IFFChunk
1086{
1087public:
1088 virtual ~COPYChunk() override;
1089 COPYChunk();
1090 COPYChunk(const COPYChunk& other) = default;
1091 COPYChunk& operator =(const COPYChunk& other) = default;
1092
1093 virtual bool isValid() const override;
1094
1095 QString value() const;
1096
1097 CHUNKID_DEFINE(COPY_CHUNK)
1098
1099protected:
1100 virtual bool innerReadStructure(QIODevice *d) override;
1101};
1102
1103/*!
1104 * \brief The DATEChunk class
1105 */
1106class DATEChunk : public IFFChunk
1107{
1108public:
1109 virtual ~DATEChunk() override;
1110 DATEChunk();
1111 DATEChunk(const DATEChunk& other) = default;
1112 DATEChunk& operator =(const DATEChunk& other) = default;
1113
1114 virtual bool isValid() const override;
1115
1116 QDateTime value() const;
1117
1118 CHUNKID_DEFINE(DATE_CHUNK)
1119
1120protected:
1121 virtual bool innerReadStructure(QIODevice *d) override;
1122};
1123
1124/*!
1125 * \brief The EXIFChunk class
1126 */
1127class EXIFChunk : public IFFChunk
1128{
1129public:
1130 virtual ~EXIFChunk() override;
1131 EXIFChunk();
1132 EXIFChunk(const EXIFChunk& other) = default;
1133 EXIFChunk& operator =(const EXIFChunk& other) = default;
1134
1135 virtual bool isValid() const override;
1136
1137 MicroExif value() const;
1138
1139 CHUNKID_DEFINE(EXIF_CHUNK)
1140
1141protected:
1142 virtual bool innerReadStructure(QIODevice *d) override;
1143};
1144
1145
1146/*!
1147 * \brief The NAMEChunk class
1148 */
1149class ICCNChunk : public IFFChunk
1150{
1151public:
1152 virtual ~ICCNChunk() override;
1153 ICCNChunk();
1154 ICCNChunk(const ICCNChunk& other) = default;
1155 ICCNChunk& operator =(const ICCNChunk& other) = default;
1156
1157 virtual bool isValid() const override;
1158
1159 QString value() const;
1160
1161 CHUNKID_DEFINE(ICCN_CHUNK)
1162
1163protected:
1164 virtual bool innerReadStructure(QIODevice *d) override;
1165};
1166
1167/*!
1168 * \brief The ICCPChunk class
1169 */
1170class ICCPChunk : public IFFChunk
1171{
1172public:
1173 virtual ~ICCPChunk() override;
1174 ICCPChunk();
1175 ICCPChunk(const ICCPChunk& other) = default;
1176 ICCPChunk& operator =(const ICCPChunk& other) = default;
1177
1178 virtual bool isValid() const override;
1179
1180 QColorSpace value() const;
1181
1182 CHUNKID_DEFINE(ICCP_CHUNK)
1183
1184protected:
1185 virtual bool innerReadStructure(QIODevice *d) override;
1186};
1187
1188
1189/*!
1190 * \brief The FVERChunk class
1191 *
1192 * \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.
1193 */
1194class FVERChunk : public IFFChunk
1195{
1196public:
1197 virtual ~FVERChunk() override;
1198 FVERChunk();
1199 FVERChunk(const FVERChunk& other) = default;
1200 FVERChunk& operator =(const FVERChunk& other) = default;
1201
1202 virtual bool isValid() const override;
1203
1204 CHUNKID_DEFINE(FVER_CHUNK)
1205
1206protected:
1207 virtual bool innerReadStructure(QIODevice *d) override;
1208};
1209
1210
1211/*!
1212 * \brief The HISTChunk class
1213 */
1214class HISTChunk : public IFFChunk
1215{
1216public:
1217 virtual ~HISTChunk() override;
1218 HISTChunk();
1219 HISTChunk(const HISTChunk& other) = default;
1220 HISTChunk& operator =(const HISTChunk& other) = default;
1221
1222 virtual bool isValid() const override;
1223
1224 QString value() const;
1225
1226 CHUNKID_DEFINE(HIST_CHUNK)
1227
1228protected:
1229 virtual bool innerReadStructure(QIODevice *d) override;
1230};
1231
1232
1233/*!
1234 * \brief The NAMEChunk class
1235 */
1236class NAMEChunk : public IFFChunk
1237{
1238public:
1239 virtual ~NAMEChunk() override;
1240 NAMEChunk();
1241 NAMEChunk(const NAMEChunk& other) = default;
1242 NAMEChunk& operator =(const NAMEChunk& other) = default;
1243
1244 virtual bool isValid() const override;
1245
1246 QString value() const;
1247
1248 CHUNKID_DEFINE(NAME_CHUNK)
1249
1250protected:
1251 virtual bool innerReadStructure(QIODevice *d) override;
1252};
1253
1254/*!
1255 * \brief The VERSChunk class
1256 */
1257class VERSChunk : public IFFChunk
1258{
1259public:
1260 virtual ~VERSChunk() override;
1261 VERSChunk();
1262 VERSChunk(const VERSChunk& other) = default;
1263 VERSChunk& operator =(const VERSChunk& other) = default;
1264
1265 virtual bool isValid() const override;
1266
1267 QString value() const;
1268
1269 CHUNKID_DEFINE(VERS_CHUNK)
1270
1271protected:
1272 virtual bool innerReadStructure(QIODevice *d) override;
1273};
1274
1275
1276/*!
1277 * \brief The XMP0Chunk class
1278 */
1279class XMP0Chunk : public IFFChunk
1280{
1281public:
1282 virtual ~XMP0Chunk() override;
1283 XMP0Chunk();
1284 XMP0Chunk(const XMP0Chunk& other) = default;
1285 XMP0Chunk& operator =(const XMP0Chunk& other) = default;
1286
1287 virtual bool isValid() const override;
1288
1289 QString value() const;
1290
1291 CHUNKID_DEFINE(XMP0_CHUNK)
1292
1293protected:
1294 virtual bool innerReadStructure(QIODevice *d) override;
1295};
1296
1297
1298/*!
1299 * *** UNDOCUMENTED CHUNKS ***
1300 */
1301
1302/*!
1303 * \brief The BEAMChunk class
1304 */
1305class BEAMChunk : public IPALChunk
1306{
1307public:
1308 virtual ~BEAMChunk() override;
1309 BEAMChunk();
1310 BEAMChunk(const BEAMChunk& other) = default;
1311 BEAMChunk& operator =(const BEAMChunk& other) = default;
1312
1313 virtual bool isValid() const override;
1314
1315 virtual QList<QRgb> palette(qint32 y, qint32 height) const override;
1316
1317 CHUNKID_DEFINE(BEAM_CHUNK)
1318
1319protected:
1320 virtual bool innerReadStructure(QIODevice *d) override;
1321};
1322
1323/*!
1324 * \brief The CTBLChunk class
1325 */
1326class CTBLChunk : public BEAMChunk
1327{
1328public:
1329 virtual ~CTBLChunk() override;
1330 CTBLChunk();
1331 CTBLChunk(const CTBLChunk& other) = default;
1332 CTBLChunk& operator =(const CTBLChunk& other) = default;
1333
1334 virtual bool isValid() const override;
1335
1336 CHUNKID_DEFINE(CTBL_CHUNK)
1337};
1338
1339/*!
1340 * \brief The SHAMChunk class
1341 */
1342class SHAMChunk : public IPALChunk
1343{
1344public:
1345 virtual ~SHAMChunk() override;
1346 SHAMChunk();
1347 SHAMChunk(const SHAMChunk& other) = default;
1348 SHAMChunk& operator =(const SHAMChunk& other) = default;
1349
1350 virtual bool isValid() const override;
1351
1352 virtual QList<QRgb> palette(qint32 y, qint32 height) const override;
1353
1354 CHUNKID_DEFINE(SHAM_CHUNK)
1355
1356protected:
1357 virtual bool innerReadStructure(QIODevice *d) override;
1358};
1359
1360/*!
1361 * \brief The RASTChunk class
1362 * \note I found an Atari STE image with the RAST chunk outside
1363 * the form chunk (Fish.neo.iff). To support it the IFF parser
1364 * should be changed so, this kind of IFFs are shown wrong.
1365 */
1366class RASTChunk : public IPALChunk
1367{
1368public:
1369 virtual ~RASTChunk() override;
1370 RASTChunk();
1371 RASTChunk(const RASTChunk& other) = default;
1372 RASTChunk& operator =(const RASTChunk& other) = default;
1373
1374 virtual bool isValid() const override;
1375
1376 virtual QList<QRgb> palette(qint32 y, qint32 height) const override;
1377
1378 CHUNKID_DEFINE(RAST_CHUNK)
1379
1380protected:
1381 virtual bool innerReadStructure(QIODevice *d) override;
1382};
1383
1384
1385#endif // KIMG_CHUNKS_P_H
1386

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