Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qxbmhandler.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
4#include <qplatformdefs.h>
5#include "private/qxbmhandler_p.h"
6
7#ifndef QT_NO_IMAGEFORMAT_XBM
8
9#include <qimage.h>
10#include <qiodevice.h>
11#include <qloggingcategory.h>
12#include <qvariant.h>
13#include <private/qtools_p.h>
14#include <private/qimage_p.h>
15#include <stdio.h>
16
18
19using namespace QtMiscUtils;
20
21/*****************************************************************************
22 X bitmap image read/write functions
23 *****************************************************************************/
24
25static inline int hex2byte(char *p)
26{
27 return QtMiscUtils::fromHex(p[0]) * 16 | QtMiscUtils::fromHex(p[1]);
28}
29
30static bool read_xbm_header(QIODevice *device, int& w, int& h)
31{
32 const int buflen = 300;
33 const int maxlen = 4096;
34 char buf[buflen + 1];
35
36 qint64 readBytes = 0;
37 qint64 totalReadBytes = 0;
38
39 buf[0] = '\0';
40
41 // skip initial comment, if any
42 while (buf[0] != '#') {
43 readBytes = device->readLine(buf, buflen);
44
45 // if readBytes >= buflen, it's very probably not a C file
46 if (readBytes <= 0 || readBytes >= buflen -1)
47 return false;
48
49 // limit xbm headers to the first 4k in the file to prevent
50 // excessive reads on non-xbm files
51 totalReadBytes += readBytes;
52 if (totalReadBytes >= maxlen)
53 return false;
54 }
55
56 auto parseDefine = [] (const char *buf, int len) -> int {
57 auto checkChar = [] (char ch) -> bool {
59 || ch == '_' || ch == '.';
60 };
61 auto isAsciiSpace = [] (char ch) -> bool {
62 return ch == ' ' || ch == '\t';
63 };
64 const char define[] = "#define";
65 constexpr size_t defineLen = sizeof(define) - 1;
66 if (strncmp(buf, define, defineLen) != 0)
67 return 0;
68 int index = defineLen;
69 while (buf[index] && isAsciiSpace(buf[index]))
70 ++index;
71 while (buf[index] && checkChar(buf[index]))
72 ++index;
73 while (buf[index] && isAsciiSpace(buf[index]))
74 ++index;
75
76 return QByteArray(buf + index, len - index).toInt();
77 };
78
79
80 // "#define .._width <num>"
81 w = parseDefine(buf, readBytes - 1);
82
83 readBytes = device->readLine(buf, buflen);
84 // "#define .._height <num>"
85 h = parseDefine(buf, readBytes - 1);
86
87 // format error
88 if (w <= 0 || w > 32767 || h <= 0 || h > 32767)
89 return false;
90
91 return true;
92}
93
94static bool read_xbm_body(QIODevice *device, int w, int h, QImage *outImage)
95{
96 const int buflen = 300;
97 char buf[buflen + 1];
98
99 qint64 readBytes = 0;
100
101 char *p;
102
103 // scan for database
104 do {
105 if ((readBytes = device->readLine(buf, buflen)) <= 0) {
106 // end of file
107 return false;
108 }
109
110 buf[readBytes] = '\0';
111 p = strstr(buf, "0x");
112 } while (!p);
113
115 return false;
116
117 outImage->fill(Qt::color0); // in case the image data does not cover the full image
118
119 outImage->setColorCount(2);
120 outImage->setColor(0, qRgb(255,255,255)); // white
121 outImage->setColor(1, qRgb(0,0,0)); // black
122
123 int x = 0, y = 0;
124 uchar *b = outImage->scanLine(0);
125 w = (w+7)/8; // byte width
126
127 while (y < h) { // for all encoded bytes...
128 if (p && p < (buf + readBytes - 3)) { // p = "0x.."
129 const int byte = hex2byte(p + 2);
130 if (byte < 0) // non-hex char encountered
131 return false;
132 *b++ = byte;
133 p += 2;
134 if (++x == w && ++y < h) {
135 b = outImage->scanLine(y);
136 x = 0;
137 }
138 p = strstr(p, "0x");
139 } else { // read another line
140 if ((readBytes = device->readLine(buf,buflen)) <= 0) // EOF ==> truncated image
141 break;
142 buf[readBytes] = '\0';
143 p = strstr(buf, "0x");
144 }
145 }
146
147 return true;
148}
149
150static bool read_xbm_image(QIODevice *device, QImage *outImage)
151{
152 int w = 0, h = 0;
153 if (!read_xbm_header(device, w, h))
154 return false;
155 return read_xbm_body(device, w, h, outImage);
156}
157
158static bool write_xbm_image(const QImage &sourceImage, QIODevice *device, const QString &fileName)
159{
160 QImage image = sourceImage;
161 int w = image.width();
162 int h = image.height();
163 int i;
164 QString s = fileName; // get file base name
165 int msize = s.size() + 100;
166 char *buf = new char[msize];
167
168 qsnprintf(buf, msize, "#define %s_width %d\n", s.toUtf8().data(), w);
169 device->write(buf, qstrlen(buf));
170 qsnprintf(buf, msize, "#define %s_height %d\n", s.toUtf8().data(), h);
171 device->write(buf, qstrlen(buf));
172 qsnprintf(buf, msize, "static char %s_bits[] = {\n ", s.toUtf8().data());
173 device->write(buf, qstrlen(buf));
174
175 if (image.format() != QImage::Format_MonoLSB)
176 image = image.convertToFormat(QImage::Format_MonoLSB);
177
178 bool invert = qGray(image.color(0)) < qGray(image.color(1));
179 char hexrep[16];
180 for (i=0; i<10; i++)
181 hexrep[i] = '0' + i;
182 for (i=10; i<16; i++)
183 hexrep[i] = 'a' -10 + i;
184 if (invert) {
185 char t;
186 for (i=0; i<8; i++) {
187 t = hexrep[15-i];
188 hexrep[15-i] = hexrep[i];
189 hexrep[i] = t;
190 }
191 }
192 int bcnt = 0;
193 char *p = buf;
194 int bpl = (w+7)/8;
195 for (int y = 0; y < h; ++y) {
196 const uchar *b = image.constScanLine(y);
197 for (i = 0; i < bpl; ++i) {
198 *p++ = '0'; *p++ = 'x';
199 *p++ = hexrep[*b >> 4];
200 *p++ = hexrep[*b++ & 0xf];
201
202 if (i < bpl - 1 || y < h - 1) {
203 *p++ = ',';
204 if (++bcnt > 14) {
205 *p++ = '\n';
206 *p++ = ' ';
207 *p = '\0';
208 if ((int)qstrlen(buf) != device->write(buf, qstrlen(buf))) {
209 delete [] buf;
210 return false;
211 }
212 p = buf;
213 bcnt = 0;
214 }
215 }
216 }
217 }
218#ifdef Q_CC_MSVC
219 strcpy_s(p, sizeof(" };\n"), " };\n");
220#else
221 strcpy(p, " };\n");
222#endif
223 if ((int)qstrlen(buf) != device->write(buf, qstrlen(buf))) {
224 delete [] buf;
225 return false;
226 }
227
228 delete [] buf;
229 return true;
230}
231
233 : state(Ready)
234{
235}
236
237bool QXbmHandler::readHeader()
238{
239 state = Error;
241 return false;
242 state = ReadHeader;
243 return true;
244}
245
247{
248 if (state == Ready && !canRead(device()))
249 return false;
250
251 if (state != Error) {
252 setFormat("xbm");
253 return true;
254 }
255
256 return false;
257}
258
260{
261 if (!device) {
262 qCWarning(lcImageIo, "QXbmHandler::canRead() called with no device");
263 return false;
264 }
265
266 // it's impossible to tell whether we can load an XBM or not when
267 // it's from a sequential device, as the only way to do it is to
268 // attempt to parse the whole image.
269 if (device->isSequential())
270 return false;
271
273 qint64 oldPos = device->pos();
274 bool success = read_xbm_image(device, &image);
275 device->seek(oldPos);
276
277 return success;
278}
279
281{
282 if (state == Error)
283 return false;
284
285 if (state == Ready && !readHeader()) {
286 state = Error;
287 return false;
288 }
289
291 state = Error;
292 return false;
293 }
294
295 state = Ready;
296 return true;
297}
298
300{
301 return write_xbm_image(image, device(), fileName);
302}
303
305{
306 return option == Name
307 || option == Size
308 || option == ImageFormat;
309}
310
312{
313 if (option == Name) {
314 return fileName;
315 } else if (option == Size) {
316 if (state == Error)
317 return QVariant();
318 if (state == Ready && !const_cast<QXbmHandler*>(this)->readHeader())
319 return QVariant();
320 return QSize(width, height);
321 } else if (option == ImageFormat) {
323 }
324 return QVariant();
325}
326
328{
329 if (option == Name)
330 fileName = value.toString();
331}
332
334
335#endif // QT_NO_IMAGEFORMAT_XBM
IOBluetoothDevice * device
\inmodule QtCore \reentrant
Definition qiodevice.h:34
virtual qint64 pos() const
For random-access devices, this function returns the position that data is written to or read from.
virtual bool isSequential() const
Returns true if this device is sequential; otherwise returns false.
virtual bool seek(qint64 pos)
For random-access devices, this function sets the current position to pos, returning true on success,...
ImageOption
This enum describes the different options supported by QImageIOHandler.
static bool allocateImage(QSize size, QImage::Format format, QImage *image)
QIODevice * device() const
Returns the device currently assigned to the QImageIOHandler.
void setFormat(const QByteArray &format)
Sets the format of the QImageIOHandler to format.
\inmodule QtGui
Definition qimage.h:37
@ Format_MonoLSB
Definition qimage.h:44
\inmodule QtCore
Definition qsize.h:25
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
qsizetype size() const noexcept
Returns the number of characters in this string.
Definition qstring.h:186
\inmodule QtCore
Definition qvariant.h:65
bool canRead() const override
Returns true if an image can be read from the device (i.e., the image format is supported,...
bool supportsOption(ImageOption option) const override
Returns true if the QImageIOHandler supports the option option; otherwise returns false.
bool write(const QImage &image) override
Writes the image image to the assigned device.
void setOption(ImageOption option, const QVariant &value) override
Sets the option option with the value value.
QVariant option(ImageOption option) const override
Returns the value assigned to option as a QVariant.
bool read(QImage *image) override
Read an image from the device, and stores it in image.
else opt state
[0]
std::list< QString >::iterator Name
Definition lalr.h:28
Combined button and popup list for selecting options.
constexpr bool isAsciiLetterOrNumber(char32_t c) noexcept
Definition qtools_p.h:82
constexpr int fromHex(char32_t c) noexcept
Definition qtools_p.h:44
@ color0
Definition qnamespace.h:28
Definition image.cpp:4
size_t qstrlen(const char *str)
Q_CORE_EXPORT int qsnprintf(char *str, size_t n, const char *fmt,...)
typedef QByteArray(EGLAPIENTRYP PFNQGSGETDISPLAYSPROC)()
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
#define qCWarning(category,...)
GLboolean GLboolean GLboolean b
GLint GLint GLint GLint GLint x
[0]
GLfloat GLfloat GLfloat w
[0]
GLint GLsizei GLsizei height
GLuint index
[2]
GLint GLsizei width
GLenum GLuint GLenum GLsizei const GLchar * buf
GLint y
GLfloat GLfloat GLfloat GLfloat h
GLdouble s
[6]
Definition qopenglext.h:235
GLdouble GLdouble t
Definition qopenglext.h:243
GLfloat GLfloat p
[1]
GLuint GLenum option
GLenum GLsizei len
GLboolean invert
Definition qopenglext.h:226
constexpr QRgb qRgb(int r, int g, int b)
Definition qrgb.h:30
constexpr int qGray(int r, int g, int b)
Definition qrgb.h:36
unsigned char uchar
Definition qtypes.h:32
long long qint64
Definition qtypes.h:60
static bool write_xbm_image(const QImage &sourceImage, QIODevice *device, const QString &fileName)
static bool read_xbm_body(QIODevice *device, int w, int h, QImage *outImage)
static bool read_xbm_header(QIODevice *device, int &w, int &h)
static bool read_xbm_image(QIODevice *device, QImage *outImage)
static int hex2byte(char *p)