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
15#include <stdio.h>
16
18
19using namespace QtMiscUtils;
20
22
23/*****************************************************************************
24 X bitmap image read/write functions
25 *****************************************************************************/
26
27static inline int hex2byte(char *p)
28{
29 return QtMiscUtils::fromHex(p[0]) * 16 | QtMiscUtils::fromHex(p[1]);
30}
31
32static bool read_xbm_header(QIODevice *device, int& w, int& h)
33{
34 const int buflen = 300;
35 const int maxlen = 4096;
36 char buf[buflen + 1];
37
38 qint64 readBytes = 0;
39 qint64 totalReadBytes = 0;
40
41 buf[0] = '\0';
42
43 // skip initial comment, if any
44 while (buf[0] != '#') {
45 readBytes = device->readLine(buf, buflen);
46
47 // if readBytes >= buflen, it's very probably not a C file
48 if (readBytes <= 0 || readBytes >= buflen -1)
49 return false;
50
51 // limit xbm headers to the first 4k in the file to prevent
52 // excessive reads on non-xbm files
53 totalReadBytes += readBytes;
54 if (totalReadBytes >= maxlen)
55 return false;
56 }
57
58 auto parseDefine = [] (const char *buf, int len) -> int {
59 auto checkChar = [] (char ch) -> bool {
61 || ch == '_' || ch == '.';
62 };
63 auto isAsciiSpace = [] (char ch) -> bool {
64 return ch == ' ' || ch == '\t';
65 };
66 const char define[] = "#define";
67 constexpr size_t defineLen = sizeof(define) - 1;
68 if (strncmp(buf, define, defineLen) != 0)
69 return 0;
70 int index = defineLen;
71 while (buf[index] && isAsciiSpace(buf[index]))
72 ++index;
73 while (buf[index] && checkChar(buf[index]))
74 ++index;
75 while (buf[index] && isAsciiSpace(buf[index]))
76 ++index;
77
78 return QByteArray(buf + index, len - index).toInt();
79 };
80
81
82 // "#define .._width <num>"
83 w = parseDefine(buf, readBytes - 1);
84
85 readBytes = device->readLine(buf, buflen);
86 // "#define .._height <num>"
87 h = parseDefine(buf, readBytes - 1);
88
89 // format error
90 if (w <= 0 || w > 32767 || h <= 0 || h > 32767)
91 return false;
92
93 return true;
94}
95
96static bool read_xbm_body(QIODevice *device, int w, int h, QImage *outImage)
97{
98 const int buflen = 300;
99 char buf[buflen + 1];
100
101 qint64 readBytes = 0;
102
103 char *p;
104
105 // scan for database
106 do {
107 if ((readBytes = device->readLine(buf, buflen)) <= 0) {
108 // end of file
109 return false;
110 }
111
112 buf[readBytes] = '\0';
113 p = strstr(buf, "0x");
114 } while (!p);
115
117 return false;
118
119 outImage->fill(Qt::color0); // in case the image data does not cover the full image
120
121 outImage->setColorCount(2);
122 outImage->setColor(0, qRgb(255,255,255)); // white
123 outImage->setColor(1, qRgb(0,0,0)); // black
124
125 int x = 0, y = 0;
126 uchar *b = outImage->scanLine(0);
127 w = (w+7)/8; // byte width
128
129 while (y < h) { // for all encoded bytes...
130 if (p && p < (buf + readBytes - 3)) { // p = "0x.."
131 const int byte = hex2byte(p + 2);
132 if (byte < 0) // non-hex char encountered
133 return false;
134 *b++ = byte;
135 p += 2;
136 if (++x == w && ++y < h) {
137 b = outImage->scanLine(y);
138 x = 0;
139 }
140 p = strstr(p, "0x");
141 } else { // read another line
142 if ((readBytes = device->readLine(buf,buflen)) <= 0) // EOF ==> truncated image
143 break;
144 buf[readBytes] = '\0';
145 p = strstr(buf, "0x");
146 }
147 }
148
149 return true;
150}
151
152static bool read_xbm_image(QIODevice *device, QImage *outImage)
153{
154 int w = 0, h = 0;
155 if (!read_xbm_header(device, w, h))
156 return false;
157 return read_xbm_body(device, w, h, outImage);
158}
159
160static bool write_xbm_image(const QImage &sourceImage, QIODevice *device, const QString &fileName)
161{
162 QImage image = sourceImage;
163 int w = image.width();
164 int h = image.height();
165 int i;
166 QString s = fileName; // get file base name
167 int msize = s.size() + 100;
168 char *buf = new char[msize];
169
170 qsnprintf(buf, msize, "#define %s_width %d\n", s.toUtf8().data(), w);
171 device->write(buf, qstrlen(buf));
172 qsnprintf(buf, msize, "#define %s_height %d\n", s.toUtf8().data(), h);
173 device->write(buf, qstrlen(buf));
174 qsnprintf(buf, msize, "static char %s_bits[] = {\n ", s.toUtf8().data());
175 device->write(buf, qstrlen(buf));
176
177 if (image.format() != QImage::Format_MonoLSB)
178 image = image.convertToFormat(QImage::Format_MonoLSB);
179
180 bool invert = qGray(image.color(0)) < qGray(image.color(1));
181 char hexrep[16];
182 for (i=0; i<10; i++)
183 hexrep[i] = '0' + i;
184 for (i=10; i<16; i++)
185 hexrep[i] = 'a' -10 + i;
186 if (invert) {
187 char t;
188 for (i=0; i<8; i++) {
189 t = hexrep[15-i];
190 hexrep[15-i] = hexrep[i];
191 hexrep[i] = t;
192 }
193 }
194 int bcnt = 0;
195 char *p = buf;
196 int bpl = (w+7)/8;
197 for (int y = 0; y < h; ++y) {
198 const uchar *b = image.constScanLine(y);
199 for (i = 0; i < bpl; ++i) {
200 *p++ = '0'; *p++ = 'x';
201 *p++ = hexrep[*b >> 4];
202 *p++ = hexrep[*b++ & 0xf];
203
204 if (i < bpl - 1 || y < h - 1) {
205 *p++ = ',';
206 if (++bcnt > 14) {
207 *p++ = '\n';
208 *p++ = ' ';
209 *p = '\0';
210 if ((int)qstrlen(buf) != device->write(buf, qstrlen(buf))) {
211 delete [] buf;
212 return false;
213 }
214 p = buf;
215 bcnt = 0;
216 }
217 }
218 }
219 }
220#ifdef Q_CC_MSVC
221 strcpy_s(p, sizeof(" };\n"), " };\n");
222#else
223 strcpy(p, " };\n");
224#endif
225 if ((int)qstrlen(buf) != device->write(buf, qstrlen(buf))) {
226 delete [] buf;
227 return false;
228 }
229
230 delete [] buf;
231 return true;
232}
233
235 : state(Ready)
236{
237}
238
239bool QXbmHandler::readHeader()
240{
241 state = Error;
243 return false;
244 state = ReadHeader;
245 return true;
246}
247
249{
250 if (state == Ready && !canRead(device()))
251 return false;
252
253 if (state != Error) {
254 setFormat("xbm");
255 return true;
256 }
257
258 return false;
259}
260
262{
263 if (!device) {
264 qCWarning(lcImageIo, "QXbmHandler::canRead() called with no device");
265 return false;
266 }
267
268 // it's impossible to tell whether we can load an XBM or not when
269 // it's from a sequential device, as the only way to do it is to
270 // attempt to parse the whole image.
271 if (device->isSequential())
272 return false;
273
275 qint64 oldPos = device->pos();
276 bool success = read_xbm_image(device, &image);
277 device->seek(oldPos);
278
279 return success;
280}
281
283{
284 if (state == Error)
285 return false;
286
287 if (state == Ready && !readHeader()) {
288 state = Error;
289 return false;
290 }
291
293 state = Error;
294 return false;
295 }
296
297 state = Ready;
298 return true;
299}
300
302{
303 return write_xbm_image(image, device(), fileName);
304}
305
307{
308 return option == Name
309 || option == Size
310 || option == ImageFormat;
311}
312
314{
315 if (option == Name) {
316 return fileName;
317 } else if (option == Size) {
318 if (state == Error)
319 return QVariant();
320 if (state == Ready && !const_cast<QXbmHandler*>(this)->readHeader())
321 return QVariant();
322 return QSize(width, height);
323 } else if (option == ImageFormat) {
325 }
326 return QVariant();
327}
328
330{
331 if (option == Name)
332 fileName = value.toString();
333}
334
336
337#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,...)
#define Q_DECLARE_LOGGING_CATEGORY(name)
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)