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 QImage img = m_reader->readImage();
267 if (img.isNull())
268 return false;
269 *image = std::move(img);
270 return true;
271}
272
273/*! \reimp
274*/
275bool QWbmpHandler::write(const QImage &image)
276{
277 if (image.isNull())
278 return false;
279
280 return m_reader->writeImage(image);
281}
282
283/*!
284 Only Size option is supported
285*/
286QVariant QWbmpHandler::option(ImageOption option) const
287{
288 if (option == QImageIOHandler::Size) {
289 QIODevice *device = QImageIOHandler::device();
290 if (device->isSequential())
291 return QVariant();
292
293 // Save old position
294 qint64 oldPos = device->pos();
295
296 WBMPHeader hdr;
297 if (readWBMPHeader(device, &hdr)) {
298 device->seek(oldPos);
299 return QSize(hdr.width, hdr.height);
300 }
301
302 device->seek(oldPos);
303
304 } else if (option == QImageIOHandler::ImageFormat) {
305 return QVariant(QImage::Format_Mono);
306 }
307
308 return QVariant();
309}
310
312{
313 return (option == QImageIOHandler::Size) ||
314 (option == QImageIOHandler::ImageFormat);
315}
316
317bool QWbmpHandler::canRead(QIODevice *device)
318{
319 return WBMPReader::canRead(device);
320}
321
322QT_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)
Combined button and popup list for selecting options.
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