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 | |
29 | Q_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 | */ |
103 | class IFFChunk |
104 | { |
105 | public: |
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 | |
274 | protected: |
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 | |
336 | private: |
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 | */ |
356 | class IPALChunk : public IFFChunk |
357 | { |
358 | public: |
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 | */ |
369 | class BMHDChunk: public IFFChunk |
370 | { |
371 | public: |
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 | |
485 | protected: |
486 | virtual bool innerReadStructure(QIODevice *d) override; |
487 | }; |
488 | |
489 | /*! |
490 | * \brief The CMAPChunk class |
491 | */ |
492 | class CMAPChunk : public IFFChunk |
493 | { |
494 | public: |
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 | |
518 | protected: |
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 | */ |
534 | class CMYKChunk : public CMAPChunk |
535 | { |
536 | public: |
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 | |
552 | protected: |
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 | */ |
563 | class CAMGChunk : public IFFChunk |
564 | { |
565 | public: |
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 | |
587 | protected: |
588 | virtual bool innerReadStructure(QIODevice *d) override; |
589 | }; |
590 | |
591 | /*! |
592 | * \brief The DPIChunk class |
593 | */ |
594 | class DPIChunk : public IFFChunk |
595 | { |
596 | public: |
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 | |
630 | protected: |
631 | virtual bool innerReadStructure(QIODevice *d) override; |
632 | }; |
633 | |
634 | |
635 | /*! |
636 | * \brief The BODYChunk class |
637 | */ |
638 | class BODYChunk : public IFFChunk |
639 | { |
640 | public: |
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 *, |
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 *, const CAMGChunk *camg, const CMAPChunk *cmap = nullptr); |
688 | |
689 | protected: |
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 *, const QByteArray& formType) const; |
696 | |
697 | QByteArray deinterleave(const QByteArray &planes, qint32 y, const BMHDChunk *, const CAMGChunk *camg = nullptr, const CMAPChunk *cmap = nullptr, const IPALChunk *ipal = nullptr) const; |
698 | |
699 | QByteArray pbm(const QByteArray &planes, qint32 y, const BMHDChunk *, const CAMGChunk *camg = nullptr, const CMAPChunk *cmap = nullptr, const IPALChunk *ipal = nullptr) const; |
700 | |
701 | QByteArray rgb8(const QByteArray &planes, qint32 y, const BMHDChunk *, const CAMGChunk *camg = nullptr, const CMAPChunk *cmap = nullptr, const IPALChunk *ipal = nullptr) const; |
702 | |
703 | QByteArray rgbN(const QByteArray &planes, qint32 y, const BMHDChunk *, const CAMGChunk *camg = nullptr, const CMAPChunk *cmap = nullptr, const IPALChunk *ipal = nullptr) const; |
704 | |
705 | private: |
706 | mutable QByteArray _readBuffer; |
707 | }; |
708 | |
709 | |
710 | /*! |
711 | * \brief The ABITChunk class |
712 | */ |
713 | class ABITChunk : public BODYChunk |
714 | { |
715 | public: |
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 *, |
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 | */ |
740 | class IFOR_Chunk : public IFFChunk |
741 | { |
742 | public: |
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 | */ |
794 | class FORMChunk : public IFOR_Chunk |
795 | { |
796 | QByteArray _type; |
797 | |
798 | public: |
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 | |
816 | protected: |
817 | virtual bool innerReadStructure(QIODevice *d) override; |
818 | }; |
819 | |
820 | |
821 | /*! |
822 | * \brief The FOR4Chunk class |
823 | */ |
824 | class FOR4Chunk : public IFOR_Chunk |
825 | { |
826 | QByteArray _type; |
827 | |
828 | public: |
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 | |
848 | protected: |
849 | virtual bool innerReadStructure(QIODevice *d) override; |
850 | }; |
851 | |
852 | /*! |
853 | * \brief The CATChunk class |
854 | */ |
855 | class CATChunk : public IFFChunk |
856 | { |
857 | QByteArray _type; |
858 | |
859 | public: |
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 | |
871 | protected: |
872 | virtual bool innerReadStructure(QIODevice *d) override; |
873 | }; |
874 | |
875 | /*! |
876 | * \brief The TBHDChunk class |
877 | */ |
878 | class TBHDChunk : public IFFChunk |
879 | { |
880 | public: |
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 | |
973 | protected: |
974 | virtual bool innerReadStructure(QIODevice *d) override; |
975 | }; |
976 | |
977 | /*! |
978 | * \brief The RGBAChunk class |
979 | */ |
980 | class RGBAChunk : public IFFChunk |
981 | { |
982 | public: |
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 *) 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 *) const; |
1019 | |
1020 | CHUNKID_DEFINE(RGBA_CHUNK) |
1021 | |
1022 | protected: |
1023 | virtual bool innerReadStructure(QIODevice *d) override; |
1024 | |
1025 | private: |
1026 | QImage compressedTile(QIODevice *d, const TBHDChunk *) const; |
1027 | |
1028 | QImage uncompressedTile(QIODevice *d, const TBHDChunk *) const; |
1029 | |
1030 | QByteArray readStride(QIODevice *d, const TBHDChunk *) const; |
1031 | |
1032 | private: |
1033 | QPoint _posPx; |
1034 | |
1035 | QSize _sizePx; |
1036 | |
1037 | mutable QByteArray _readBuffer; |
1038 | }; |
1039 | |
1040 | /*! |
1041 | * \brief The ANNOChunk class |
1042 | */ |
1043 | class ANNOChunk : public IFFChunk |
1044 | { |
1045 | public: |
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 | |
1057 | protected: |
1058 | virtual bool innerReadStructure(QIODevice *d) override; |
1059 | }; |
1060 | |
1061 | /*! |
1062 | * \brief The AUTHChunk class |
1063 | */ |
1064 | class AUTHChunk : public IFFChunk |
1065 | { |
1066 | public: |
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 | |
1078 | protected: |
1079 | virtual bool innerReadStructure(QIODevice *d) override; |
1080 | }; |
1081 | |
1082 | /*! |
1083 | * \brief The COPYChunk class |
1084 | */ |
1085 | class COPYChunk : public IFFChunk |
1086 | { |
1087 | public: |
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 | |
1099 | protected: |
1100 | virtual bool innerReadStructure(QIODevice *d) override; |
1101 | }; |
1102 | |
1103 | /*! |
1104 | * \brief The DATEChunk class |
1105 | */ |
1106 | class DATEChunk : public IFFChunk |
1107 | { |
1108 | public: |
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 | |
1120 | protected: |
1121 | virtual bool innerReadStructure(QIODevice *d) override; |
1122 | }; |
1123 | |
1124 | /*! |
1125 | * \brief The EXIFChunk class |
1126 | */ |
1127 | class EXIFChunk : public IFFChunk |
1128 | { |
1129 | public: |
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 | |
1141 | protected: |
1142 | virtual bool innerReadStructure(QIODevice *d) override; |
1143 | }; |
1144 | |
1145 | |
1146 | /*! |
1147 | * \brief The NAMEChunk class |
1148 | */ |
1149 | class ICCNChunk : public IFFChunk |
1150 | { |
1151 | public: |
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 | |
1163 | protected: |
1164 | virtual bool innerReadStructure(QIODevice *d) override; |
1165 | }; |
1166 | |
1167 | /*! |
1168 | * \brief The ICCPChunk class |
1169 | */ |
1170 | class ICCPChunk : public IFFChunk |
1171 | { |
1172 | public: |
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 | |
1184 | protected: |
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 | */ |
1194 | class FVERChunk : public IFFChunk |
1195 | { |
1196 | public: |
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 | |
1206 | protected: |
1207 | virtual bool innerReadStructure(QIODevice *d) override; |
1208 | }; |
1209 | |
1210 | |
1211 | /*! |
1212 | * \brief The HISTChunk class |
1213 | */ |
1214 | class HISTChunk : public IFFChunk |
1215 | { |
1216 | public: |
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 | |
1228 | protected: |
1229 | virtual bool innerReadStructure(QIODevice *d) override; |
1230 | }; |
1231 | |
1232 | |
1233 | /*! |
1234 | * \brief The NAMEChunk class |
1235 | */ |
1236 | class NAMEChunk : public IFFChunk |
1237 | { |
1238 | public: |
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 | |
1250 | protected: |
1251 | virtual bool innerReadStructure(QIODevice *d) override; |
1252 | }; |
1253 | |
1254 | /*! |
1255 | * \brief The VERSChunk class |
1256 | */ |
1257 | class VERSChunk : public IFFChunk |
1258 | { |
1259 | public: |
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 | |
1271 | protected: |
1272 | virtual bool innerReadStructure(QIODevice *d) override; |
1273 | }; |
1274 | |
1275 | |
1276 | /*! |
1277 | * \brief The XMP0Chunk class |
1278 | */ |
1279 | class XMP0Chunk : public IFFChunk |
1280 | { |
1281 | public: |
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 | |
1293 | protected: |
1294 | virtual bool innerReadStructure(QIODevice *d) override; |
1295 | }; |
1296 | |
1297 | |
1298 | /*! |
1299 | * *** UNDOCUMENTED CHUNKS *** |
1300 | */ |
1301 | |
1302 | /*! |
1303 | * \brief The BEAMChunk class |
1304 | */ |
1305 | class BEAMChunk : public IPALChunk |
1306 | { |
1307 | public: |
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 | |
1319 | protected: |
1320 | virtual bool innerReadStructure(QIODevice *d) override; |
1321 | }; |
1322 | |
1323 | /*! |
1324 | * \brief The CTBLChunk class |
1325 | */ |
1326 | class CTBLChunk : public BEAMChunk |
1327 | { |
1328 | public: |
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 | */ |
1342 | class SHAMChunk : public IPALChunk |
1343 | { |
1344 | public: |
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 | |
1356 | protected: |
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 | */ |
1366 | class RASTChunk : public IPALChunk |
1367 | { |
1368 | public: |
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 | |
1380 | protected: |
1381 | virtual bool innerReadStructure(QIODevice *d) override; |
1382 | }; |
1383 | |
1384 | |
1385 | #endif // KIMG_CHUNKS_P_H |
1386 | |