Qt 4.8
qbmphandler.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/qbmphandler_p.h"
43 
44 #ifndef QT_NO_IMAGEFORMAT_BMP
45 
46 #include <qimage.h>
47 #include <qvariant.h>
48 #include <qvector.h>
49 
51 
52 static void swapPixel01(QImage *image) // 1-bpp: swap 0 and 1 pixels
53 {
54  int i;
55  if (image->depth() == 1 && image->colorCount() == 2) {
56  register uint *p = (uint *)image->bits();
57  int nbytes = image->byteCount();
58  for (i=0; i<nbytes/4; i++) {
59  *p = ~*p;
60  p++;
61  }
62  uchar *p2 = (uchar *)p;
63  for (i=0; i<(nbytes&3); i++) {
64  *p2 = ~*p2;
65  p2++;
66  }
67  QRgb t = image->color(0); // swap color 0 and 1
68  image->setColor(0, image->color(1));
69  image->setColor(1, t);
70  }
71 }
72 
73 /*
74  QImageIO::defineIOHandler("BMP", "^BM", 0,
75  read_bmp_image, write_bmp_image);
76 */
77 
78 /*****************************************************************************
79  BMP (DIB) image read/write functions
80  *****************************************************************************/
81 
82 const int BMP_FILEHDR_SIZE = 14; // size of BMP_FILEHDR data
83 
85 { // read file header
86  s.readRawData(bf.bfType, 2);
87  s >> bf.bfSize >> bf.bfReserved1 >> bf.bfReserved2 >> bf.bfOffBits;
88  return s;
89 }
90 
92 { // write file header
93  s.writeRawData(bf.bfType, 2);
94  s << bf.bfSize << bf.bfReserved1 << bf.bfReserved2 << bf.bfOffBits;
95  return s;
96 }
97 
98 
99 const int BMP_OLD = 12; // old Windows/OS2 BMP size
100 const int BMP_WIN = 40; // Windows BMP v3 size
101 const int BMP_OS2 = 64; // new OS/2 BMP size
102 const int BMP_WIN4 = 108; // Windows BMP v4 size
103 const int BMP_WIN5 = 124; // Windows BMP v5 size
104 
105 const int BMP_RGB = 0; // no compression
106 const int BMP_RLE8 = 1; // run-length encoded, 8 bits
107 const int BMP_RLE4 = 2; // run-length encoded, 4 bits
108 const int BMP_BITFIELDS = 3; // RGB values encoded in data as bit-fields
109 
110 
112 {
113  s >> bi.biSize;
114  if (bi.biSize == BMP_WIN || bi.biSize == BMP_OS2 || bi.biSize == BMP_WIN4 || bi.biSize == BMP_WIN5) {
115  s >> bi.biWidth >> bi.biHeight >> bi.biPlanes >> bi.biBitCount;
116  s >> bi.biCompression >> bi.biSizeImage;
117  s >> bi.biXPelsPerMeter >> bi.biYPelsPerMeter;
118  s >> bi.biClrUsed >> bi.biClrImportant;
119  }
120  else { // probably old Windows format
121  qint16 w, h;
122  s >> w >> h >> bi.biPlanes >> bi.biBitCount;
123  bi.biWidth = w;
124  bi.biHeight = h;
125  bi.biCompression = BMP_RGB; // no compression
126  bi.biSizeImage = 0;
127  bi.biXPelsPerMeter = bi.biYPelsPerMeter = 0;
128  bi.biClrUsed = bi.biClrImportant = 0;
129  }
130  return s;
131 }
132 
134 {
135  s << bi.biSize;
136  s << bi.biWidth << bi.biHeight;
137  s << bi.biPlanes;
138  s << bi.biBitCount;
139  s << bi.biCompression;
140  s << bi.biSizeImage;
141  s << bi.biXPelsPerMeter << bi.biYPelsPerMeter;
142  s << bi.biClrUsed << bi.biClrImportant;
143  return s;
144 }
145 
146 static int calc_shift(uint mask)
147 {
148  int result = 0;
149  while (mask && !(mask & 1)) {
150  result++;
151  mask >>= 1;
152  }
153  return result;
154 }
155 
157 {
158  // read BMP file header
159  s >> bf;
160  if (s.status() != QDataStream::Ok)
161  return false;
162 
163  // check header
164  if (qstrncmp(bf.bfType,"BM",2) != 0)
165  return false;
166 
167  return true;
168 }
169 
171 {
172  s >> bi; // read BMP info header
173  if (s.status() != QDataStream::Ok)
174  return false;
175 
176  int nbits = bi.biBitCount;
177  int comp = bi.biCompression;
178  if (!(nbits == 1 || nbits == 4 || nbits == 8 || nbits == 16 || nbits == 24 || nbits == 32) ||
179  bi.biPlanes != 1 || comp > BMP_BITFIELDS)
180  return false; // weird BMP image
181  if (!(comp == BMP_RGB || (nbits == 4 && comp == BMP_RLE4) ||
182  (nbits == 8 && comp == BMP_RLE8) || ((nbits == 16 || nbits == 32) && comp == BMP_BITFIELDS)))
183  return false; // weird compression type
184 
185  return true;
186 }
187 
188 static bool read_dib_body(QDataStream &s, const BMP_INFOHDR &bi, int offset, int startpos, QImage &image)
189 {
190  QIODevice* d = s.device();
191  if (d->atEnd()) // end of stream/file
192  return false;
193 #if 0
194  qDebug("offset...........%d", offset);
195  qDebug("startpos.........%d", startpos);
196  qDebug("biSize...........%d", bi.biSize);
197  qDebug("biWidth..........%d", bi.biWidth);
198  qDebug("biHeight.........%d", bi.biHeight);
199  qDebug("biPlanes.........%d", bi.biPlanes);
200  qDebug("biBitCount.......%d", bi.biBitCount);
201  qDebug("biCompression....%d", bi.biCompression);
202  qDebug("biSizeImage......%d", bi.biSizeImage);
203  qDebug("biXPelsPerMeter..%d", bi.biXPelsPerMeter);
204  qDebug("biYPelsPerMeter..%d", bi.biYPelsPerMeter);
205  qDebug("biClrUsed........%d", bi.biClrUsed);
206  qDebug("biClrImportant...%d", bi.biClrImportant);
207 #endif
208  int w = bi.biWidth, h = bi.biHeight, nbits = bi.biBitCount;
209  int t = bi.biSize, comp = bi.biCompression;
210  uint red_mask = 0;
211  uint green_mask = 0;
212  uint blue_mask = 0;
213  int red_shift = 0;
214  int green_shift = 0;
215  int blue_shift = 0;
216  int red_scale = 0;
217  int green_scale = 0;
218  int blue_scale = 0;
219 
220  int ncols = 0;
221  int depth = 0;
223  switch (nbits) {
224  case 32:
225  case 24:
226  case 16:
227  depth = 32;
228  format = QImage::Format_RGB32;
229  break;
230  case 8:
231  case 4:
232  depth = 8;
233  format = QImage::Format_Indexed8;
234  break;
235  default:
236  depth = 1;
237  format = QImage::Format_Mono;
238  }
239 
240  if (bi.biHeight < 0)
241  h = -h; // support images with negative height
242 
243  if (image.size() != QSize(w, h) || image.format() != format) {
244  image = QImage(w, h, format);
245  if (image.isNull()) // could not create image
246  return false;
247  }
248 
249  if (depth != 32) {
250  ncols = bi.biClrUsed ? bi.biClrUsed : 1 << nbits;
251  if (ncols > 256) // sanity check - don't run out of mem if color table is broken
252  return false;
253  image.setColorCount(ncols);
254  }
255 
258 
259  if (!d->isSequential())
260  d->seek(startpos + BMP_FILEHDR_SIZE + (bi.biSize >= BMP_WIN4? BMP_WIN : bi.biSize)); // goto start of colormap
261 
262  if (bi.biSize >= BMP_WIN4 || (comp == BMP_BITFIELDS && (nbits == 16 || nbits == 32))) {
263  if (d->read((char *)&red_mask, sizeof(red_mask)) != sizeof(red_mask))
264  return false;
265  if (d->read((char *)&green_mask, sizeof(green_mask)) != sizeof(green_mask))
266  return false;
267  if (d->read((char *)&blue_mask, sizeof(blue_mask)) != sizeof(blue_mask))
268  return false;
269 
270  // Read BMP v4+ header
271  if (bi.biSize >= BMP_WIN4) {
272  int alpha_mask = 0;
273  int CSType = 0;
274  int gamma_red = 0;
275  int gamma_green = 0;
276  int gamma_blue = 0;
277  int endpoints[9];
278 
279  if (d->read((char *)&alpha_mask, sizeof(alpha_mask)) != sizeof(alpha_mask))
280  return false;
281  if (d->read((char *)&CSType, sizeof(CSType)) != sizeof(CSType))
282  return false;
283  if (d->read((char *)&endpoints, sizeof(endpoints)) != sizeof(endpoints))
284  return false;
285  if (d->read((char *)&gamma_red, sizeof(gamma_red)) != sizeof(gamma_red))
286  return false;
287  if (d->read((char *)&gamma_green, sizeof(gamma_green)) != sizeof(gamma_green))
288  return false;
289  if (d->read((char *)&gamma_blue, sizeof(gamma_blue)) != sizeof(gamma_blue))
290  return false;
291 
292  if (bi.biSize == BMP_WIN5) {
293  qint32 intent = 0;
294  qint32 profileData = 0;
295  qint32 profileSize = 0;
296  qint32 reserved = 0;
297 
298  if (d->read((char *)&intent, sizeof(intent)) != sizeof(intent))
299  return false;
300  if (d->read((char *)&profileData, sizeof(profileData)) != sizeof(profileData))
301  return false;
302  if (d->read((char *)&profileSize, sizeof(profileSize)) != sizeof(profileSize))
303  return false;
304  if (d->read((char *)&reserved, sizeof(reserved)) != sizeof(reserved) || reserved != 0)
305  return false;
306  }
307  }
308  }
309 
310  if (ncols > 0) { // read color table
311  uchar rgb[4];
312  int rgb_len = t == BMP_OLD ? 3 : 4;
313  for (int i=0; i<ncols; i++) {
314  if (d->read((char *)rgb, rgb_len) != rgb_len)
315  return false;
316  image.setColor(i, qRgb(rgb[2],rgb[1],rgb[0]));
317  if (d->atEnd()) // truncated file
318  return false;
319  }
320  } else if (comp == BMP_BITFIELDS && (nbits == 16 || nbits == 32)) {
321  red_shift = calc_shift(red_mask);
322  red_scale = 256 / ((red_mask >> red_shift) + 1);
323  green_shift = calc_shift(green_mask);
324  green_scale = 256 / ((green_mask >> green_shift) + 1);
325  blue_shift = calc_shift(blue_mask);
326  blue_scale = 256 / ((blue_mask >> blue_shift) + 1);
327  } else if (comp == BMP_RGB && (nbits == 24 || nbits == 32)) {
328  blue_mask = 0x000000ff;
329  green_mask = 0x0000ff00;
330  red_mask = 0x00ff0000;
331  blue_shift = 0;
332  green_shift = 8;
333  red_shift = 16;
334  blue_scale = green_scale = red_scale = 1;
335  } else if (comp == BMP_RGB && nbits == 16) {
336  blue_mask = 0x001f;
337  green_mask = 0x03e0;
338  red_mask = 0x7c00;
339  blue_shift = 0;
340  green_shift = 2;
341  red_shift = 7;
342  red_scale = 1;
343  green_scale = 1;
344  blue_scale = 8;
345  }
346 
347  // offset can be bogus, be careful
348  if (offset>=0 && startpos + offset > d->pos()) {
349  if (!d->isSequential())
350  d->seek(startpos + offset); // start of image data
351  }
352 
353  int bpl = image.bytesPerLine();
354  uchar *data = image.bits();
355 
356  if (nbits == 1) { // 1 bit BMP image
357  while (--h >= 0) {
358  if (d->read((char*)(data + h*bpl), bpl) != bpl)
359  break;
360  }
361  if (ncols == 2 && qGray(image.color(0)) < qGray(image.color(1)))
362  swapPixel01(&image); // pixel 0 is white!
363  }
364 
365  else if (nbits == 4) { // 4 bit BMP image
366  int buflen = ((w+7)/8)*4;
367  uchar *buf = new uchar[buflen];
368  if (comp == BMP_RLE4) { // run length compression
369  int x=0, y=0, c, i;
370  quint8 b;
371  register uchar *p = data + (h-1)*bpl;
372  const uchar *endp = p + w;
373  while (y < h) {
374  if (!d->getChar((char *)&b))
375  break;
376  if (b == 0) { // escape code
377  if (!d->getChar((char *)&b) || b == 1) {
378  y = h; // exit loop
379  } else switch (b) {
380  case 0: // end of line
381  x = 0;
382  y++;
383  p = data + (h-y-1)*bpl;
384  break;
385  case 2: // delta (jump)
386  {
387  quint8 tmp;
388  d->getChar((char *)&tmp);
389  x += tmp;
390  d->getChar((char *)&tmp);
391  y += tmp;
392  }
393 
394  // Protection
395  if ((uint)x >= (uint)w)
396  x = w-1;
397  if ((uint)y >= (uint)h)
398  y = h-1;
399 
400  p = data + (h-y-1)*bpl + x;
401  break;
402  default: // absolute mode
403  // Protection
404  if (p + b > endp)
405  b = endp-p;
406 
407  i = (c = b)/2;
408  while (i--) {
409  d->getChar((char *)&b);
410  *p++ = b >> 4;
411  *p++ = b & 0x0f;
412  }
413  if (c & 1) {
414  unsigned char tmp;
415  d->getChar((char *)&tmp);
416  *p++ = tmp >> 4;
417  }
418  if ((((c & 3) + 1) & 2) == 2)
419  d->getChar(0); // align on word boundary
420  x += c;
421  }
422  } else { // encoded mode
423  // Protection
424  if (p + b > endp)
425  b = endp-p;
426 
427  i = (c = b)/2;
428  d->getChar((char *)&b); // 2 pixels to be repeated
429  while (i--) {
430  *p++ = b >> 4;
431  *p++ = b & 0x0f;
432  }
433  if (c & 1)
434  *p++ = b >> 4;
435  x += c;
436  }
437  }
438  } else if (comp == BMP_RGB) { // no compression
439  memset(data, 0, h*bpl);
440  while (--h >= 0) {
441  if (d->read((char*)buf,buflen) != buflen)
442  break;
443  register uchar *p = data + h*bpl;
444  uchar *b = buf;
445  for (int i=0; i<w/2; i++) { // convert nibbles to bytes
446  *p++ = *b >> 4;
447  *p++ = *b++ & 0x0f;
448  }
449  if (w & 1) // the last nibble
450  *p = *b >> 4;
451  }
452  }
453  delete [] buf;
454  }
455 
456  else if (nbits == 8) { // 8 bit BMP image
457  if (comp == BMP_RLE8) { // run length compression
458  int x=0, y=0;
459  quint8 b;
460  register uchar *p = data + (h-1)*bpl;
461  const uchar *endp = p + w;
462  while (y < h) {
463  if (!d->getChar((char *)&b))
464  break;
465  if (b == 0) { // escape code
466  if (!d->getChar((char *)&b) || b == 1) {
467  y = h; // exit loop
468  } else switch (b) {
469  case 0: // end of line
470  x = 0;
471  y++;
472  p = data + (h-y-1)*bpl;
473  break;
474  case 2: // delta (jump)
475  // Protection
476  if ((uint)x >= (uint)w)
477  x = w-1;
478  if ((uint)y >= (uint)h)
479  y = h-1;
480 
481  {
482  quint8 tmp;
483  d->getChar((char *)&tmp);
484  x += tmp;
485  d->getChar((char *)&tmp);
486  y += tmp;
487  }
488  p = data + (h-y-1)*bpl + x;
489  break;
490  default: // absolute mode
491  // Protection
492  if (p + b > endp)
493  b = endp-p;
494 
495  if (d->read((char *)p, b) != b)
496  return false;
497  if ((b & 1) == 1)
498  d->getChar(0); // align on word boundary
499  x += b;
500  p += b;
501  }
502  } else { // encoded mode
503  // Protection
504  if (p + b > endp)
505  b = endp-p;
506 
507  char tmp;
508  d->getChar(&tmp);
509  memset(p, tmp, b); // repeat pixel
510  x += b;
511  p += b;
512  }
513  }
514  } else if (comp == BMP_RGB) { // uncompressed
515  while (--h >= 0) {
516  if (d->read((char *)data + h*bpl, bpl) != bpl)
517  break;
518  }
519  }
520  }
521 
522  else if (nbits == 16 || nbits == 24 || nbits == 32) { // 16,24,32 bit BMP image
523  register QRgb *p;
524  QRgb *end;
525  uchar *buf24 = new uchar[bpl];
526  int bpl24 = ((w*nbits+31)/32)*4;
527  uchar *b;
528  int c;
529 
530  while (--h >= 0) {
531  p = (QRgb *)(data + h*bpl);
532  end = p + w;
533  if (d->read((char *)buf24,bpl24) != bpl24)
534  break;
535  b = buf24;
536  while (p < end) {
537  c = *(uchar*)b | (*(uchar*)(b+1)<<8);
538  if (nbits != 16)
539  c |= *(uchar*)(b+2)<<16;
540  *p++ = qRgb(((c & red_mask) >> red_shift) * red_scale,
541  ((c & green_mask) >> green_shift) * green_scale,
542  ((c & blue_mask) >> blue_shift) * blue_scale);
543  b += nbits/8;
544  }
545  }
546  delete[] buf24;
547  }
548 
549  if (bi.biHeight < 0) {
550  // Flip the image
551  uchar *buf = new uchar[bpl];
552  h = -bi.biHeight;
553  for (int y = 0; y < h/2; ++y) {
554  memcpy(buf, data + y*bpl, bpl);
555  memcpy(data + y*bpl, data + (h-y-1)*bpl, bpl);
556  memcpy(data + (h-y-1)*bpl, buf, bpl);
557  }
558  delete [] buf;
559  }
560 
561  return true;
562 }
563 
564 // this is also used in qmime_win.cpp
566 {
567  int nbits;
568  int bpl_bmp;
569  int bpl = image.bytesPerLine();
570 
571  QIODevice* d = s.device();
572  if (!d->isWritable())
573  return false;
574 
575  if (image.depth() == 8 && image.colorCount() <= 16) {
576  bpl_bmp = (((bpl+1)/2+3)/4)*4;
577  nbits = 4;
578  } else if (image.depth() == 32) {
579  bpl_bmp = ((image.width()*24+31)/32)*4;
580  nbits = 24;
581 #ifdef Q_WS_QWS
582  } else if (image.depth() == 1 || image.depth() == 8) {
583  // Qt for Embedded Linux doesn't word align.
584  bpl_bmp = ((image.width()*image.depth()+31)/32)*4;
585  nbits = image.depth();
586 #endif
587  } else {
588  bpl_bmp = bpl;
589  nbits = image.depth();
590  }
591 
592  BMP_INFOHDR bi;
593  bi.biSize = BMP_WIN; // build info header
594  bi.biWidth = image.width();
595  bi.biHeight = image.height();
596  bi.biPlanes = 1;
597  bi.biBitCount = nbits;
598  bi.biCompression = BMP_RGB;
599  bi.biSizeImage = bpl_bmp*image.height();
600  bi.biXPelsPerMeter = image.dotsPerMeterX() ? image.dotsPerMeterX()
601  : 2834; // 72 dpi default
602  bi.biYPelsPerMeter = image.dotsPerMeterY() ? image.dotsPerMeterY() : 2834;
603  bi.biClrUsed = image.colorCount();
604  bi.biClrImportant = image.colorCount();
605  s << bi; // write info header
606  if (s.status() != QDataStream::Ok)
607  return false;
608 
609  if (image.depth() != 32) { // write color table
610  uchar *color_table = new uchar[4*image.colorCount()];
611  uchar *rgb = color_table;
612  QVector<QRgb> c = image.colorTable();
613  for (int i=0; i<image.colorCount(); i++) {
614  *rgb++ = qBlue (c[i]);
615  *rgb++ = qGreen(c[i]);
616  *rgb++ = qRed (c[i]);
617  *rgb++ = 0;
618  }
619  if (d->write((char *)color_table, 4*image.colorCount()) == -1) {
620  delete [] color_table;
621  return false;
622  }
623  delete [] color_table;
624  }
625 
626  if (image.format() == QImage::Format_MonoLSB)
627  image = image.convertToFormat(QImage::Format_Mono);
628 
629  int y;
630 
631  if (nbits == 1 || nbits == 8) { // direct output
632 #ifdef Q_WS_QWS
633  // Qt for Embedded Linux doesn't word align.
634  int pad = bpl_bmp - bpl;
635  char padding[4];
636 #endif
637  for (y=image.height()-1; y>=0; y--) {
638  if (d->write((char*)image.scanLine(y), bpl) == -1)
639  return false;
640 #ifdef Q_WS_QWS
641  if (d->write(padding, pad) == -1)
642  return false;
643 #endif
644  }
645  return true;
646  }
647 
648  uchar *buf = new uchar[bpl_bmp];
649  uchar *b, *end;
650  register uchar *p;
651 
652  memset(buf, 0, bpl_bmp);
653  for (y=image.height()-1; y>=0; y--) { // write the image bits
654  if (nbits == 4) { // convert 8 -> 4 bits
655  p = image.scanLine(y);
656  b = buf;
657  end = b + image.width()/2;
658  while (b < end) {
659  *b++ = (*p << 4) | (*(p+1) & 0x0f);
660  p += 2;
661  }
662  if (image.width() & 1)
663  *b = *p << 4;
664  } else { // 32 bits
665  QRgb *p = (QRgb *)image.scanLine(y);
666  QRgb *end = p + image.width();
667  b = buf;
668  while (p < end) {
669  *b++ = qBlue(*p);
670  *b++ = qGreen(*p);
671  *b++ = qRed(*p);
672  p++;
673  }
674  }
675  if (bpl_bmp != d->write((char*)buf, bpl_bmp)) {
676  delete[] buf;
677  return false;
678  }
679  }
680  delete[] buf;
681  return true;
682 }
683 
684 // this is also used in qmime_win.cpp
686 {
687  BMP_INFOHDR bi;
688  if (!read_dib_infoheader(s, bi))
689  return false;
690  return read_dib_body(s, bi, -1, -BMP_FILEHDR_SIZE, image);
691 }
692 
694  : state(Ready)
695 {
696 }
697 
699 {
700  state = Error;
701 
702  QIODevice *d = device();
703  QDataStream s(d);
704  startpos = d->pos();
705 
706  // Intel byte order
708 
709  // read BMP file header
711  return false;
712 
713  // read BMP info header
715  return false;
716 
717  state = ReadHeader;
718  return true;
719 }
720 
722 {
723  if (state == Ready && !canRead(device()))
724  return false;
725 
726  if (state != Error) {
727  setFormat("bmp");
728  return true;
729  }
730 
731  return false;
732 }
733 
735 {
736  if (!device) {
737  qWarning("QBmpHandler::canRead() called with 0 pointer");
738  return false;
739  }
740 
741  char head[2];
742  if (device->peek(head, sizeof(head)) != sizeof(head))
743  return false;
744 
745  return (qstrncmp(head, "BM", 2) == 0);
746 }
747 
749 {
750  if (state == Error)
751  return false;
752 
753  if (!image) {
754  qWarning("QBmpHandler::read: cannot read into null pointer");
755  return false;
756  }
757 
758  if (state == Ready && !readHeader()) {
759  state = Error;
760  return false;
761  }
762 
763  QIODevice *d = device();
764  QDataStream s(d);
765 
766  // Intel byte order
768 
769  // read image
771  return false;
772 
773  state = Ready;
774  return true;
775 }
776 
777 bool QBmpHandler::write(const QImage &img)
778 {
779  QImage image;
780  switch (img.format()) {
786  break;
793  break;
794  default:
795  image = img;
796  }
797 
798  QIODevice *d = device();
799  QDataStream s(d);
800  BMP_FILEHDR bf;
801  int bpl_bmp;
802  int bpl = image.bytesPerLine();
803 
804  // Code partially repeated in qt_write_dib
805  if (image.depth() == 8 && image.colorCount() <= 16) {
806  bpl_bmp = (((bpl+1)/2+3)/4)*4;
807  } else if (image.depth() == 32) {
808  bpl_bmp = ((image.width()*24+31)/32)*4;
809  } else {
810  bpl_bmp = bpl;
811  }
812 
813  // Intel byte order
815 
816  // build file header
817  memcpy(bf.bfType, "BM", 2);
818 
819  // write file header
820  bf.bfReserved1 = 0;
821  bf.bfReserved2 = 0;
822  bf.bfOffBits = BMP_FILEHDR_SIZE + BMP_WIN + image.colorCount() * 4;
823  bf.bfSize = bf.bfOffBits + bpl_bmp*image.height();
824  s << bf;
825 
826  // write image
827  return qt_write_dib(s, image);
828 }
829 
831 {
832  return option == Size
833  || option == ImageFormat;
834 }
835 
837 {
838  if (option == Size) {
839  if (state == Error)
840  return QVariant();
841  if (state == Ready && !const_cast<QBmpHandler*>(this)->readHeader())
842  return QVariant();
844  } else if (option == ImageFormat) {
845  if (state == Error)
846  return QVariant();
847  if (state == Ready && !const_cast<QBmpHandler*>(this)->readHeader())
848  return QVariant();
850  switch (infoHeader.biBitCount) {
851  case 32:
852  case 24:
853  case 16:
854  format = QImage::Format_RGB32;
855  break;
856  case 8:
857  case 4:
858  format = QImage::Format_Indexed8;
859  break;
860  default:
861  format = QImage::Format_Mono;
862  }
863  return format;
864  }
865  return QVariant();
866 }
867 
869 {
870  Q_UNUSED(option);
871  Q_UNUSED(value);
872 }
873 
875 {
876  return "bmp";
877 }
878 
880 
881 #endif // QT_NO_IMAGEFORMAT_BMP
The QVariant class acts like a union for the most common Qt data types.
Definition: qvariant.h:92
double d
Definition: qnumeric_p.h:62
Status status() const
Returns the status of the data stream.
void setOption(ImageOption option, const QVariant &value)
Sets the option option with the value value.
qint32 bfOffBits
Definition: qbmphandler_p.h:67
const int BMP_WIN
char bfType[2]
Definition: qbmphandler_p.h:63
static bool read_dib_body(QDataStream &s, const BMP_INFOHDR &bi, int offset, int startpos, QImage &image)
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 qstrncmp(const char *str1, const char *str2, uint len)
Definition: qbytearray.h:101
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
int qint32
Definition: qglobal.h:937
bool isWritable() const
Returns true if data can be written to the device; otherwise returns false.
Definition: qiodevice.cpp:558
bool qt_write_dib(QDataStream &s, QImage image)
const int BMP_RLE4
bool isNull() const
Returns true if it is a null image, otherwise returns false.
Definition: qimage.cpp:1542
qint32 biSize
Definition: qbmphandler_p.h:71
static void swapPixel01(QImage *image)
Definition: qbmphandler.cpp:52
The QByteArray class provides an array of bytes.
Definition: qbytearray.h:135
bool qt_read_dib(QDataStream &s, QImage &image)
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
bool getChar(char *c)
Reads one character from the device and stores it in c.
Definition: qiodevice.cpp:1536
int byteCount() const
Returns the number of bytes occupied by the image data.
Definition: qimage.cpp:1800
int bytesPerLine() const
Returns the number of bytes per image scanline.
Definition: qimage.cpp:1812
unsigned char quint8
Definition: qglobal.h:934
int dotsPerMeterY() const
Returns the number of pixels that fit vertically in a physical meter.
Definition: qimage.cpp:5628
qint32 bfSize
Definition: qbmphandler_p.h:64
static int calc_shift(uint mask)
QByteArray name() const
Use format() instead.
const int BMP_BITFIELDS
virtual bool atEnd() const
Returns true if the current read and write position is at the end of the device (i.e.
Definition: qiodevice.cpp:711
int qRed(QRgb rgb)
Returns the red component of the ARGB quadruplet rgb.
Definition: qrgb.h:57
Format format() const
Returns the format of the image.
Definition: qimage.cpp:2305
qint32 biSizeImage
Definition: qbmphandler_p.h:77
qint32 biClrUsed
Definition: qbmphandler_p.h:80
qint32 biWidth
Definition: qbmphandler_p.h:72
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
Q_CORE_EXPORT void qDebug(const char *,...)
const int BMP_RGB
unsigned char uchar
Definition: qglobal.h:994
const int BMP_RLE8
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
qint32 biYPelsPerMeter
Definition: qbmphandler_p.h:79
int readRawData(char *, int len)
Reads at most len bytes from the stream into s and returns the number of bytes read.
bool canRead() const
Returns true if an image can be read from the device (i.
ImageOption
This enum describes the different options supported by QImageIOHandler.
short qint16
Definition: qglobal.h:935
qint64 peek(char *data, qint64 maxlen)
Reads at most maxSize bytes from the device into data, without side effects (i.
Definition: qiodevice.cpp:1563
const int BMP_OLD
Definition: qbmphandler.cpp:99
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
static const char * data(const QByteArray &arr)
unsigned int uint
Definition: qglobal.h:996
int qGray(int r, int g, int b)
Definition: qrgb.h:75
void setByteOrder(ByteOrder)
Sets the serialization byte order to bo.
void setDotsPerMeterY(int)
Sets the number of pixels that fit vertically in a physical meter, to y.
Definition: qimage.cpp:5667
int depth() const
Returns the depth of the image.
Definition: qimage.cpp:1620
qint16 biBitCount
Definition: qbmphandler_p.h:75
const int BMP_FILEHDR_SIZE
Definition: qbmphandler.cpp:82
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
static bool read_dib_fileheader(QDataStream &s, BMP_FILEHDR &bf)
#define rgb(r, g, b)
Definition: qcolor_p.cpp:130
BMP_INFOHDR infoHeader
qint16 bfReserved1
Definition: qbmphandler_p.h:65
QRgb qRgb(int r, int g, int b)
Returns the ARGB quadruplet (255, {r}, {g}, {b}).
Definition: qrgb.h:69
bool supportsOption(ImageOption option) const
Returns true if the QImageIOHandler supports the option option; otherwise returns false...
uchar * bits()
Returns a pointer to the first pixel data.
Definition: qimage.cpp:1946
const int BMP_OS2
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
QIODevice * device() const
Returns the I/O device currently set, or 0 if no device is currently set.
Definition: qdatastream.h:206
void setDotsPerMeterX(int)
Sets the number of pixels that fit horizontally in a physical meter, to x.
Definition: qimage.cpp:5645
int colorCount() const
Returns the size of the color table for the image.
Definition: qimage.cpp:1656
qint16 bfReserved2
Definition: qbmphandler_p.h:66
qint32 biCompression
Definition: qbmphandler_p.h:76
const int BMP_WIN4
const int BMP_WIN5
static bool read_dib_infoheader(QDataStream &s, BMP_INFOHDR &bi)
int qstrncmp(const char *str1, const char *str2, uint len)
Definition: qbytearray.h:101
QVariant option(ImageOption option) const
Returns the value assigned to option as a QVariant.
QIODevice * device() const
Returns the device currently assigned to the QImageIOHandler.
int height() const
Returns the height of the image.
Definition: qimage.cpp:1572
qint32 biClrImportant
Definition: qbmphandler_p.h:81
bool readHeader()
The QSize class defines the size of a two-dimensional object using integer point precision.
Definition: qsize.h:53
The QDataStream class provides serialization of binary data to a QIODevice.
Definition: qdatastream.h:71
bool read(QImage *image)
Read an image from the device, and stores it in image.
BMP_FILEHDR fileHeader
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
qint32 biXPelsPerMeter
Definition: qbmphandler_p.h:78
QDataStream & operator<<(QDataStream &out, const QUrl &url)
Writes url url to the stream out and returns a reference to the stream.
Definition: qurl.cpp:6757
#define Q_UNUSED(x)
Indicates to the compiler that the parameter with the specified name is not used in the body of a fun...
Definition: qglobal.h:1729
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
int dotsPerMeterX() const
Returns the number of pixels that fit horizontally in a physical meter.
Definition: qimage.cpp:5615
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
int writeRawData(const char *, int len)
Writes len bytes from s to the stream.
QRgb color(int i) const
Returns the color in the color table at index i.
Definition: qimage.cpp:1829
bool write(const QImage &image)
Writes the image image to the assigned device.
uchar * scanLine(int)
Returns a pointer to the pixel data at the scanline with index i.
Definition: qimage.cpp:1886
qint16 biPlanes
Definition: qbmphandler_p.h:74
qint32 biHeight
Definition: qbmphandler_p.h:73
QDataStream & operator>>(QDataStream &in, QUrl &url)
Reads a url into url from the stream in and returns a reference to the stream.
Definition: qurl.cpp:6774