Qt 4.8
qicohandler.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 plugins 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 
54 #include "qicohandler.h"
55 #include <QtCore/qendian.h>
56 #include <QtGui/QImage>
57 #include <QtCore/QFile>
58 #include <QtCore/QBuffer>
59 #include <qvariant.h>
60 
62 
63 // These next two structs represent how the icon information is stored
64 // in an ICO file.
65 typedef struct
66 {
67  quint8 bWidth; // Width of the image
68  quint8 bHeight; // Height of the image (times 2)
69  quint8 bColorCount; // Number of colors in image (0 if >=8bpp) [ not ture ]
70  quint8 bReserved; // Reserved
71  quint16 wPlanes; // Color Planes
72  quint16 wBitCount; // Bits per pixel
73  quint32 dwBytesInRes; // how many bytes in this resource?
74  quint32 dwImageOffset; // where in the file is this image
76 #define ICONDIRENTRY_SIZE 16
77 
78 typedef struct
79 {
80  quint16 idReserved; // Reserved
81  quint16 idType; // resource type (1 for icons)
82  quint16 idCount; // how many images?
83  ICONDIRENTRY idEntries[1]; // the entries for each image
84 } ICONDIR, *LPICONDIR;
85 #define ICONDIR_SIZE 6 // Exclude the idEntries field
86 
87 typedef struct { // BMP information header
88  quint32 biSize; // size of this struct
89  quint32 biWidth; // pixmap width
90  quint32 biHeight; // pixmap height (specifies the combined height of the XOR and AND masks)
91  quint16 biPlanes; // should be 1
92  quint16 biBitCount; // number of bits per pixel
93  quint32 biCompression; // compression method
94  quint32 biSizeImage; // size of image
95  quint32 biXPelsPerMeter; // horizontal resolution
96  quint32 biYPelsPerMeter; // vertical resolution
97  quint32 biClrUsed; // number of colors used
98  quint32 biClrImportant; // number of important colors
100 #define BMP_INFOHDR_SIZE 40
101 
103 {
104 public:
105  ICOReader(QIODevice * iodevice);
106  int count();
107  QImage iconAt(int index);
108  static bool canRead(QIODevice *iodev);
109 
110  static QList<QImage> read(QIODevice * device);
111 
112  static bool write(QIODevice * device, const QList<QImage> & images);
113 
114 private:
115  bool readHeader();
116  bool readIconEntry(int index, ICONDIRENTRY * iconEntry);
117 
118  bool readBMPHeader(quint32 imageOffset, BMP_INFOHDR * header);
119  void findColorInfo(QImage & image);
120  void readColorTable(QImage & image);
121 
122  void readBMP(QImage & image);
123  void read1BitBMP(QImage & image);
124  void read4BitBMP(QImage & image);
125  void read8BitBMP(QImage & image);
126  void read16_24_32BMP(QImage & image);
127 
128  struct IcoAttrib
129  {
130  int nbits;
131  int ncolors;
132  int h;
133  int w;
134  int depth;
135  } icoAttrib;
136 
141 
142 };
143 
144 // Data readers and writers that takes care of alignment and endian stuff.
145 static bool readIconDirEntry(QIODevice *iodev, ICONDIRENTRY *iconDirEntry)
146 {
147  if (iodev) {
149  if (iodev->read((char*)tmp, ICONDIRENTRY_SIZE) == ICONDIRENTRY_SIZE) {
150  iconDirEntry->bWidth = tmp[0];
151  iconDirEntry->bHeight = tmp[1];
152  iconDirEntry->bColorCount = tmp[2];
153  iconDirEntry->bReserved = tmp[3];
154 
155  iconDirEntry->wPlanes = qFromLittleEndian<quint16>(&tmp[4]);
156  iconDirEntry->wBitCount = qFromLittleEndian<quint16>(&tmp[6]);
157  iconDirEntry->dwBytesInRes = qFromLittleEndian<quint32>(&tmp[8]);
158  iconDirEntry->dwImageOffset = qFromLittleEndian<quint32>(&tmp[12]);
159  return true;
160  }
161  }
162  return false;
163 }
164 
165 static bool writeIconDirEntry(QIODevice *iodev, const ICONDIRENTRY &iconEntry)
166 {
167  if (iodev) {
169  tmp[0] = iconEntry.bWidth;
170  tmp[1] = iconEntry.bHeight;
171  tmp[2] = iconEntry.bColorCount;
172  tmp[3] = iconEntry.bReserved;
173  qToLittleEndian<quint16>(iconEntry.wPlanes, &tmp[4]);
174  qToLittleEndian<quint16>(iconEntry.wBitCount, &tmp[6]);
175  qToLittleEndian<quint32>(iconEntry.dwBytesInRes, &tmp[8]);
176  qToLittleEndian<quint32>(iconEntry.dwImageOffset, &tmp[12]);
177  return (iodev->write((char*)tmp, ICONDIRENTRY_SIZE) == ICONDIRENTRY_SIZE) ? true : false;
178  }
179 
180  return false;
181 }
182 
183 static bool readIconDir(QIODevice *iodev, ICONDIR *iconDir)
184 {
185  if (iodev) {
186  uchar tmp[ICONDIR_SIZE];
187  if (iodev->read((char*)tmp, ICONDIR_SIZE) == ICONDIR_SIZE) {
188  iconDir->idReserved = qFromLittleEndian<quint16>(&tmp[0]);
189  iconDir->idType = qFromLittleEndian<quint16>(&tmp[2]);
190  iconDir->idCount = qFromLittleEndian<quint16>(&tmp[4]);
191  return true;
192  }
193  }
194  return false;
195 }
196 
197 static bool writeIconDir(QIODevice *iodev, const ICONDIR &iconDir)
198 {
199  if (iodev) {
200  uchar tmp[6];
201  qToLittleEndian(iconDir.idReserved, tmp);
202  qToLittleEndian(iconDir.idType, &tmp[2]);
203  qToLittleEndian(iconDir.idCount, &tmp[4]);
204  return (iodev->write((char*)tmp, 6) == 6) ? true : false;
205  }
206  return false;
207 }
208 
209 static bool readBMPInfoHeader(QIODevice *iodev, BMP_INFOHDR *pHeader)
210 {
211  if (iodev) {
212  uchar header[BMP_INFOHDR_SIZE];
213  if (iodev->read((char*)header, BMP_INFOHDR_SIZE) == BMP_INFOHDR_SIZE) {
214  pHeader->biSize = qFromLittleEndian<quint32>(&header[0]);
215  pHeader->biWidth = qFromLittleEndian<quint32>(&header[4]);
216  pHeader->biHeight = qFromLittleEndian<quint32>(&header[8]);
217  pHeader->biPlanes = qFromLittleEndian<quint16>(&header[12]);
218  pHeader->biBitCount = qFromLittleEndian<quint16>(&header[14]);
219  pHeader->biCompression = qFromLittleEndian<quint32>(&header[16]);
220  pHeader->biSizeImage = qFromLittleEndian<quint32>(&header[20]);
221  pHeader->biXPelsPerMeter = qFromLittleEndian<quint32>(&header[24]);
222  pHeader->biYPelsPerMeter = qFromLittleEndian<quint32>(&header[28]);
223  pHeader->biClrUsed = qFromLittleEndian<quint32>(&header[32]);
224  pHeader->biClrImportant = qFromLittleEndian<quint32>(&header[36]);
225  return true;
226  }
227  }
228  return false;
229 }
230 
231 static bool writeBMPInfoHeader(QIODevice *iodev, const BMP_INFOHDR &header)
232 {
233  if (iodev) {
234  uchar tmp[BMP_INFOHDR_SIZE];
235  qToLittleEndian<quint32>(header.biSize, &tmp[0]);
236  qToLittleEndian<quint32>(header.biWidth, &tmp[4]);
237  qToLittleEndian<quint32>(header.biHeight, &tmp[8]);
238  qToLittleEndian<quint16>(header.biPlanes, &tmp[12]);
239  qToLittleEndian<quint16>(header.biBitCount, &tmp[14]);
240  qToLittleEndian<quint32>(header.biCompression, &tmp[16]);
241  qToLittleEndian<quint32>(header.biSizeImage, &tmp[20]);
242  qToLittleEndian<quint32>(header.biXPelsPerMeter, &tmp[24]);
243  qToLittleEndian<quint32>(header.biYPelsPerMeter, &tmp[28]);
244  qToLittleEndian<quint32>(header.biClrUsed, &tmp[32]);
245  qToLittleEndian<quint32>(header.biClrImportant, &tmp[36]);
246 
247  return (iodev->write((char*)tmp, BMP_INFOHDR_SIZE) == BMP_INFOHDR_SIZE) ? true : false;
248  }
249  return false;
250 }
251 
252 
254 : iod(iodevice)
255 , startpos(0)
256 , headerRead(false)
257 {
258 }
259 
260 
262 {
263  if (readHeader())
264  return iconDir.idCount;
265  return 0;
266 }
267 
269 {
270  bool isProbablyICO = false;
271  if (iodev) {
272  qint64 oldPos = iodev->pos();
273 
274  ICONDIR ikonDir;
275  if (readIconDir(iodev, &ikonDir)) {
276  qint64 readBytes = ICONDIR_SIZE;
277  if (readIconDirEntry(iodev, &ikonDir.idEntries[0])) {
278  readBytes += ICONDIRENTRY_SIZE;
279  // ICO format does not have a magic identifier, so we read 6 different values, which will hopefully be enough to identify the file.
280  if ( ikonDir.idReserved == 0
281  && ikonDir.idType == 1
282  && ikonDir.idEntries[0].bReserved == 0
283  && ikonDir.idEntries[0].wPlanes <= 1
284  && ikonDir.idEntries[0].wBitCount <= 32 // Bits per pixel
285  && ikonDir.idEntries[0].dwBytesInRes >= 40 // Must be over 40, since sizeof (infoheader) == 40
286  ) {
287  isProbablyICO = true;
288  }
289 
290  if (iodev->isSequential()) {
291  // Our structs might be padded due to alignment, so we need to fetch each member before we ungetChar() !
292  quint32 tmp = ikonDir.idEntries[0].dwImageOffset;
293  iodev->ungetChar((tmp >> 24) & 0xff);
294  iodev->ungetChar((tmp >> 16) & 0xff);
295  iodev->ungetChar((tmp >> 8) & 0xff);
296  iodev->ungetChar(tmp & 0xff);
297 
298  tmp = ikonDir.idEntries[0].dwBytesInRes;
299  iodev->ungetChar((tmp >> 24) & 0xff);
300  iodev->ungetChar((tmp >> 16) & 0xff);
301  iodev->ungetChar((tmp >> 8) & 0xff);
302  iodev->ungetChar(tmp & 0xff);
303 
304  tmp = ikonDir.idEntries[0].wBitCount;
305  iodev->ungetChar((tmp >> 8) & 0xff);
306  iodev->ungetChar(tmp & 0xff);
307 
308  tmp = ikonDir.idEntries[0].wPlanes;
309  iodev->ungetChar((tmp >> 8) & 0xff);
310  iodev->ungetChar(tmp & 0xff);
311 
312  iodev->ungetChar(ikonDir.idEntries[0].bReserved);
313  iodev->ungetChar(ikonDir.idEntries[0].bColorCount);
314  iodev->ungetChar(ikonDir.idEntries[0].bHeight);
315  iodev->ungetChar(ikonDir.idEntries[0].bWidth);
316  }
317  }
318 
319  if (iodev->isSequential()) {
320  // Our structs might be padded due to alignment, so we need to fetch each member before we ungetChar() !
321  quint32 tmp = ikonDir.idCount;
322  iodev->ungetChar((tmp >> 8) & 0xff);
323  iodev->ungetChar(tmp & 0xff);
324 
325  tmp = ikonDir.idType;
326  iodev->ungetChar((tmp >> 8) & 0xff);
327  iodev->ungetChar(tmp & 0xff);
328 
329  tmp = ikonDir.idReserved;
330  iodev->ungetChar((tmp >> 8) & 0xff);
331  iodev->ungetChar(tmp & 0xff);
332  }
333  }
334  if (!iodev->isSequential()) iodev->seek(oldPos);
335  }
336 
337  return isProbablyICO;
338 }
339 
341 {
342  if (iod && !headerRead) {
343  startpos = iod->pos();
344  if (readIconDir(iod, &iconDir)) {
345  if (iconDir.idReserved == 0 || iconDir.idType == 1)
346  headerRead = true;
347  }
348  }
349 
350  return headerRead;
351 }
352 
354 {
355  if (iod) {
356  if (iod->seek(startpos + ICONDIR_SIZE + (index * ICONDIRENTRY_SIZE))) {
357  return readIconDirEntry(iod, iconEntry);
358  }
359  }
360  return false;
361 }
362 
363 
364 
365 bool ICOReader::readBMPHeader(quint32 imageOffset, BMP_INFOHDR * header)
366 {
367  if (iod) {
368  if (iod->seek(startpos + imageOffset)) {
369  if (readBMPInfoHeader(iod, header)) {
370  return TRUE;
371  }
372  }
373  }
374  return FALSE;
375 }
376 
378 {
379  if (icoAttrib.ncolors > 0) { // set color table
380  readColorTable(image);
381  } else if (icoAttrib.nbits == 16) { // don't support RGB values for 15/16 bpp
382  image = QImage();
383  }
384 }
385 
387 {
388  if (iod) {
390  uchar rgb[4];
391  for (int i=0; i<icoAttrib.ncolors; i++) {
392  if (iod->read((char*)rgb, 4) != 4) {
393  image = QImage();
394  break;
395  }
396  image.setColor(i, qRgb(rgb[2],rgb[1],rgb[0]));
397  }
398  } else {
399  image = QImage();
400  }
401 }
402 
404 {
405  if (icoAttrib.nbits == 1) { // 1 bit BMP image
406  read1BitBMP(image);
407  } else if (icoAttrib.nbits == 4) { // 4 bit BMP image
408  read4BitBMP(image);
409  } else if (icoAttrib.nbits == 8) {
410  read8BitBMP(image);
411  } else if (icoAttrib.nbits == 16 || icoAttrib.nbits == 24 || icoAttrib.nbits == 32 ) { // 16,24,32 bit BMP image
412  read16_24_32BMP(image);
413  }
414 }
415 
416 
423 {
424  if (iod) {
425 
426  int h = image.height();
427  int bpl = image.bytesPerLine();
428 
429  while (--h >= 0) {
430  if (iod->read((char*)image.scanLine(h),bpl) != bpl) {
431  image = QImage();
432  break;
433  }
434  }
435  } else {
436  image = QImage();
437  }
438 }
439 
441 {
442  if (iod) {
443 
444  int h = icoAttrib.h;
445  int buflen = ((icoAttrib.w+7)/8)*4;
446  uchar *buf = new uchar[buflen];
447  Q_CHECK_PTR(buf);
448 
449  while (--h >= 0) {
450  if (iod->read((char*)buf,buflen) != buflen) {
451  image = QImage();
452  break;
453  }
454  register uchar *p = image.scanLine(h);
455  uchar *b = buf;
456  for (int i=0; i<icoAttrib.w/2; i++) { // convert nibbles to bytes
457  *p++ = *b >> 4;
458  *p++ = *b++ & 0x0f;
459  }
460  if (icoAttrib.w & 1) // the last nibble
461  *p = *b >> 4;
462  }
463 
464  delete [] buf;
465 
466  } else {
467  image = QImage();
468  }
469 }
470 
472 {
473  if (iod) {
474 
475  int h = icoAttrib.h;
476  int bpl = image.bytesPerLine();
477 
478  while (--h >= 0) {
479  if (iod->read((char *)image.scanLine(h), bpl) != bpl) {
480  image = QImage();
481  break;
482  }
483  }
484  } else {
485  image = QImage();
486  }
487 }
488 
490 {
491  if (iod) {
492  int h = icoAttrib.h;
493  register QRgb *p;
494  QRgb *end;
495  uchar *buf = new uchar[image.bytesPerLine()];
496  int bpl = ((icoAttrib.w*icoAttrib.nbits+31)/32)*4;
497  uchar *b;
498 
499  while (--h >= 0) {
500  p = (QRgb *)image.scanLine(h);
501  end = p + icoAttrib.w;
502  if (iod->read((char *)buf, bpl) != bpl) {
503  image = QImage();
504  break;
505  }
506  b = buf;
507  while (p < end) {
508  if (icoAttrib.nbits == 24)
509  *p++ = qRgb(*(b+2), *(b+1), *b);
510  else if (icoAttrib.nbits == 32)
511  *p++ = qRgba(*(b+2), *(b+1), *b, *(b+3));
512  b += icoAttrib.nbits/8;
513  }
514  }
515 
516  delete[] buf;
517 
518  } else {
519  image = QImage();
520  }
521 }
522 
524 {
525  QImage img;
526 
527  if (count() > index) { // forces header to be read
528 
529  ICONDIRENTRY iconEntry;
530  if (readIconEntry(index, &iconEntry)) {
531 
532  static const uchar pngMagicData[] = { 137, 80, 78, 71, 13, 10, 26, 10 };
533 
534  iod->seek(iconEntry.dwImageOffset);
535 
536  const QByteArray pngMagic = QByteArray::fromRawData((char*)pngMagicData, sizeof(pngMagicData));
537  const bool isPngImage = (iod->read(pngMagic.size()) == pngMagic);
538 
539  if (isPngImage) {
540  iod->seek(iconEntry.dwImageOffset);
541  return QImage::fromData(iod->read(iconEntry.dwBytesInRes), "png");
542  }
543 
544  BMP_INFOHDR header;
545  if (readBMPHeader(iconEntry.dwImageOffset, &header)) {
546  icoAttrib.nbits = header.biBitCount ? header.biBitCount : iconEntry.wBitCount;
547 
548  switch (icoAttrib.nbits) {
549  case 32:
550  case 24:
551  case 16:
552  icoAttrib.depth = 32;
553  break;
554  case 8:
555  case 4:
556  icoAttrib.depth = 8;
557  break;
558  default:
559  icoAttrib.depth = 1;
560  }
561  if (icoAttrib.depth == 32) // there's no colormap
562  icoAttrib.ncolors = 0;
563  else // # colors used
564  icoAttrib.ncolors = header.biClrUsed ? header.biClrUsed : 1 << icoAttrib.nbits;
565  if (icoAttrib.ncolors > 256) //color table can't be more than 256
566  return img;
567  icoAttrib.w = iconEntry.bWidth;
568  if (icoAttrib.w == 0)
569  icoAttrib.w = header.biWidth;
570  icoAttrib.h = iconEntry.bHeight;
571  if (icoAttrib.h == 0)
572  icoAttrib.h = header.biHeight/2;
573 
575  if (icoAttrib.nbits == 24)
576  format = QImage::Format_RGB32;
577  else if (icoAttrib.ncolors == 2)
578  format = QImage::Format_Mono;
579  else if (icoAttrib.ncolors > 0)
580  format = QImage::Format_Indexed8;
581 
582  QImage image(icoAttrib.w, icoAttrib.h, format);
583  if (!image.isNull()) {
584  findColorInfo(image);
585  if (!image.isNull()) {
586  readBMP(image);
587  if (!image.isNull()) {
588  QImage mask(image.width(), image.height(), QImage::Format_Mono);
589  if (!mask.isNull()) {
590  mask.setColorCount(2);
591  mask.setColor(0, qRgba(255,255,255,0xff));
592  mask.setColor(1, qRgba(0 ,0 ,0 ,0xff));
593  read1BitBMP(mask);
594  if (!mask.isNull()) {
595  img = QImage(image.width(), image.height(), QImage::Format_ARGB32 );
596  img = image;
597  img.setAlphaChannel(mask);
598  // (Luckily, it seems that setAlphaChannel() does not ruin the alpha values
599  // of partially transparent pixels in those icons that have that)
600  }
601  }
602  }
603  }
604  }
605  }
606  }
607  }
608 
609  return img;
610 }
611 
612 
623 {
624  QList<QImage> images;
625 
626  ICOReader reader(device);
627  for (int i = 0; i < reader.count(); i++)
628  images += reader.iconAt(i);
629 
630  return images;
631 }
632 
633 
646 bool ICOReader::write(QIODevice * device, const QList<QImage> & images)
647 {
648  bool retValue = false;
649 
650  if (images.count()) {
651 
652  qint64 origOffset = device->pos();
653 
654  ICONDIR id;
655  id.idReserved = 0;
656  id.idType = 1;
657  id.idCount = images.count();
658 
659  ICONDIRENTRY * entries = new ICONDIRENTRY[id.idCount];
660  BMP_INFOHDR * bmpHeaders = new BMP_INFOHDR[id.idCount];
661  QByteArray * imageData = new QByteArray[id.idCount];
662 
663  for (int i=0; i<id.idCount; i++) {
664 
665  QImage image = images[i];
666  // Scale down the image if it is larger than 128 pixels in either width or height
667  if (image.width() > 128 || image.height() > 128)
668  {
669  image = image.scaled(128, 128, Qt::KeepAspectRatio, Qt::SmoothTransformation);
670  }
671  QImage maskImage(image.width(), image.height(), QImage::Format_Mono);
672  image = image.convertToFormat(QImage::Format_ARGB32);
673 
674  if (image.hasAlphaChannel()) {
675  maskImage = image.createAlphaMask();
676  } else {
677  maskImage.fill(0xff);
678  }
679  maskImage = maskImage.convertToFormat(QImage::Format_Mono);
680 
681  int nbits = 32;
682  int bpl_bmp = ((image.width()*nbits+31)/32)*4;
683 
684  entries[i].bColorCount = 0;
685  entries[i].bReserved = 0;
686  entries[i].wBitCount = nbits;
687  entries[i].bHeight = image.height();
688  entries[i].bWidth = image.width();
689  entries[i].dwBytesInRes = BMP_INFOHDR_SIZE + (bpl_bmp * image.height())
690  + (maskImage.bytesPerLine() * maskImage.height());
691  entries[i].wPlanes = 1;
692  if (i == 0)
693  entries[i].dwImageOffset = origOffset + ICONDIR_SIZE
694  + (id.idCount * ICONDIRENTRY_SIZE);
695  else
696  entries[i].dwImageOffset = entries[i-1].dwImageOffset + entries[i-1].dwBytesInRes;
697 
698  bmpHeaders[i].biBitCount = entries[i].wBitCount;
699  bmpHeaders[i].biClrImportant = 0;
700  bmpHeaders[i].biClrUsed = entries[i].bColorCount;
701  bmpHeaders[i].biCompression = 0;
702  bmpHeaders[i].biHeight = entries[i].bHeight * 2; // 2 is for the mask
703  bmpHeaders[i].biPlanes = entries[i].wPlanes;
704  bmpHeaders[i].biSize = BMP_INFOHDR_SIZE;
705  bmpHeaders[i].biSizeImage = entries[i].dwBytesInRes - BMP_INFOHDR_SIZE;
706  bmpHeaders[i].biWidth = entries[i].bWidth;
707  bmpHeaders[i].biXPelsPerMeter = 0;
708  bmpHeaders[i].biYPelsPerMeter = 0;
709 
710  QBuffer buffer(&imageData[i]);
711  buffer.open(QIODevice::WriteOnly);
712 
713  uchar *buf = new uchar[bpl_bmp];
714  uchar *b;
715  memset( buf, 0, bpl_bmp );
716  int y;
717  for (y = image.height() - 1; y >= 0; y--) { // write the image bits
718  // 32 bits
719  QRgb *p = (QRgb *)image.scanLine(y);
720  QRgb *end = p + image.width();
721  b = buf;
722  int x = 0;
723  while (p < end) {
724  *b++ = qBlue(*p);
725  *b++ = qGreen(*p);
726  *b++ = qRed(*p);
727  *b++ = qAlpha(*p);
728  if (qAlpha(*p) > 0) // Even mostly transparent pixels must not be masked away
729  maskImage.setPixel(x, y, Qt::color1); // (i.e. createAlphaMask() takes away too much)
730  p++;
731  x++;
732  }
733  buffer.write((char*)buf, bpl_bmp);
734  }
735  delete[] buf;
736 
737  maskImage.invertPixels(); // seems as though it needs this
738  // NOTE! !! The mask is only flipped vertically - not horizontally !!
739  for (y = maskImage.height() - 1; y >= 0; y--)
740  buffer.write((char*)maskImage.scanLine(y), maskImage.bytesPerLine());
741  }
742 
743  if (writeIconDir(device, id)) {
744  int i;
745  bool bOK = true;
746  for (i = 0; i < id.idCount && bOK; i++) {
747  bOK = writeIconDirEntry(device, entries[i]);
748  }
749  if (bOK) {
750  for (i = 0; i < id.idCount && bOK; i++) {
751  bOK = writeBMPInfoHeader(device, bmpHeaders[i]);
752  bOK &= (device->write(imageData[i]) == (int) imageData[i].size());
753  }
754  retValue = bOK;
755  }
756  }
757 
758  delete [] entries;
759  delete [] bmpHeaders;
760  delete [] imageData;
761 
762  }
763  return retValue;
764 }
765 
770 {
771  m_currentIconIndex = 0;
772  setDevice(device);
773  m_pICOReader = new ICOReader(device);
774 }
775 
780 {
781  delete m_pICOReader;
782 }
783 
785 {
786  if (option == Size) {
788  qint64 oldPos = device->pos();
789  ICONDIRENTRY iconEntry;
790  if (device->seek(oldPos + ICONDIR_SIZE + (m_currentIconIndex * ICONDIRENTRY_SIZE))) {
791  if (readIconDirEntry(device, &iconEntry)) {
792  device->seek(oldPos);
793  return QSize(iconEntry.bWidth, iconEntry.bHeight);
794  }
795  }
796  if (!device->isSequential())
797  device->seek(oldPos);
798  }
799  return QVariant();
800 }
801 
803 {
804  return option == Size;
805 }
806 
813 {
814  bool bCanRead = false;
816  if (device) {
817  bCanRead = ICOReader::canRead(device);
818  if (bCanRead)
819  setFormat("ico");
820  } else {
821  qWarning("QtIcoHandler::canRead() called with no device");
822  }
823  return bCanRead;
824 }
825 
830 {
831  Q_ASSERT(device);
832  return ICOReader::canRead(device);
833 }
834 
839 {
840  bool bSuccess = false;
841  QImage img = m_pICOReader->iconAt(m_currentIconIndex);
842 
843  // Make sure we only write to \a image when we succeed.
844  if (!img.isNull()) {
845  bSuccess = true;
846  *image = img;
847  }
848 
849  return bSuccess;
850 }
851 
852 
856 bool QtIcoHandler::write(const QImage &image)
857 {
859  QList<QImage> imgs;
860  imgs.append(image);
861  return ICOReader::write(device, imgs);
862 }
863 
869 {
870  return "ico";
871 }
872 
873 
878 {
879  return m_pICOReader->count();
880 }
881 
885 bool QtIcoHandler::jumpToImage(int imageNumber)
886 {
887  if (imageNumber < imageCount()) {
888  m_currentIconIndex = imageNumber;
889  }
890 
891  return (imageNumber < imageCount()) ? true : false;
892 }
893 
898 {
899  return jumpToImage(m_currentIconIndex + 1);
900 }
901 
The QVariant class acts like a union for the most common Qt data types.
Definition: qvariant.h:92
static bool writeIconDir(QIODevice *iodev, const ICONDIR &iconDir)
quint32 dwBytesInRes
Definition: qicohandler.cpp:73
void read4BitBMP(QImage &image)
Format
The following image formats are available in Qt.
Definition: qimage.h:91
unsigned int QRgb
Definition: qrgb.h:53
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
quint32 biHeight
Definition: qicohandler.cpp:90
#define ICONDIR_SIZE
Definition: qicohandler.cpp:85
void readBMP(QImage &image)
Q_GUI_EXPORT_INLINE int qAlpha(QRgb rgb)
Definition: qrgb.h:66
bool open(OpenMode openMode)
Reimplemented Function
Definition: qbuffer.cpp:338
quint8 bHeight
Definition: qicohandler.cpp:68
quint16 qFromLittleEndian< quint16 >(const uchar *src)
Definition: qendian.h:157
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
void fill(uint pixel)
Fills the entire image with the given pixelValue.
Definition: qimage.cpp:2032
The QByteArray class provides an array of bytes.
Definition: qbytearray.h:135
#define BMP_INFOHDR_SIZE
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
quint8 bColorCount
Definition: qicohandler.cpp:69
ICONDIRENTRY idEntries[1]
Definition: qicohandler.cpp:83
bool canRead() const
Verifies if some values (magic bytes) are set as expected in the header of the file.
bool write(const QImage &image)
Reimplemented Function
int bytesPerLine() const
Returns the number of bytes per image scanline.
Definition: qimage.cpp:1812
int count(const T &t) const
Returns the number of occurrences of value in the list.
Definition: qlist.h:891
unsigned char quint8
Definition: qglobal.h:934
QImage iconAt(int index)
The QBuffer class provides a QIODevice interface for a QByteArray.
Definition: qbuffer.h:57
bool read(QImage *image)
Reimplemented Function
quint16 wBitCount
Definition: qicohandler.cpp:72
void ungetChar(char c)
Puts the character c back into the device, and decrements the current position unless the position is...
Definition: qiodevice.cpp:1462
quint32 biWidth
Definition: qicohandler.cpp:89
static bool write(QIODevice *device, const QList< QImage > &images)
Writes all the QImages in the images list to the given device.
#define Q_ASSERT(cond)
Definition: qglobal.h:1823
bool readHeader()
quint16 biBitCount
Definition: qicohandler.cpp:92
static bool readIconDir(QIODevice *iodev, ICONDIR *iconDir)
qint32 biSizeImage
Definition: qbmphandler_p.h:77
Q_GUI_EXPORT_INLINE int qRed(QRgb rgb)
Definition: qrgb.h:57
qint32 biClrUsed
Definition: qbmphandler_p.h:80
qint32 biWidth
Definition: qbmphandler_p.h:72
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
quint32 biYPelsPerMeter
Definition: qicohandler.cpp:96
#define ICONDIRENTRY_SIZE
Definition: qicohandler.cpp:76
quint16 biPlanes
Definition: qicohandler.cpp:91
unsigned char uchar
Definition: qglobal.h:994
quint32 biSize
Definition: qicohandler.cpp:88
void append(const T &t)
Inserts value at the end of the list.
Definition: qlist.h:507
void setColorCount(int)
Resizes the color table to contain colorCount entries.
Definition: qimage.cpp:2275
quint16 idReserved
Definition: qicohandler.cpp:80
qint64 startpos
#define QT_BEGIN_NAMESPACE
This macro expands to.
Definition: qglobal.h:89
Q_GUI_EXPORT_INLINE QRgb qRgba(int r, int g, int b, int a)
Definition: qrgb.h:72
bool headerRead
struct ICONDIR * LPICONDIR
qint32 biYPelsPerMeter
Definition: qbmphandler_p.h:79
ImageOption
This enum describes the different options supported by QImageIOHandler.
int imageCount() const
Reimplemented Function
struct BMP_INFOHDR * LPBMP_INFOHDR
static QByteArray fromRawData(const char *, int size)
Constructs a QByteArray that uses the first size bytes of the data array.
unsigned short quint16
Definition: qglobal.h:936
Q_CORE_EXPORT void qWarning(const char *,...)
quint32 biSizeImage
Definition: qicohandler.cpp:94
quint32 qFromLittleEndian< quint32 >(const uchar *src)
Definition: qendian.h:148
bool supportsOption(ImageOption option) const
Returns true if the QImageIOHandler supports the option option; otherwise returns false...
The QImage class provides a hardware-independent image representation that allows direct access to th...
Definition: qimage.h:87
quint32 biClrUsed
Definition: qicohandler.cpp:97
void readColorTable(QImage &image)
quint16 wPlanes
Definition: qicohandler.cpp:71
#define FALSE
Synonym for false.
Definition: qglobal.h:1019
QImage createAlphaMask(Qt::ImageConversionFlags flags=Qt::AutoColor) const
Builds and returns a 1-bpp mask from the alpha buffer in this image.
Definition: qimage.cpp:4720
void read16_24_32BMP(QImage &image)
ICONDIR iconDir
virtual ~QtIcoHandler()
Destructor for QtIcoHandler.
__int64 qint64
Definition: qglobal.h:942
handler setDevice(device)
ICOReader(QIODevice *iodevice)
qint16 biBitCount
Definition: qbmphandler_p.h:75
void findColorInfo(QImage &image)
Q_GUI_EXPORT_INLINE int qBlue(QRgb rgb)
Definition: qrgb.h:63
QtIcoHandler(QIODevice *device)
Constructs an instance of QtIcoHandler initialized to use device.
virtual bool isSequential() const
Returns true if this device is sequential; otherwise returns false.
Definition: qiodevice.cpp:454
static bool readBMPInfoHeader(QIODevice *iodev, BMP_INFOHDR *pHeader)
#define rgb(r, g, b)
Definition: qcolor_p.cpp:130
#define TRUE
Synonym for true.
Definition: qglobal.h:1018
static const MacSpecialKey entries[NumEntries]
#define Q_CHECK_PTR(p)
Definition: qglobal.h:1853
int width() const
Returns the width of the image.
Definition: qimage.cpp:1557
quint32 biClrImportant
Definition: qicohandler.cpp:98
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
struct ICOReader::IcoAttrib icoAttrib
quint8 bReserved
Definition: qicohandler.cpp:70
quint32 biCompression
Definition: qicohandler.cpp:93
qint32 biCompression
Definition: qbmphandler_p.h:76
Q_GUI_EXPORT_INLINE QRgb qRgb(int r, int g, int b)
Definition: qrgb.h:69
unsigned int quint32
Definition: qglobal.h:938
bool jumpToImage(int imageNumber)
Reimplemented Function
QIODevice * device() const
Returns the device currently assigned to the QImageIOHandler.
static bool readIconDirEntry(QIODevice *iodev, ICONDIRENTRY *iconDirEntry)
int height() const
Returns the height of the image.
Definition: qimage.cpp:1572
int size() const
Returns the number of bytes in this byte array.
Definition: qbytearray.h:402
quint16 index
Q_GUI_EXPORT_INLINE int qGreen(QRgb rgb)
Definition: qrgb.h:60
qint32 biClrImportant
Definition: qbmphandler_p.h:81
static bool canRead(QIODevice *iodev)
The QSize class defines the size of a two-dimensional object using integer point precision.
Definition: qsize.h:53
bool readIconEntry(int index, ICONDIRENTRY *iconEntry)
QVariant option(ImageOption option) const
Returns the value assigned to option as a QVariant.
void setAlphaChannel(const QImage &alphaChannel)
Sets the alpha channel of this image to the given alphaChannel.
Definition: qimage.cpp:6329
qint64 write(const char *data, qint64 len)
Writes at most maxSize bytes of data from data to the device.
Definition: qiodevice.cpp:1342
quint16 idType
Definition: qicohandler.cpp:81
QImage scaled(int w, int h, Qt::AspectRatioMode aspectMode=Qt::IgnoreAspectRatio, Qt::TransformationMode mode=Qt::FastTransformation) const
Definition: qimage.h:232
bool readBMPHeader(quint32 imageOffset, BMP_INFOHDR *header)
struct ICONDIRENTRY * LPICONDIRENTRY
static const KeyPair *const end
static bool writeIconDirEntry(QIODevice *iodev, const ICONDIRENTRY &iconEntry)
The QIODevice class is the base interface class of all I/O devices in Qt.
Definition: qiodevice.h:66
static QList< QImage > read(QIODevice *device)
Reads all the icons from the given device, and returns them as a list of QImage objects.
qint32 biXPelsPerMeter
Definition: qbmphandler_p.h:78
static bool writeBMPInfoHeader(QIODevice *iodev, const BMP_INFOHDR &header)
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
T qToLittleEndian(T source)
Definition: qendian.h:341
quint16 idCount
Definition: qicohandler.cpp:82
static QImage fromData(const uchar *data, int size, const char *format=0)
Constructs a QImage from the first size bytes of the given binary data.
Definition: qimage.cpp:5313
quint32 biXPelsPerMeter
Definition: qicohandler.cpp:95
QIODevice * iod
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
bool jumpToNextImage()
Reimplemented Function
qint32 biHeight
Definition: qbmphandler_p.h:73
void read1BitBMP(QImage &image)
void read8BitBMP(QImage &image)
quint32 dwImageOffset
Definition: qicohandler.cpp:74
QByteArray name() const
Return the common identifier of the format.