Qt 4.8
qppmhandler.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 "private/qppmhandler_p.h"
43 
44 #ifndef QT_NO_IMAGEFORMAT_PPM
45 
46 #include <qimage.h>
47 #include <qvariant.h>
48 #include <qvector.h>
49 #include <ctype.h>
50 
52 
53 /*****************************************************************************
54  PBM/PGM/PPM (ASCII and RAW) image read/write functions
55  *****************************************************************************/
56 
57 static int read_pbm_int(QIODevice *d)
58 {
59  char c;
60  int val = -1;
61  bool digit;
62  const int buflen = 100;
63  char buf[buflen];
64  for (;;) {
65  if (!d->getChar(&c)) // end of file
66  break;
67  digit = isdigit((uchar) c);
68  if (val != -1) {
69  if (digit) {
70  val = 10*val + c - '0';
71  continue;
72  } else {
73  if (c == '#') // comment
74  d->readLine(buf, buflen);
75  break;
76  }
77  }
78  if (digit) // first digit
79  val = c - '0';
80  else if (isspace((uchar) c))
81  continue;
82  else if (c == '#')
83  (void)d->readLine(buf, buflen);
84  else
85  break;
86  }
87  return val;
88 }
89 
90 static bool read_pbm_header(QIODevice *device, char& type, int& w, int& h, int& mcc)
91 {
92  char buf[3];
93  if (device->read(buf, 3) != 3) // read P[1-6]<white-space>
94  return false;
95 
96  if (!(buf[0] == 'P' && isdigit((uchar) buf[1]) && isspace((uchar) buf[2])))
97  return false;
98 
99  type = buf[1];
100  if (type < '1' || type > '6')
101  return false;
102 
103  w = read_pbm_int(device); // get image width
104  h = read_pbm_int(device); // get image height
105 
106  if (type == '1' || type == '4')
107  mcc = 1; // ignore max color component
108  else
109  mcc = read_pbm_int(device); // get max color component
110 
111  if (w <= 0 || w > 32767 || h <= 0 || h > 32767 || mcc <= 0)
112  return false; // weird P.M image
113 
114  return true;
115 }
116 
117 static bool read_pbm_body(QIODevice *device, char type, int w, int h, int mcc, QImage *outImage)
118 {
119  int nbits, y;
120  int pbm_bpl;
121  bool raw;
122 
124  switch (type) {
125  case '1': // ascii PBM
126  case '4': // raw PBM
127  nbits = 1;
128  format = QImage::Format_Mono;
129  break;
130  case '2': // ascii PGM
131  case '5': // raw PGM
132  nbits = 8;
133  format = QImage::Format_Indexed8;
134  break;
135  case '3': // ascii PPM
136  case '6': // raw PPM
137  nbits = 32;
138  format = QImage::Format_RGB32;
139  break;
140  default:
141  return false;
142  }
143  raw = type >= '4';
144 
145  int maxc = mcc;
146  if (maxc > 255)
147  maxc = 255;
148  if (outImage->size() != QSize(w, h) || outImage->format() != format) {
149  *outImage = QImage(w, h, format);
150  if (outImage->isNull())
151  return false;
152  }
153 
154  pbm_bpl = (nbits*w+7)/8; // bytes per scanline in PBM
155 
156  if (raw) { // read raw data
157  if (nbits == 32) { // type 6
158  pbm_bpl = mcc < 256 ? 3*w : 6*w;
159  uchar *buf24 = new uchar[pbm_bpl], *b;
160  QRgb *p;
161  QRgb *end;
162  for (y=0; y<h; y++) {
163  if (device->read((char *)buf24, pbm_bpl) != pbm_bpl) {
164  delete[] buf24;
165  return false;
166  }
167  p = (QRgb *)outImage->scanLine(y);
168  end = p + w;
169  b = buf24;
170  while (p < end) {
171  if (mcc < 256) {
172  *p++ = qRgb(b[0],b[1],b[2]);
173  b += 3;
174  } else {
175  *p++ = qRgb(((int(b[0]) * 256 + int(b[1]) + 1) * 256) / (mcc + 1) - 1,
176  ((int(b[2]) * 256 + int(b[3]) + 1) * 256) / (mcc + 1) - 1,
177  ((int(b[4]) * 256 + int(b[5]) + 1) * 256) / (mcc + 1) - 1);
178  b += 6;
179  }
180  }
181  }
182  delete[] buf24;
183  } else { // type 4,5
184  for (y=0; y<h; y++) {
185  if (device->read((char *)outImage->scanLine(y), pbm_bpl)
186  != pbm_bpl)
187  return false;
188  }
189  }
190  } else { // read ascii data
191  register uchar *p;
192  int n;
193  for (y=0; y<h; y++) {
194  p = outImage->scanLine(y);
195  n = pbm_bpl;
196  if (nbits == 1) {
197  int b;
198  int bitsLeft = w;
199  while (n--) {
200  b = 0;
201  for (int i=0; i<8; i++) {
202  if (i < bitsLeft)
203  b = (b << 1) | (read_pbm_int(device) & 1);
204  else
205  b = (b << 1) | (0 & 1); // pad it our self if we need to
206  }
207  bitsLeft -= 8;
208  *p++ = b;
209  }
210  } else if (nbits == 8) {
211  if (mcc == maxc) {
212  while (n--) {
213  *p++ = read_pbm_int(device);
214  }
215  } else {
216  while (n--) {
217  *p++ = read_pbm_int(device) * maxc / mcc;
218  }
219  }
220  } else { // 32 bits
221  n /= 4;
222  int r, g, b;
223  if (mcc == maxc) {
224  while (n--) {
225  r = read_pbm_int(device);
226  g = read_pbm_int(device);
227  b = read_pbm_int(device);
228  *((QRgb*)p) = qRgb(r, g, b);
229  p += 4;
230  }
231  } else {
232  while (n--) {
233  r = read_pbm_int(device) * maxc / mcc;
234  g = read_pbm_int(device) * maxc / mcc;
235  b = read_pbm_int(device) * maxc / mcc;
236  *((QRgb*)p) = qRgb(r, g, b);
237  p += 4;
238  }
239  }
240  }
241  }
242  }
243 
244  if (nbits == 1) { // bitmap
245  outImage->setColorCount(2);
246  outImage->setColor(0, qRgb(255,255,255)); // white
247  outImage->setColor(1, qRgb(0,0,0)); // black
248  } else if (nbits == 8) { // graymap
249  outImage->setColorCount(maxc+1);
250  for (int i=0; i<=maxc; i++)
251  outImage->setColor(i, qRgb(i*255/maxc,i*255/maxc,i*255/maxc));
252  }
253 
254  return true;
255 }
256 
257 static bool write_pbm_image(QIODevice *out, const QImage &sourceImage, const QByteArray &sourceFormat)
258 {
259  QByteArray str;
260  QImage image = sourceImage;
261  QByteArray format = sourceFormat;
262 
263  format = format.left(3); // ignore RAW part
264  bool gray = format == "pgm";
265 
266  if (format == "pbm") {
267  image = image.convertToFormat(QImage::Format_Mono);
268  } else if (image.depth() == 1) {
270  } else {
271  switch (image.format()) {
277  image = image.convertToFormat(QImage::Format_RGB32);
278  break;
283  image = image.convertToFormat(QImage::Format_ARGB32);
284  break;
285  default:
286  break;
287  }
288  }
289 
290  if (image.depth() == 1 && image.colorCount() == 2) {
291  if (qGray(image.color(0)) < qGray(image.color(1))) {
292  // 0=dark/black, 1=light/white - invert
293  image.detach();
294  for (int y=0; y<image.height(); y++) {
295  uchar *p = image.scanLine(y);
296  uchar *end = p + image.bytesPerLine();
297  while (p < end)
298  *p++ ^= 0xff;
299  }
300  }
301  }
302 
303  uint w = image.width();
304  uint h = image.height();
305 
306  str = "P\n";
307  str += QByteArray::number(w);
308  str += ' ';
309  str += QByteArray::number(h);
310  str += '\n';
311 
312  switch (image.depth()) {
313  case 1: {
314  str.insert(1, '4');
315  if (out->write(str, str.length()) != str.length())
316  return false;
317  w = (w+7)/8;
318  for (uint y=0; y<h; y++) {
319  uchar* line = image.scanLine(y);
320  if (w != (uint)out->write((char*)line, w))
321  return false;
322  }
323  }
324  break;
325 
326  case 8: {
327  str.insert(1, gray ? '5' : '6');
328  str.append("255\n");
329  if (out->write(str, str.length()) != str.length())
330  return false;
331  QVector<QRgb> color = image.colorTable();
332  uint bpl = w*(gray ? 1 : 3);
333  uchar *buf = new uchar[bpl];
334  for (uint y=0; y<h; y++) {
335  uchar *b = image.scanLine(y);
336  uchar *p = buf;
337  uchar *end = buf+bpl;
338  if (gray) {
339  while (p < end) {
340  uchar g = (uchar)qGray(color[*b++]);
341  *p++ = g;
342  }
343  } else {
344  while (p < end) {
345  QRgb rgb = color[*b++];
346  *p++ = qRed(rgb);
347  *p++ = qGreen(rgb);
348  *p++ = qBlue(rgb);
349  }
350  }
351  if (bpl != (uint)out->write((char*)buf, bpl))
352  return false;
353  }
354  delete [] buf;
355  }
356  break;
357 
358  case 32: {
359  str.insert(1, gray ? '5' : '6');
360  str.append("255\n");
361  if (out->write(str, str.length()) != str.length())
362  return false;
363  uint bpl = w*(gray ? 1 : 3);
364  uchar *buf = new uchar[bpl];
365  for (uint y=0; y<h; y++) {
366  QRgb *b = (QRgb*)image.scanLine(y);
367  uchar *p = buf;
368  uchar *end = buf+bpl;
369  if (gray) {
370  while (p < end) {
371  uchar g = (uchar)qGray(*b++);
372  *p++ = g;
373  }
374  } else {
375  while (p < end) {
376  QRgb rgb = *b++;
377  *p++ = qRed(rgb);
378  *p++ = qGreen(rgb);
379  *p++ = qBlue(rgb);
380  }
381  }
382  if (bpl != (uint)out->write((char*)buf, bpl))
383  return false;
384  }
385  delete [] buf;
386  }
387  break;
388 
389  default:
390  return false;
391  }
392 
393  return true;
394 }
395 
397  : state(Ready)
398 {
399 }
400 
402 {
403  state = Error;
405  return false;
406  state = ReadHeader;
407  return true;
408 }
409 
411 {
412  if (state == Ready && !canRead(device(), &subType))
413  return false;
414 
415  if (state != Error) {
417  return true;
418  }
419 
420  return false;
421 }
422 
424 {
425  if (!device) {
426  qWarning("QPpmHandler::canRead() called with no device");
427  return false;
428  }
429 
430  char head[2];
431  if (device->peek(head, sizeof(head)) != sizeof(head))
432  return false;
433 
434  if (head[0] != 'P')
435  return false;
436 
437  if (head[1] == '1' || head[1] == '4') {
438  if (subType)
439  *subType = "pbm";
440  } else if (head[1] == '2' || head[1] == '5') {
441  if (subType)
442  *subType = "pgm";
443  } else if (head[1] == '3' || head[1] == '6') {
444  if (subType)
445  *subType = "ppm";
446  } else {
447  return false;
448  }
449  return true;
450 }
451 
453 {
454  if (state == Error)
455  return false;
456 
457  if (state == Ready && !readHeader()) {
458  state = Error;
459  return false;
460  }
461 
462  if (!read_pbm_body(device(), type, width, height, mcc, image)) {
463  state = Error;
464  return false;
465  }
466 
467  state = Ready;
468  return true;
469 }
470 
471 bool QPpmHandler::write(const QImage &image)
472 {
473  return write_pbm_image(device(), image, subType);
474 }
475 
477 {
478  return option == SubType
479  || option == Size
480  || option == ImageFormat;
481 }
482 
484 {
485  if (option == SubType) {
486  return subType;
487  } else if (option == Size) {
488  if (state == Error)
489  return QVariant();
490  if (state == Ready && !const_cast<QPpmHandler*>(this)->readHeader())
491  return QVariant();
492  return QSize(width, height);
493  } else if (option == ImageFormat) {
494  if (state == Error)
495  return QVariant();
496  if (state == Ready && !const_cast<QPpmHandler*>(this)->readHeader())
497  return QVariant();
499  switch (type) {
500  case '1': // ascii PBM
501  case '4': // raw PBM
502  format = QImage::Format_Mono;
503  break;
504  case '2': // ascii PGM
505  case '5': // raw PGM
506  format = QImage::Format_Indexed8;
507  break;
508  case '3': // ascii PPM
509  case '6': // raw PPM
510  format = QImage::Format_RGB32;
511  break;
512  default:
513  break;
514  }
515  return format;
516  }
517  return QVariant();
518 }
519 
521 {
522  if (option == SubType)
523  subType = value.toByteArray().toLower();
524 }
525 
527 {
528  return subType.isEmpty() ? QByteArray("ppm") : subType;
529 }
530 
532 
533 #endif // QT_NO_IMAGEFORMAT_PPM
The QVariant class acts like a union for the most common Qt data types.
Definition: qvariant.h:92
bool supportsOption(ImageOption option) const
Returns true if the QImageIOHandler supports the option option; otherwise returns false...
double d
Definition: qnumeric_p.h:62
static int read_pbm_int(QIODevice *d)
Definition: qppmhandler.cpp:57
Format
The following image formats are available in Qt.
Definition: qimage.h:91
unsigned int QRgb
Definition: qrgb.h:53
void setFormat(const QByteArray &format)
Sets the format of the QImageIOHandler to format.
int type
Definition: qmetatype.cpp:239
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
unsigned char c[8]
Definition: qnumeric_p.h:62
#define QT_END_NAMESPACE
This macro expands to.
Definition: qglobal.h:90
QByteArray & append(char c)
Appends the character ch to this byte array.
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
bool readHeader()
bool getChar(char *c)
Reads one character from the device and stores it in c.
Definition: qiodevice.cpp:1536
QByteArray toLower() const
Returns a lowercase copy of the byte array.
int bytesPerLine() const
Returns the number of bytes per image scanline.
Definition: qimage.cpp:1812
int qRed(QRgb rgb)
Returns the red component of the ARGB quadruplet rgb.
Definition: qrgb.h:57
QByteArray toByteArray() const
Returns the variant as a QByteArray if the variant has type() ByteArray or String (converted using QS...
Definition: qvariant.cpp:2383
Format format() const
Returns the format of the image.
Definition: qimage.cpp:2305
QByteArray format() const
Returns the format that is currently assigned to QImageIOHandler.
qint64 read(char *data, qint64 maxlen)
Reads at most maxSize bytes from the device into data, and returns the number of bytes read...
Definition: qiodevice.cpp:791
QVariant option(ImageOption option) const
Returns the value assigned to option as a QVariant.
unsigned char uchar
Definition: qglobal.h:994
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
QByteArray name() const
Use format() instead.
ImageOption
This enum describes the different options supported by QImageIOHandler.
qint64 peek(char *data, qint64 maxlen)
Reads at most maxSize bytes from the device into data, without side effects (i.
Definition: qiodevice.cpp:1563
void detach()
If multiple images share common data, this image makes a copy of the data and detaches itself from th...
Definition: qimage.cpp:1359
Q_CORE_EXPORT void qWarning(const char *,...)
The QImage class provides a hardware-independent image representation that allows direct access to th...
Definition: qimage.h:87
unsigned int uint
Definition: qglobal.h:996
int qGray(int r, int g, int b)
Definition: qrgb.h:75
bool write(const QImage &image)
Writes the image image to the assigned device.
int depth() const
Returns the depth of the image.
Definition: qimage.cpp:1620
QByteArray left(int len) const
Returns a byte array that contains the leftmost len bytes of this byte array.
static bool read_pbm_body(QIODevice *device, char type, int w, int h, int mcc, QImage *outImage)
QSize size() const
Returns the size of the image, i.
Definition: qimage.cpp:1587
#define rgb(r, g, b)
Definition: qcolor_p.cpp:130
int length() const
Same as size().
Definition: qbytearray.h:356
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
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
int colorCount() const
Returns the size of the color table for the image.
Definition: qimage.cpp:1656
bool read(QImage *image)
Read an image from the device, and stores it in image.
static bool write_pbm_image(QIODevice *out, const QImage &sourceImage, const QByteArray &sourceFormat)
QIODevice * device() const
Returns the device currently assigned to the QImageIOHandler.
int height() const
Returns the height of the image.
Definition: qimage.cpp:1572
bool isEmpty() const
Returns true if the byte array has size 0; otherwise returns false.
Definition: qbytearray.h:421
The QSize class defines the size of a two-dimensional object using integer point precision.
Definition: qsize.h:53
void setOption(ImageOption option, const QVariant &value)
Sets the option option with the value value.
QByteArray subType
Definition: qppmhandler_p.h:91
qint64 write(const char *data, qint64 len)
Writes at most maxSize bytes of data from data to the device.
Definition: qiodevice.cpp:1342
int qGreen(QRgb rgb)
Returns the green component of the ARGB quadruplet rgb.
Definition: qrgb.h:60
int qBlue(QRgb rgb)
Returns the blue component of the ARGB quadruplet rgb.
Definition: qrgb.h:63
static const KeyPair *const end
The QIODevice class is the base interface class of all I/O devices in Qt.
Definition: qiodevice.h:66
bool canRead() const
Returns true if an image can be read from the device (i.
static QByteArray number(int, int base=10)
Returns a byte array containing the string equivalent of the number n to base base (10 by default)...
QVector< QRgb > colorTable() const
Returns a list of the colors contained in the image&#39;s color table, or an empty list if the image does...
Definition: qimage.cpp:1770
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
static bool read_pbm_header(QIODevice *device, char &type, int &w, int &h, int &mcc)
Definition: qppmhandler.cpp:90
QByteArray & insert(int i, char c)
Inserts character ch at index position i in the byte array.