Qt 4.8
qxbmhandler.cpp
Go to the documentation of this file.
1 /****************************************************************************
2 **
3 ** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the QtGui module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia. For licensing terms and
14 ** conditions see http://qt.digia.com/licensing. For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights. These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file. Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41 
42 #include <qplatformdefs.h>
43 #include "private/qxbmhandler_p.h"
44 
45 #ifndef QT_NO_IMAGEFORMAT_XBM
46 
47 #include <qimage.h>
48 #include <qiodevice.h>
49 #include <qvariant.h>
50 
51 #include <stdio.h>
52 #include <ctype.h>
53 
55 
56 /*****************************************************************************
57  X bitmap image read/write functions
58  *****************************************************************************/
59 
60 static inline int hex2byte(register char *p)
61 {
62  return ((isdigit((uchar) *p) ? *p - '0' : toupper((uchar) *p) - 'A' + 10) << 4) |
63  (isdigit((uchar) *(p+1)) ? *(p+1) - '0' : toupper((uchar) *(p+1)) - 'A' + 10);
64 }
65 
66 static bool read_xbm_header(QIODevice *device, int& w, int& h)
67 {
68  const int buflen = 300;
69  const int maxlen = 4096;
70  char buf[buflen + 1];
71  QRegExp r1(QLatin1String("^#define[ \t]+[a-zA-Z0-9._]+[ \t]+"));
72  QRegExp r2(QLatin1String("[0-9]+"));
73 
74  qint64 readBytes = 0;
75  qint64 totalReadBytes = 0;
76 
77  buf[0] = '\0';
78 
79  // skip initial comment, if any
80  while (buf[0] != '#') {
81  readBytes = device->readLine(buf, buflen);
82 
83  // if readBytes >= buflen, it's very probably not a C file
84  if (readBytes <= 0 || readBytes >= buflen -1)
85  return false;
86 
87  // limit xbm headers to the first 4k in the file to prevent
88  // excessive reads on non-xbm files
89  totalReadBytes += readBytes;
90  if (totalReadBytes >= maxlen)
91  return false;
92  }
93 
94  buf[readBytes - 1] = '\0';
95  QString sbuf;
96  sbuf = QString::fromLatin1(buf);
97 
98  // "#define .._width <num>"
99  if (r1.indexIn(sbuf) == 0 &&
100  r2.indexIn(sbuf, r1.matchedLength()) == r1.matchedLength())
101  w = QByteArray(&buf[r1.matchedLength()]).trimmed().toInt();
102 
103  // "#define .._height <num>"
104  readBytes = device->readLine(buf, buflen);
105  if (readBytes <= 0)
106  return false;
107  buf[readBytes - 1] = '\0';
108 
109  sbuf = QString::fromLatin1(buf);
110 
111  if (r1.indexIn(sbuf) == 0 &&
112  r2.indexIn(sbuf, r1.matchedLength()) == r1.matchedLength())
113  h = QByteArray(&buf[r1.matchedLength()]).trimmed().toInt();
114 
115  // format error
116  if (w <= 0 || w > 32767 || h <= 0 || h > 32767)
117  return false;
118 
119  return true;
120 }
121 
122 static bool read_xbm_body(QIODevice *device, int w, int h, QImage *outImage)
123 {
124  const int buflen = 300;
125  char buf[buflen + 1];
126 
127  qint64 readBytes = 0;
128 
129  // scan for database
130  for (;;) {
131  if ((readBytes = device->readLine(buf, buflen)) <= 0) {
132  // end of file
133  return false;
134  }
135 
136  buf[readBytes] = '\0';
137  if (QByteArray::fromRawData(buf, readBytes).contains("0x"))
138  break;
139  }
140 
141  if (outImage->size() != QSize(w, h) || outImage->format() != QImage::Format_MonoLSB) {
142  *outImage = QImage(w, h, QImage::Format_MonoLSB);
143  if (outImage->isNull())
144  return false;
145  }
146 
147  outImage->setColorCount(2);
148  outImage->setColor(0, qRgb(255,255,255)); // white
149  outImage->setColor(1, qRgb(0,0,0)); // black
150 
151  int x = 0, y = 0;
152  uchar *b = outImage->scanLine(0);
153  char *p = buf + QByteArray::fromRawData(buf, readBytes).indexOf("0x");
154  w = (w+7)/8; // byte width
155 
156  while (y < h) { // for all encoded bytes...
157  if (p) { // p = "0x.."
158  *b++ = hex2byte(p+2);
159  p += 2;
160  if (++x == w && ++y < h) {
161  b = outImage->scanLine(y);
162  x = 0;
163  }
164  p = strstr(p, "0x");
165  } else { // read another line
166  if ((readBytes = device->readLine(buf,buflen)) <= 0) // EOF ==> truncated image
167  break;
168  p = buf + QByteArray::fromRawData(buf, readBytes).indexOf("0x");
169  }
170  }
171 
172  return true;
173 }
174 
175 static bool read_xbm_image(QIODevice *device, QImage *outImage)
176 {
177  int w = 0, h = 0;
178  if (!read_xbm_header(device, w, h))
179  return false;
180  return read_xbm_body(device, w, h, outImage);
181 }
182 
183 static bool write_xbm_image(const QImage &sourceImage, QIODevice *device, const QString &fileName)
184 {
185  QImage image = sourceImage;
186  int w = image.width();
187  int h = image.height();
188  int i;
189  QString s = fileName; // get file base name
190  int msize = s.length() + 100;
191  char *buf = new char[msize];
192 
193  qsnprintf(buf, msize, "#define %s_width %d\n", s.toAscii().data(), w);
194  device->write(buf, qstrlen(buf));
195  qsnprintf(buf, msize, "#define %s_height %d\n", s.toAscii().data(), h);
196  device->write(buf, qstrlen(buf));
197  qsnprintf(buf, msize, "static char %s_bits[] = {\n ", s.toAscii().data());
198  device->write(buf, qstrlen(buf));
199 
200  if (image.format() != QImage::Format_MonoLSB)
202 
203  bool invert = qGray(image.color(0)) < qGray(image.color(1));
204  char hexrep[16];
205  for (i=0; i<10; i++)
206  hexrep[i] = '0' + i;
207  for (i=10; i<16; i++)
208  hexrep[i] = 'a' -10 + i;
209  if (invert) {
210  char t;
211  for (i=0; i<8; i++) {
212  t = hexrep[15-i];
213  hexrep[15-i] = hexrep[i];
214  hexrep[i] = t;
215  }
216  }
217  int bcnt = 0;
218  register char *p = buf;
219  int bpl = (w+7)/8;
220  for (int y = 0; y < h; ++y) {
221  uchar *b = image.scanLine(y);
222  for (i = 0; i < bpl; ++i) {
223  *p++ = '0'; *p++ = 'x';
224  *p++ = hexrep[*b >> 4];
225  *p++ = hexrep[*b++ & 0xf];
226 
227  if (i < bpl - 1 || y < h - 1) {
228  *p++ = ',';
229  if (++bcnt > 14) {
230  *p++ = '\n';
231  *p++ = ' ';
232  *p = '\0';
233  if ((int)qstrlen(buf) != device->write(buf, qstrlen(buf))) {
234  delete [] buf;
235  return false;
236  }
237  p = buf;
238  bcnt = 0;
239  }
240  }
241  }
242  }
243 #if defined(_MSC_VER) && _MSC_VER >= 1400
244  strcpy_s(p, sizeof(" };\n"), " };\n");
245 #else
246  strcpy(p, " };\n");
247 #endif
248  if ((int)qstrlen(buf) != device->write(buf, qstrlen(buf))) {
249  delete [] buf;
250  return false;
251  }
252 
253  delete [] buf;
254  return true;
255 }
256 
258  : state(Ready)
259 {
260 }
261 
263 {
264  state = Error;
266  return false;
267  state = ReadHeader;
268  return true;
269 }
270 
272 {
273  if (state == Ready && !canRead(device()))
274  return false;
275 
276  if (state != Error) {
277  setFormat("xbm");
278  return true;
279  }
280 
281  return false;
282 }
283 
285 {
286  QImage image;
287 
288  // it's impossible to tell whether we can load an XBM or not when
289  // it's from a sequential device, as the only way to do it is to
290  // attempt to parse the whole image.
291  if (device->isSequential())
292  return false;
293 
294  qint64 oldPos = device->pos();
295  bool success = read_xbm_image(device, &image);
296  device->seek(oldPos);
297 
298  return success;
299 }
300 
302 {
303  if (state == Error)
304  return false;
305 
306  if (state == Ready && !readHeader()) {
307  state = Error;
308  return false;
309  }
310 
311  if (!read_xbm_body(device(), width, height, image)) {
312  state = Error;
313  return false;
314  }
315 
316  state = Ready;
317  return true;
318 }
319 
320 bool QXbmHandler::write(const QImage &image)
321 {
322  return write_xbm_image(image, device(), fileName);
323 }
324 
326 {
327  return option == Name
328  || option == Size
329  || option == ImageFormat;
330 }
331 
333 {
334  if (option == Name) {
335  return fileName;
336  } else if (option == Size) {
337  if (state == Error)
338  return QVariant();
339  if (state == Ready && !const_cast<QXbmHandler*>(this)->readHeader())
340  return QVariant();
341  return QSize(width, height);
342  } else if (option == ImageFormat) {
343  return QImage::Format_MonoLSB;
344  }
345  return QVariant();
346 }
347 
349 {
350  if (option == Name)
351  fileName = value.toString();
352 }
353 
355 {
356  return "xbm";
357 }
358 
360 
361 #endif // QT_NO_IMAGEFORMAT_XBM
The QVariant class acts like a union for the most common Qt data types.
Definition: qvariant.h:92
void setFormat(const QByteArray &format)
Sets the format of the QImageIOHandler to format.
void setColor(int i, QRgb c)
Sets the color at the given index in the color table, to the given to colorValue. ...
Definition: qimage.cpp:1850
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
char * data()
Returns a pointer to the data stored in the byte array.
Definition: qbytearray.h:429
The QRegExp class provides pattern matching using regular expressions.
Definition: qregexp.h:61
int toInt(bool *ok=0, int base=10) const
Returns the string converted to an int using base base, which is 10 by default and must be between 2 ...
Definition: qstring.cpp:6090
static int hex2byte(register char *p)
Definition: qxbmhandler.cpp:60
bool isNull() const
Returns true if it is a null image, otherwise returns false.
Definition: qimage.cpp:1542
The QByteArray class provides an array of bytes.
Definition: qbytearray.h:135
int length() const
Returns the number of characters in this string.
Definition: qstring.h:696
virtual qint64 pos() const
For random-access devices, this function returns the position that data is written to or read from...
Definition: qiodevice.cpp:624
QString toString() const
Returns the variant as a QString if the variant has type() String , Bool , ByteArray ...
Definition: qvariant.cpp:2270
int matchedLength() const
Returns the length of the last matched string, or -1 if there was no match.
Definition: qregexp.cpp:4193
QLatin1String(DBUS_INTERFACE_DBUS))) Q_GLOBAL_STATIC_WITH_ARGS(QString
bool readHeader()
The QString class provides a Unicode character string.
Definition: qstring.h:83
static bool read_xbm_body(QIODevice *device, int w, int h, QImage *outImage)
void setOption(ImageOption option, const QVariant &value)
Sets the option option with the value value.
Format format() const
Returns the format of the image.
Definition: qimage.cpp:2305
static bool read_xbm_image(QIODevice *device, QImage *outImage)
bool write(const QImage &image)
Writes the image image to the assigned device.
unsigned char uchar
Definition: qglobal.h:994
static bool read_xbm_header(QIODevice *device, int &w, int &h)
Definition: qxbmhandler.cpp:66
void setColorCount(int)
Resizes the color table to contain colorCount entries.
Definition: qimage.cpp:2275
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
int indexIn(const QString &str, int offset=0, CaretMode caretMode=CaretAtZero) const
Attempts to find a match in str from position offset (0 by default).
Definition: qregexp.cpp:4136
ImageOption
This enum describes the different options supported by QImageIOHandler.
static QByteArray fromRawData(const char *, int size)
Constructs a QByteArray that uses the first size bytes of the data array.
The QImage class provides a hardware-independent image representation that allows direct access to th...
Definition: qimage.h:87
int qGray(int r, int g, int b)
Definition: qrgb.h:75
__int64 qint64
Definition: qglobal.h:942
QVariant option(ImageOption option) const
Returns the value assigned to option as a QVariant.
bool supportsOption(ImageOption option) const
Returns true if the QImageIOHandler supports the option option; otherwise returns false...
int indexOf(char c, int from=0) const
Returns the index position of the first occurrence of the character ch in the byte array...
static bool write_xbm_image(const QImage &sourceImage, QIODevice *device, const QString &fileName)
virtual bool isSequential() const
Returns true if this device is sequential; otherwise returns false.
Definition: qiodevice.cpp:454
QSize size() const
Returns the size of the image, i.
Definition: qimage.cpp:1587
QRgb qRgb(int r, int g, int b)
Returns the ARGB quadruplet (255, {r}, {g}, {b}).
Definition: qrgb.h:69
int width() const
Returns the width of the image.
Definition: qimage.cpp:1557
QImage convertToFormat(Format f, Qt::ImageConversionFlags flags=Qt::AutoColor) const Q_REQUIRED_RESULT
Returns a copy of the image in the given format.
Definition: qimage.cpp:3966
QString trimmed(QString source)
Definition: generator.cpp:233
qint64 readLine(char *data, qint64 maxlen)
This function reads a line of ASCII characters from the device, up to a maximum of maxSize - 1 bytes...
Definition: qiodevice.cpp:1110
static QString fromLatin1(const char *, int size=-1)
Returns a QString initialized with the first size characters of the Latin-1 string str...
Definition: qstring.cpp:4188
QString fileName
Definition: qxbmhandler_p.h:88
uint qstrlen(const char *str)
Definition: qbytearray.h:79
QByteArray toAscii() const Q_REQUIRED_RESULT
Returns an 8-bit representation of the string as a QByteArray.
Definition: qstring.cpp:4014
QIODevice * device() const
Returns the device currently assigned to the QImageIOHandler.
int qsnprintf(char *str, size_t n, const char *fmt,...)
A portable snprintf() function, calls qvsnprintf.
Definition: qvsnprintf.cpp:128
int height() const
Returns the height of the image.
Definition: qimage.cpp:1572
The QSize class defines the size of a two-dimensional object using integer point precision.
Definition: qsize.h:53
QByteArray name() const
Use format() instead.
qint64 write(const char *data, qint64 len)
Writes at most maxSize bytes of data from data to the device.
Definition: qiodevice.cpp:1342
bool canRead() const
Returns true if an image can be read from the device (i.
The QIODevice class is the base interface class of all I/O devices in Qt.
Definition: qiodevice.h:66
virtual bool seek(qint64 pos)
For random-access devices, this function sets the current position to pos, returning true on success...
Definition: qiodevice.cpp:659
static QString fileName(const QString &fileUrl)
QRgb color(int i) const
Returns the color in the color table at index i.
Definition: qimage.cpp:1829
uchar * scanLine(int)
Returns a pointer to the pixel data at the scanline with index i.
Definition: qimage.cpp:1886
QBool contains(char c) const
Returns true if the byte array contains the character ch; otherwise returns false.
Definition: qbytearray.h:525
bool read(QImage *image)
Read an image from the device, and stores it in image.