Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qwbmphandler.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:critical reason:data-parser
4
6
7/*!
8 \class QWbmpHandler
9 \since 5.0
10 \brief The QWbmpHandler class provides support for the WBMP image format.
11 \internal
12*/
13
14#include <qimage.h>
15#include <qvariant.h>
16
18
19// This struct represents header of WBMP image file
21{
22 quint8 type; // Type of WBMP image (always equal to 0)
23 quint8 format; // Format of WBMP image
24 quint32 width; // Width of the image already decoded from multibyte integer
25 quint32 height; // Height of the image already decoded from multibyte integer
26};
27#define WBMPFIXEDHEADER_SIZE 2
28
29// Data renderers and writers which takes care of data alignment endiness and stuff
30static bool readMultiByteInt(QIODevice *iodev, quint32 *num)
31{
32 quint32 res = 0;
33
34 quint8 c;
35 unsigned int count = 0;
36 do {
37 // Do not allow to read longer
38 // then we can store in num
39 if (++count > sizeof(*num))
40 return false;
41
42 if (!iodev->getChar(reinterpret_cast<char *>(&c)))
43 return false;
44
45 res = (res << 7) | (c & 0x7F);
46
47 } while (c & 0x80);
48
49 *num = res;
50 return true;
51}
52
53static bool writeMultiByteInt(QIODevice *iodev, quint32 num)
54{
55 quint64 tmp = num & 0x7F;
56 num >>= 7;
57
58 while (num) {
59 quint8 c = num & 0x7F;
60 num = num >> 7;
61 tmp = (tmp << 8) | (c | 0x80);
62 }
63
64 while (tmp) {
65 quint8 c = tmp & 0xFF;
66 if (!iodev->putChar(c))
67 return false;
68 tmp >>= 8;
69 }
70 return true;
71}
72
73static bool readWBMPHeader(QIODevice *iodev, WBMPHeader *hdr)
74{
75 if (!iodev)
76 return false;
77
78 uchar tmp[WBMPFIXEDHEADER_SIZE];
79 if (iodev->read(reinterpret_cast<char *>(tmp), WBMPFIXEDHEADER_SIZE) == WBMPFIXEDHEADER_SIZE) {
80 hdr->type = tmp[0];
81 hdr->format = tmp[1];
82 } else {
83 return false;
84 }
85
86 if (readMultiByteInt(iodev, &hdr->width)
87 && readMultiByteInt(iodev, &hdr->height)) {
88 return true;
89 }
90 return false;
91}
92
93static bool writeWBMPHeader(QIODevice *iodev, const WBMPHeader &hdr)
94{
95 if (iodev) {
96 uchar tmp[WBMPFIXEDHEADER_SIZE];
97 tmp[0] = hdr.type;
98 tmp[1] = hdr.format;
99 if (iodev->write(reinterpret_cast<char *>(tmp), WBMPFIXEDHEADER_SIZE) != WBMPFIXEDHEADER_SIZE)
100 return false;
101
102 if (writeMultiByteInt(iodev, hdr.width) &&
103 writeMultiByteInt(iodev, hdr.height))
104 return true;
105 }
106 return false;
107}
108
109static bool writeWBMPData(QIODevice *iodev, const QImage &image)
110{
111 if (iodev) {
112 int h = image.height();
113 int bpl = (image.width() + 7) / 8;
114
115 for (int l=0; l<h; l++) {
116 if (iodev->write(reinterpret_cast<const char *>(image.constScanLine(l)), bpl) != bpl)
117 return false;
118 }
119 return true;
120 }
121 return false;
122}
123
124static bool readWBMPData(QIODevice *iodev, QImage &image)
125{
126 if (iodev) {
127 int h = image.height();
128 int bpl = (image.width() + 7) / 8;
129
130 for (int l = 0; l < h; l++) {
131 if (iodev->read(reinterpret_cast<char *>(image.scanLine(l)), bpl) != bpl)
132 return false;
133 }
134 return true;
135 }
136 return false;
137}
138
140{
141public:
142 WBMPReader(QIODevice *iodevice);
143
144 QImage readImage();
145 bool writeImage(QImage image);
146
147 static bool canRead(QIODevice *iodevice);
148
149private:
150 QIODevice *iodev;
151 WBMPHeader hdr;
152};
153
154// WBMP common reader and writer implementation
155WBMPReader::WBMPReader(QIODevice *iodevice) : iodev(iodevice)
156{
157 memset(&hdr, 0, sizeof(hdr));
158}
159
161{
162 if (!readWBMPHeader(iodev, &hdr))
163 return QImage();
164
165 QImage image;
166 if (!QImageIOHandler::allocateImage(QSize(hdr.width, hdr.height), QImage::Format_Mono, &image))
167 return QImage();
168 if (!readWBMPData(iodev, image))
169 return QImage();
170
171 return image;
172}
173
174bool WBMPReader::writeImage(QImage image)
175{
176 if (image.format() != QImage::Format_Mono)
177 image = image.convertToFormat(QImage::Format_Mono);
178
179 if (image.colorTable().at(0) == image.colorTable().at(1)) {
180 // degenerate image: actually blank.
181 image.fill((qGray(image.colorTable().at(0)) < 128) ? 0 : 1);
182 } else if (qGray(image.colorTable().at(0)) > qGray(image.colorTable().at(1))) {
183 // Conform to WBMP's convention about black and white
184 image.invertPixels();
185 }
186
187 hdr.type = 0;
188 hdr.format = 0;
189 hdr.width = image.width();
190 hdr.height = image.height();
191
192 if (!writeWBMPHeader(iodev, hdr))
193 return false;
194
195 if (!writeWBMPData(iodev, image))
196 return false;
197
198 return true;
199}
200
201bool WBMPReader::canRead(QIODevice *device)
202{
203 if (device) {
204
205 if (device->isSequential())
206 return false;
207
208 // Save previous position
209 qint64 oldPos = device->pos();
210
211 WBMPHeader hdr;
212 if (readWBMPHeader(device, &hdr)) {
213 if ((hdr.type == 0) && (hdr.format == 0)) {
214 const qint64 imageSize = hdr.height * ((qint64(hdr.width) + 7) / 8);
215 qint64 available = device->bytesAvailable();
216 device->seek(oldPos);
217 return (imageSize == available);
218 }
219 }
220 device->seek(oldPos);
221 }
222 return false;
223}
224
225/*!
226 Constructs an instance of QWbmpHandler initialized to use \a device.
227*/
228QWbmpHandler::QWbmpHandler(QIODevice *device) :
229 m_reader(new WBMPReader(device))
230{
231}
232
233/*!
234 Destructor for QWbmpHandler.
235*/
237{
238 delete m_reader;
239}
240
241/*!
242 * Verifies if some values (magic bytes) are set as expected in the header of the file.
243 * If the magic bytes were found, it is assumed that the QWbmpHandler can read the file.
244 */
246{
247 bool bCanRead = false;
248
249 QIODevice *device = QImageIOHandler::device();
250 if (device) {
251 bCanRead = QWbmpHandler::canRead(device);
252 if (bCanRead)
253 setFormat("wbmp");
254
255 } else {
256 qWarning("QWbmpHandler::canRead() called with no device");
257 }
258
259 return bCanRead;
260}
261
262/*! \reimp
263*/
264bool QWbmpHandler::read(QImage *image)
265{
266 bool bSuccess = false;
267 QImage img = m_reader->readImage();
268
269 if (!img.isNull()) {
270 bSuccess = true;
271 *image = img;
272 }
273
274 return bSuccess;
275}
276
277/*! \reimp
278*/
279bool QWbmpHandler::write(const QImage &image)
280{
281 if (image.isNull())
282 return false;
283
284 return m_reader->writeImage(image);
285}
286
287/*!
288 Only Size option is supported
289*/
290QVariant QWbmpHandler::option(ImageOption option) const
291{
292 if (option == QImageIOHandler::Size) {
293 QIODevice *device = QImageIOHandler::device();
294 if (device->isSequential())
295 return QVariant();
296
297 // Save old position
298 qint64 oldPos = device->pos();
299
300 WBMPHeader hdr;
301 if (readWBMPHeader(device, &hdr)) {
302 device->seek(oldPos);
303 return QSize(hdr.width, hdr.height);
304 }
305
306 device->seek(oldPos);
307
308 } else if (option == QImageIOHandler::ImageFormat) {
309 return QVariant(QImage::Format_Mono);
310 }
311
312 return QVariant();
313}
314
316{
317 return (option == QImageIOHandler::Size) ||
318 (option == QImageIOHandler::ImageFormat);
319}
320
321bool QWbmpHandler::canRead(QIODevice *device)
322{
323 return WBMPReader::canRead(device);
324}
325
326QT_END_NAMESPACE
ImageOption
This enum describes the different options supported by QImageIOHandler.
The QWbmpHandler class provides support for the WBMP image format.
bool canRead() const override
Verifies if some values (magic bytes) are set as expected in the header of the file.
QVariant option(ImageOption option) const override
Only Size option is supported.
~QWbmpHandler()
Destructor for QWbmpHandler.
bool supportsOption(ImageOption option) const override
Returns true if the QImageIOHandler supports the option option; otherwise returns false.
bool write(const QImage &image) override
\reimp
bool read(QImage *image) override
\reimp
QImage readImage()
bool writeImage(QImage image)
WBMPReader(QIODevice *iodevice)
static bool canRead(QIODevice *iodevice)
static bool writeWBMPData(QIODevice *iodev, const QImage &image)
static bool writeWBMPHeader(QIODevice *iodev, const WBMPHeader &hdr)
static bool writeMultiByteInt(QIODevice *iodev, quint32 num)
#define WBMPFIXEDHEADER_SIZE
static bool readMultiByteInt(QIODevice *iodev, quint32 *num)
static bool readWBMPHeader(QIODevice *iodev, WBMPHeader *hdr)
static bool readWBMPData(QIODevice *iodev, QImage &image)
quint32 width
quint32 height