209static bool read_dib_body(QDataStream &s,
const BMP_INFOHDR &bi, qint64 datapos, qint64 startpos, QImage &image)
211 QIODevice* d = s.device();
215 qDebug(
"offset...........%lld", datapos);
216 qDebug(
"startpos.........%lld", startpos);
217 qDebug(
"biSize...........%d", bi.biSize);
218 qDebug(
"biWidth..........%d", bi.biWidth);
219 qDebug(
"biHeight.........%d", bi.biHeight);
220 qDebug(
"biPlanes.........%d", bi.biPlanes);
221 qDebug(
"biBitCount.......%d", bi.biBitCount);
222 qDebug(
"biCompression....%d", bi.biCompression);
223 qDebug(
"biSizeImage......%d", bi.biSizeImage);
224 qDebug(
"biXPelsPerMeter..%d", bi.biXPelsPerMeter);
225 qDebug(
"biYPelsPerMeter..%d", bi.biYPelsPerMeter);
226 qDebug(
"biClrUsed........%d", bi.biClrUsed);
227 qDebug(
"biClrImportant...%d", bi.biClrImportant);
229 int w = bi.biWidth, h = bi.biHeight, nbits = bi.biBitCount;
230 int t = bi.biSize, comp = bi.biCompression;
236 uint green_shift = 0;
238 uint alpha_shift = 0;
240 uint green_scale = 0;
242 uint alpha_scale = 0;
245 if (!d->isSequential())
246 d->seek(startpos + bi.biSize);
249 red_mask = bi.biRedMask;
250 green_mask = bi.biGreenMask;
251 blue_mask = bi.biBlueMask;
252 alpha_mask = bi.biAlphaMask;
253 }
else if (bitfields && (nbits == 16 || nbits == 32)) {
254 if (d->read((
char *)&red_mask,
sizeof(red_mask)) !=
sizeof(red_mask))
256 if (d->read((
char *)&green_mask,
sizeof(green_mask)) !=
sizeof(green_mask))
258 if (d->read((
char *)&blue_mask,
sizeof(blue_mask)) !=
sizeof(blue_mask))
260 if (comp ==
BMP_ALPHABITFIELDS && d->read((
char *)&alpha_mask,
sizeof(alpha_mask)) !=
sizeof(alpha_mask))
264 bool transp = bitfields || (comp ==
BMP_RGB && nbits == 32 && alpha_mask == 0xff000000);
265 transp = transp && alpha_mask;
269 QImage::Format format;
275 format = transp ? QImage::Format_ARGB32 : QImage::Format_RGB32;
280 format = QImage::Format_Indexed8;
284 format = QImage::Format_Mono;
292 ncols = bi.biClrUsed ? bi.biClrUsed : 1 << nbits;
293 if (ncols < 1 || ncols > 256)
300 if (!QImageIOHandler::allocateImage(QSize(w, h), format, &image))
303 image.setColorCount(ncols);
305 int rgb_len = t ==
BMP_OLD ? 3 : 4;
306 for (
int i=0; i<ncols; i++) {
307 if (d->read((
char *)rgb, rgb_len) != rgb_len)
309 image.setColor(i, qRgb(rgb[2],rgb[1],rgb[0]));
313 }
else if (bitfields && (nbits == 16 || nbits == 32)) {
314 red_shift = calc_shift(red_mask);
315 if (((red_mask >> red_shift) + 1) == 0)
317 red_scale = calc_scale(red_mask >> red_shift);
318 green_shift = calc_shift(green_mask);
319 if (((green_mask >> green_shift) + 1) == 0)
321 green_scale = calc_scale(green_mask >> green_shift);
322 blue_shift = calc_shift(blue_mask);
323 if (((blue_mask >> blue_shift) + 1) == 0)
325 blue_scale = calc_scale(blue_mask >> blue_shift);
326 alpha_shift = calc_shift(alpha_mask);
327 if (((alpha_mask >> alpha_shift) + 1) == 0)
329 alpha_scale = calc_scale(alpha_mask >> alpha_shift);
330 }
else if (comp ==
BMP_RGB && (nbits == 24 || nbits == 32)) {
331 blue_mask = 0x000000ff;
332 green_mask = 0x0000ff00;
333 red_mask = 0x00ff0000;
337 blue_scale = green_scale = red_scale = 0;
339 alpha_shift = calc_shift(alpha_mask);
340 if (((alpha_mask >> alpha_shift) + 1) == 0)
342 alpha_scale = calc_scale(alpha_mask >> alpha_shift);
344 }
else if (comp ==
BMP_RGB && nbits == 16) {
351 blue_scale = green_scale = red_scale = 3;
354 image.setDotsPerMeterX(bi.biXPelsPerMeter);
355 image.setDotsPerMeterY(bi.biYPelsPerMeter);
358 qDebug(
"Rmask: %08x Rshift: %08x Rscale:%08x", red_mask, red_shift, red_scale);
359 qDebug(
"Gmask: %08x Gshift: %08x Gscale:%08x", green_mask, green_shift, green_scale);
360 qDebug(
"Bmask: %08x Bshift: %08x Bscale:%08x", blue_mask, blue_shift, blue_scale);
361 qDebug(
"Amask: %08x Ashift: %08x Ascale:%08x", alpha_mask, alpha_shift, alpha_scale);
364 if (datapos >= 0 && datapos > d->pos()) {
365 if (!d->isSequential())
369 int bpl = image.bytesPerLine();
370 uchar *data = image.bits();
374 if (d->read((
char*)(data + h*bpl), bpl) != bpl)
377 if (ncols == 2 && qGray(image.color(0)) < qGray(image.color(1)))
381 else if (nbits == 4) {
382 int buflen = ((w+7)/8)*4;
383 uchar *buf =
new uchar[buflen];
387 uchar *p = data + (h-1)*bpl;
388 const uchar *endp = p + w;
390 if (!d->getChar((
char *)&b))
393 if (!d->getChar((
char *)&b) || b == 1) {
399 p = data + (h-y-1)*bpl;
404 d->getChar((
char *)&tmp);
406 d->getChar((
char *)&tmp);
411 if ((uint)x >= (uint)w)
413 if ((uint)y >= (uint)h)
416 p = data + (h-y-1)*bpl + x;
425 d->getChar((
char *)&b);
431 d->getChar((
char *)&tmp);
434 if ((((c & 3) + 1) & 2) == 2)
444 d->getChar((
char *)&b);
455 memset(data, 0, h*bpl);
457 if (d->read((
char*)buf,buflen) != buflen)
459 uchar *p = data + h*bpl;
461 for (
int i=0; i<w/2; i++) {
472 else if (nbits == 8) {
476 uchar *p = data + (h-1)*bpl;
477 const uchar *endp = p + w;
479 if (!d->getChar((
char *)&b))
482 if (!d->getChar((
char *)&b) || b == 1) {
488 p = data + (h-y-1)*bpl;
493 d->getChar((
char *)&tmp);
495 d->getChar((
char *)&tmp);
500 if ((uint)x >= (uint)w)
502 if ((uint)y >= (uint)h)
505 p = data + (h-y-1)*bpl + x;
512 if (d->read((
char *)p, b) != b)
533 if (d->read((
char *)data + h*bpl, bpl) != bpl)
539 else if (nbits == 16 || nbits == 24 || nbits == 32) {
542 uchar *buf24 =
new uchar[bpl];
543 int bpl24 = ((w*nbits+31)/32)*4;
548 p = (QRgb *)(data + h*bpl);
550 if (d->read((
char *)buf24,bpl24) != bpl24)
554 c = *(uchar*)b | (*(uchar*)(b+1)<<8);
556 c |= *(uchar*)(b+2)<<16;
558 c |= *(uchar*)(b+3)<<24;
559 *p++ = qRgba(apply_scale((c & red_mask) >> red_shift, red_scale),
560 apply_scale((c & green_mask) >> green_shift, green_scale),
561 apply_scale((c & blue_mask) >> blue_shift, blue_scale),
562 transp ? apply_scale((c & alpha_mask) >> alpha_shift, alpha_scale) : 0xff);
569 if (bi.biHeight < 0) {
571 uchar *buf =
new uchar[bpl];
573 for (
int y = 0; y < h/2; ++y) {
574 memcpy(buf, data + y*bpl, bpl);
575 memcpy(data + y*bpl, data + (h-y-1)*bpl, bpl);
576 memcpy(data + (h-y-1)*bpl, buf, bpl);
584bool qt_write_dib(QDataStream &s,
const QImage &image,
int bpl,
int bpl_bmp,
int nbits)
586 QIODevice* d = s.device();
587 if (!d->isWritable())
592 bi.biWidth = image.width();
593 bi.biHeight = image.height();
595 bi.biBitCount = nbits;
597 bi.biSizeImage = bpl_bmp*image.height();
598 bi.biXPelsPerMeter = image.dotsPerMeterX() ? image.dotsPerMeterX()
600 bi.biYPelsPerMeter = image.dotsPerMeterY() ? image.dotsPerMeterY() : 2834;
601 bi.biClrUsed = image.colorCount();
602 bi.biClrImportant = image.colorCount();
606 if (image.depth() != 32) {
607 uchar *color_table =
new uchar[4*image.colorCount()];
608 uchar *rgb = color_table;
609 const QList<QRgb> c = image.colorTable();
610 for (
int i = 0; i < image.colorCount(); i++) {
611 *rgb++ = qBlue (c[i]);
612 *rgb++ = qGreen(c[i]);
613 *rgb++ = qRed (c[i]);
616 if (d->write((
char *)color_table, 4*image.colorCount()) == -1) {
617 delete [] color_table;
620 delete [] color_table;
625 if (nbits == 1 || nbits == 8) {
626 for (y=image.height()-1; y>=0; y--) {
627 if (d->write((
const char*)image.constScanLine(y), bpl) == -1)
633 uchar *buf =
new uchar[bpl_bmp];
637 memset(buf, 0, bpl_bmp);
638 for (y=image.height()-1; y>=0; y--) {
640 p = image.constScanLine(y);
642 end = b + image.width()/2;
644 *b++ = (*p << 4) | (*(p+1) & 0x0f);
647 if (image.width() & 1)
650 const QRgb *p = (
const QRgb *)image.constScanLine(y);
651 const QRgb *end = p + image.width();
660 if (bpl_bmp != d->write((
char*)buf, bpl_bmp)) {
729bool QBmpHandler::read(QImage *image)
735 qWarning(
"QBmpHandler::read: cannot read into null pointer");
739 if (state == Ready && !readHeader()) {
744 QIODevice *d = device();
748 s.setByteOrder(QDataStream::LittleEndian);
751 qint64 datapos = startpos;
752 if (m_format == BmpFormat) {
753 datapos += fileHeader.bfOffBits;
758 if (infoHeader.biSizeImage > 0 && infoHeader.biSizeImage < d->size()) {
759 datapos = d->size() - infoHeader.biSizeImage;
763 datapos += infoHeader.biSize;
765 if (infoHeader.biBitCount == 16 || infoHeader.biBitCount == 32) {
766 if (infoHeader.biCompression == BMP_BITFIELDS) {
768 }
else if (infoHeader.biCompression == BMP_ALPHABITFIELDS) {
774 const bool readSuccess = m_format == BmpFormat ?
775 read_dib_body(s, infoHeader, datapos, startpos + BMP_FILEHDR_SIZE, *image) :
776 read_dib_body(s, infoHeader, datapos, startpos, *image);
784bool QBmpHandler::write(
const QImage &img)
787 switch (img.format()) {
788 case QImage::Format_Mono:
789 case QImage::Format_Indexed8:
790 case QImage::Format_RGB32:
791 case QImage::Format_ARGB32:
794 case QImage::Format_MonoLSB:
795 image = img.convertToFormat(QImage::Format_Mono);
797 case QImage::Format_Alpha8:
798 case QImage::Format_Grayscale8:
799 image = img.convertToFormat(QImage::Format_Indexed8);
802 if (img.hasAlphaChannel())
803 image = img.convertToFormat(QImage::Format_ARGB32);
805 image = img.convertToFormat(QImage::Format_RGB32);
812 qsizetype bpl = ((image.width() * image.depth() + 31) >> 5) << 2;
814 if (image.depth() == 8 && image.colorCount() <= 16) {
815 bpl_bmp = (((bpl+1)/2+3)/4)*4;
817 }
else if (image.depth() == 32) {
818 bpl_bmp = ((image.width()*24+31)/32)*4;
822 nbits = image.depth();
824 if (qsizetype(
int(bpl_bmp)) != bpl_bmp)
827 if (m_format == DibFormat) {
828 QDataStream dibStream(device());
829 dibStream.setByteOrder(QDataStream::LittleEndian);
830 return qt_write_dib(dibStream, img, bpl, bpl_bmp, nbits);
833 QIODevice *d = device();
838 s.setByteOrder(QDataStream::LittleEndian);
841 memcpy(bf.bfType,
"BM", 2);
846 bf.bfOffBits = BMP_FILEHDR_SIZE + BMP_WIN + image.colorCount() * 4;
847 bf.bfSize = bf.bfOffBits + bpl_bmp*image.height();
848 if (qsizetype(bf.bfSize) != bf.bfOffBits + bpl_bmp*image.height())
853 return qt_write_dib(s, image, bpl, bpl_bmp, nbits);