1 | /* |
2 | PIC_RW - Qt PIC Support |
3 | SPDX-FileCopyrightText: 2007 Ruben Lopez <r.lopez@bren.es> |
4 | |
5 | SPDX-License-Identifier: LGPL-2.0-or-later |
6 | */ |
7 | |
8 | #ifndef KIMG_PIC_P_H |
9 | #define KIMG_PIC_P_H |
10 | |
11 | #include <QDataStream> |
12 | #include <QImageIOPlugin> |
13 | |
14 | /** |
15 | * The magic number at the start of a SoftImage PIC file. |
16 | */ |
17 | static const qint32 PIC_MAGIC_NUMBER = 0x5380f634; |
18 | |
19 | /** |
20 | * How fields are distributed over the image. |
21 | * |
22 | * This information is not used by this image format code. |
23 | */ |
24 | enum PicFields { |
25 | NoPicture = 0, /**< No picture */ |
26 | OddScanlines = 1, /**< Odd scanlines */ |
27 | EvenScanlines = 2, /**< Even scanlines */ |
28 | BothScanlines = 3, /**< Every scanline */ |
29 | }; |
30 | |
31 | /** |
32 | * How the data for a channel is encoded. |
33 | */ |
34 | enum PicChannelEncoding { |
35 | Uncompressed = 0, /**< Image is uncompressed */ |
36 | MixedRLE = 2, /**< Run length compression */ |
37 | }; |
38 | |
39 | /** |
40 | * What components are encoded in a channel. |
41 | */ |
42 | enum PicChannelCode { |
43 | RED = 0x80, /**< Red channel */ |
44 | GREEN = 0x40, /**< Green channel */ |
45 | BLUE = 0x20, /**< Blue channel */ |
46 | ALPHA = 0x10, /**< Alpha channel */ |
47 | }; |
48 | |
49 | /** |
50 | * The header for a SoftImage PIC file. |
51 | * |
52 | * @private |
53 | */ |
54 | struct { |
55 | /** |
56 | * Construct a valid header for a SoftImage PIC file. |
57 | * |
58 | * Note that the comment will be truncated to 80 bytes when written. |
59 | * |
60 | * @param _width The width of the image in pixels |
61 | * @param _height The height of the image in pixels |
62 | * @param _comment A comment to add to the image |
63 | */ |
64 | (quint16 _width, quint16 _height, const QByteArray & = QByteArray()) |
65 | : magic(PIC_MAGIC_NUMBER) |
66 | , version(3.71f) |
67 | , comment(_comment) |
68 | , id("PICT" ) |
69 | , width(_width) |
70 | , height(_height) |
71 | , ratio(1.0f) |
72 | , fields(BothScanlines) |
73 | { |
74 | } |
75 | /** Construct an invalid header. */ |
76 | () |
77 | { |
78 | } |
79 | |
80 | quint32 ; /**< Should be PIC_MAGIC_NUMBER */ |
81 | float ; /**< Version of something (header? file format?) (ignored) */ |
82 | QByteArray ; /**< A free comment field (truncated to 80 bytes when |
83 | written) */ |
84 | QByteArray ; /**< The file format ID (should be "PICT") */ |
85 | quint16 ; /**< The width of the image in pixels */ |
86 | quint16 ; /**< The height of the image in pixels */ |
87 | float ; /**< The aspect ratio: width/height of each individual pixel |
88 | (ignored) */ |
89 | PicFields ; /**< The interlace type (ignored) */ |
90 | |
91 | /** |
92 | * Returns true if the @p magic and @p id fields are set correctly. |
93 | */ |
94 | bool () const |
95 | { |
96 | return magic == PIC_MAGIC_NUMBER && id == "PICT" ; |
97 | } |
98 | |
99 | /** |
100 | * The length of the encoded data, in bytes. |
101 | */ |
102 | static const qint64 = 104; |
103 | }; |
104 | |
105 | /** |
106 | * Describes a channel in a SoftImage PIC file. |
107 | * |
108 | * @private |
109 | */ |
110 | struct PicChannel { |
111 | quint8 size; /**< Bits per component per pixel. */ |
112 | quint8 encoding; /**< How the channel's data is encoded. */ |
113 | quint8 code; /**< Flag field to describe which components are encoded in |
114 | this channel. */ |
115 | |
116 | /** |
117 | * Constructs a channel description for a SoftImage PIC file. |
118 | * |
119 | * @param _encoding How the channel's data is or will be encoded. |
120 | * @param _code What components are or will be encoded by this |
121 | * channel. |
122 | * @param _size The number of bits used to encoded a single component |
123 | * for a single pixel in this channel (should be 8). |
124 | */ |
125 | PicChannel(PicChannelEncoding _encoding, quint8 _code, quint8 _size = 8) |
126 | : size(_size) |
127 | , encoding(_encoding) |
128 | , code(_code) |
129 | { |
130 | } |
131 | /** |
132 | * Constructs a default channel description for a SoftImage PIC file. |
133 | * |
134 | * This will have size set to 8, encoding set to Uncompressed and the code |
135 | * set to 0 (so that the channel does not encode any information). |
136 | * |
137 | * The result of this should not be written to a file without setting the |
138 | * encoding and channel fields correctly. |
139 | */ |
140 | PicChannel() |
141 | : size(8) |
142 | { |
143 | } |
144 | }; |
145 | |
146 | class SoftimagePICHandler : public QImageIOHandler |
147 | { |
148 | public: |
149 | bool canRead() const override; |
150 | bool read(QImage *image) override; |
151 | bool write(const QImage &) override; |
152 | |
153 | QVariant option(ImageOption option) const override; |
154 | void setOption(ImageOption option, const QVariant &value) override; |
155 | bool supportsOption(ImageOption option) const override; |
156 | |
157 | static bool canRead(QIODevice *device); |
158 | |
159 | enum State { |
160 | Error, |
161 | Ready, |
162 | ReadHeader, |
163 | ReadChannels, |
164 | }; |
165 | |
166 | SoftimagePICHandler() |
167 | : m_state(Ready) |
168 | , m_compression(true) |
169 | { |
170 | } |
171 | |
172 | bool readHeader(); |
173 | bool readChannels(); |
174 | |
175 | private: |
176 | State m_state; |
177 | QDataStream m_dataStream; |
178 | PicHeader m_header; |
179 | QList<PicChannel> m_channels; |
180 | // mostly used for writing: |
181 | bool m_compression; |
182 | QByteArray m_description; |
183 | }; |
184 | |
185 | class SoftimagePICPlugin : public QImageIOPlugin |
186 | { |
187 | Q_OBJECT |
188 | Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QImageIOHandlerFactoryInterface" FILE "pic.json" ) |
189 | |
190 | public: |
191 | Capabilities capabilities(QIODevice *device, const QByteArray &format) const override; |
192 | QImageIOHandler *create(QIODevice *device, const QByteArray &format = QByteArray()) const override; |
193 | }; |
194 | |
195 | #endif // KIMG_PIC_P_H |
196 | |