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 PicHeader {
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     PicHeader(quint16 _width, quint16 _height, const QByteArray &_comment = QByteArray())
magicPicHeader65         : 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. */
PicHeaderPicHeader76     PicHeader()
77     {
78     }
79 
80     quint32 magic; /**< Should be PIC_MAGIC_NUMBER */
81     float version; /**< Version of something (header? file format?) (ignored) */
82     QByteArray comment; /**< A free comment field (truncated to 80 bytes when
83                              written) */
84     QByteArray id; /**< The file format ID (should be "PICT") */
85     quint16 width; /**< The width of the image in pixels */
86     quint16 height; /**< The height of the image in pixels */
87     float ratio; /**< The aspect ratio: width/height of each individual pixel
88                       (ignored) */
89     PicFields fields; /**< The interlace type (ignored) */
90 
91     /**
92      * Returns true if the @p magic and @p id fields are set correctly.
93      */
isValidPicHeader94     bool isValid() 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 encodedLength = 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)
sizePicChannel126         : 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      */
PicChannelPicChannel140     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 
SoftimagePICHandler()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