211static bool read_dib_body(QDataStream &s,
const BMP_INFOHDR &bi, qint64 datapos, qint64 startpos, QImage &image)
213 QIODevice* d = s.device();
217 qDebug(
"offset...........%lld", datapos);
218 qDebug(
"startpos.........%lld", startpos);
219 qDebug(
"biSize...........%d", bi.biSize);
220 qDebug(
"biWidth..........%d", bi.biWidth);
221 qDebug(
"biHeight.........%d", bi.biHeight);
222 qDebug(
"biPlanes.........%d", bi.biPlanes);
223 qDebug(
"biBitCount.......%d", bi.biBitCount);
224 qDebug(
"biCompression....%d", bi.biCompression);
225 qDebug(
"biSizeImage......%d", bi.biSizeImage);
226 qDebug(
"biXPelsPerMeter..%d", bi.biXPelsPerMeter);
227 qDebug(
"biYPelsPerMeter..%d", bi.biYPelsPerMeter);
228 qDebug(
"biClrUsed........%d", bi.biClrUsed);
229 qDebug(
"biClrImportant...%d", bi.biClrImportant);
231 int w = bi.biWidth, h = bi.biHeight, nbits = bi.biBitCount;
232 int t = bi.biSize, comp = bi.biCompression;
238 uint green_shift = 0;
240 uint alpha_shift = 0;
242 uint green_scale = 0;
244 uint alpha_scale = 0;
247 if (!d->isSequential())
248 d->seek(startpos + bi.biSize);
251 red_mask = bi.biRedMask;
252 green_mask = bi.biGreenMask;
253 blue_mask = bi.biBlueMask;
254 alpha_mask = bi.biAlphaMask;
255 }
else if (bitfields && (nbits == 16 || nbits == 32)) {
256 if (d->read((
char *)&red_mask,
sizeof(red_mask)) !=
sizeof(red_mask))
258 if (d->read((
char *)&green_mask,
sizeof(green_mask)) !=
sizeof(green_mask))
260 if (d->read((
char *)&blue_mask,
sizeof(blue_mask)) !=
sizeof(blue_mask))
262 if (comp ==
BMP_ALPHABITFIELDS && d->read((
char *)&alpha_mask,
sizeof(alpha_mask)) !=
sizeof(alpha_mask))
266 bool transp = bitfields || (comp ==
BMP_RGB && nbits == 32 && alpha_mask == 0xff000000);
267 transp = transp && alpha_mask;
271 QImage::Format format;
277 format = transp ? QImage::Format_ARGB32 : QImage::Format_RGB32;
282 format = QImage::Format_Indexed8;
286 format = QImage::Format_Mono;
294 ncols = bi.biClrUsed ? bi.biClrUsed : 1 << nbits;
295 if (ncols < 1 || ncols > 256)
302 if (!QImageIOHandler::allocateImage(QSize(w, h), format, &image))
306 image.setColorCount(ncols);
308 int rgb_len = t ==
BMP_OLD ? 3 : 4;
309 for (
int i=0; i<ncols; i++) {
310 if (d->read((
char *)rgb, rgb_len) != rgb_len)
312 image.setColor(i, qRgb(rgb[2],rgb[1],rgb[0]));
316 }
else if (bitfields && (nbits == 16 || nbits == 32)) {
318 if (((red_mask >> red_shift) + 1) == 0)
322 if (((green_mask >> green_shift) + 1) == 0)
326 if (((blue_mask >> blue_shift) + 1) == 0)
330 if (((alpha_mask >> alpha_shift) + 1) == 0)
333 }
else if (comp ==
BMP_RGB && (nbits == 24 || nbits == 32)) {
334 blue_mask = 0x000000ff;
335 green_mask = 0x0000ff00;
336 red_mask = 0x00ff0000;
340 blue_scale = green_scale = red_scale = 0;
343 if (((alpha_mask >> alpha_shift) + 1) == 0)
347 }
else if (comp ==
BMP_RGB && nbits == 16) {
354 blue_scale = green_scale = red_scale = 3;
357 image.setDotsPerMeterX(bi.biXPelsPerMeter);
358 image.setDotsPerMeterY(bi.biYPelsPerMeter);
361 qDebug(
"Rmask: %08x Rshift: %08x Rscale:%08x", red_mask, red_shift, red_scale);
362 qDebug(
"Gmask: %08x Gshift: %08x Gscale:%08x", green_mask, green_shift, green_scale);
363 qDebug(
"Bmask: %08x Bshift: %08x Bscale:%08x", blue_mask, blue_shift, blue_scale);
364 qDebug(
"Amask: %08x Ashift: %08x Ascale:%08x", alpha_mask, alpha_shift, alpha_scale);
367 if (datapos >= 0 && datapos > d->pos()) {
368 if (!d->isSequential())
372 int bpl = image.bytesPerLine();
373 uchar *data = image.bits();
377 if (d->read((
char*)(data + h*bpl), bpl) != bpl)
380 if (ncols == 2 && qGray(image.color(0)) < qGray(image.color(1)))
384 else if (nbits == 4) {
385 int buflen = ((w+7)/8)*4;
386 uchar *buf =
new uchar[buflen];
390 uchar *p = data + (h-1)*bpl;
391 const uchar *endp = p + w;
393 if (!d->getChar((
char *)&b))
396 if (!d->getChar((
char *)&b) || b == 1) {
402 p = data + (h-y-1)*bpl;
407 d->getChar((
char *)&tmp);
409 d->getChar((
char *)&tmp);
414 if ((uint)x >= (uint)w)
416 if ((uint)y >= (uint)h)
419 p = data + (h-y-1)*bpl + x;
428 d->getChar((
char *)&b);
433 unsigned char tmp = 0;
434 d->getChar((
char *)&tmp);
437 if ((((c & 3) + 1) & 2) == 2)
447 d->getChar((
char *)&b);
459 if (d->read((
char*)buf,buflen) != buflen)
461 uchar *p = data + h*bpl;
463 for (
int i=0; i<w/2; i++) {
474 else if (nbits == 8) {
478 uchar *p = data + (h-1)*bpl;
479 const uchar *endp = p + w;
481 if (!d->getChar((
char *)&b))
484 if (!d->getChar((
char *)&b) || b == 1) {
490 p = data + (h-y-1)*bpl;
495 d->getChar((
char *)&tmp);
497 d->getChar((
char *)&tmp);
502 if ((uint)x >= (uint)w)
504 if ((uint)y >= (uint)h)
507 p = data + (h-y-1)*bpl + x;
514 if (d->read((
char *)p, b) != b)
535 if (d->read((
char *)data + h*bpl, bpl) != bpl)
541 else if (nbits == 16 || nbits == 24 || nbits == 32) {
544 uchar *buf24 =
new uchar[bpl];
545 qint64 bpl24 = ((qint64(w)*nbits+31)/32)*4;
550 p = (QRgb *)(data + h*bpl);
552 if (d->read((
char *)buf24,bpl24) != bpl24)
556 c = *(uchar*)b | (*(uchar*)(b+1)<<8);
558 c |= *(uchar*)(b+2)<<16;
560 c |= *(uchar*)(b+3)<<24;
564 transp ?
apply_scale((c & alpha_mask) >> alpha_shift
, alpha_scale
) : 0xff);
571 if (bi.biHeight < 0) {
573 uchar *buf =
new uchar[bpl];
575 for (
int y = 0; y < h/2; ++y) {
576 memcpy(buf, data + y*bpl, bpl);
577 memcpy(data + y*bpl, data + (h-y-1)*bpl, bpl);
578 memcpy(data + (h-y-1)*bpl, buf, bpl);
583 if (ncols > 0 && ncols < (1 << nbits)) {
589 for (
int y = 0; y < image.height() && maxIndex < 255; ++y) {
590 const uchar *p = image.constScanLine(y);
591 maxIndex = qMax(maxIndex,
int(*
std::max_element(p, p + image.width())));
594 if (maxIndex >= ncols) {
595 image.setColorCount(maxIndex + 1);
596 for (
int i = ncols; i <= maxIndex; ++i)
597 image.setColor(i, qRgb(0, 0, 0));
604bool qt_write_dib(QDataStream &s,
const QImage &image,
int bpl,
int bpl_bmp,
int nbits)
606 QIODevice* d = s.device();
607 if (!d->isWritable())
610 BMP_INFOHDR bi = { };
612 bi.biWidth = image.width();
613 bi.biHeight = image.height();
615 bi.biBitCount = nbits;
617 bi.biSizeImage = bpl_bmp*image.height();
618 bi.biXPelsPerMeter = image.dotsPerMeterX() ? image.dotsPerMeterX()
620 bi.biYPelsPerMeter = image.dotsPerMeterY() ? image.dotsPerMeterY() : 2834;
621 bi.biClrUsed = image.colorCount();
622 bi.biClrImportant = image.colorCount();
626 if (image.depth() != 32) {
627 uchar *color_table =
new uchar[4*image.colorCount()];
628 uchar *rgb = color_table;
629 const QList<QRgb> c = image.colorTable();
630 for (
int i = 0; i < image.colorCount(); i++) {
631 *rgb++ = qBlue (c[i]);
632 *rgb++ = qGreen(c[i]);
633 *rgb++ = qRed (c[i]);
636 if (d->write((
char *)color_table, 4*image.colorCount()) == -1) {
637 delete [] color_table;
640 delete [] color_table;
645 if (nbits == 1 || nbits == 8) {
646 for (y=image.height()-1; y>=0; y--) {
647 if (d->write((
const char*)image.constScanLine(y), bpl) == -1)
653 uchar *buf =
new uchar[bpl_bmp];
657 memset(buf, 0, bpl_bmp);
658 for (y=image.height()-1; y>=0; y--) {
660 p = image.constScanLine(y);
662 end = b + image.width()/2;
664 *b++ = (*p << 4) | (*(p+1) & 0x0f);
667 if (image.width() & 1)
670 const QRgb *p = (
const QRgb *)image.constScanLine(y);
671 const QRgb *end = p + image.width();
680 if (bpl_bmp != d->write((
char*)buf, bpl_bmp)) {
749bool QBmpHandler::read(QImage *image)
755 qWarning(
"QBmpHandler::read: cannot read into null pointer");
759 if (state == Ready && !readHeader()) {
764 QIODevice *d = device();
768 s.setByteOrder(QDataStream::LittleEndian);
771 qint64 datapos = startpos;
772 if (m_format == BmpFormat) {
773 datapos += fileHeader.bfOffBits;
778 if (infoHeader.biSizeImage > 0 && infoHeader.biSizeImage < d->size()) {
779 datapos = d->size() - infoHeader.biSizeImage;
783 datapos += infoHeader.biSize;
785 if (infoHeader.biBitCount == 16 || infoHeader.biBitCount == 32) {
786 if (infoHeader.biCompression == BMP_BITFIELDS) {
788 }
else if (infoHeader.biCompression == BMP_ALPHABITFIELDS) {
794 const bool readSuccess = m_format == BmpFormat ?
795 read_dib_body(s, infoHeader, datapos, startpos + BMP_FILEHDR_SIZE, *image) :
796 read_dib_body(s, infoHeader, datapos, startpos, *image);
804bool QBmpHandler::write(
const QImage &img)
807 switch (img.format()) {
808 case QImage::Format_Mono:
809 case QImage::Format_Indexed8:
810 case QImage::Format_RGB32:
811 case QImage::Format_ARGB32:
814 case QImage::Format_MonoLSB:
815 image = img.convertToFormat(QImage::Format_Mono);
817 case QImage::Format_Alpha8:
818 case QImage::Format_Grayscale8:
819 image = img.convertToFormat(QImage::Format_Indexed8);
822 if (img.hasAlphaChannel())
823 image = img.convertToFormat(QImage::Format_ARGB32);
825 image = img.convertToFormat(QImage::Format_RGB32);
832 qsizetype bpl = ((image.width() * image.depth() + 31) >> 5) << 2;
834 if (image.depth() == 8 && image.colorCount() <= 16) {
835 bpl_bmp = (((bpl+1)/2+3)/4)*4;
837 }
else if (image.depth() == 32) {
838 bpl_bmp = ((image.width()*24+31)/32)*4;
842 nbits = image.depth();
844 if (qsizetype(
int(bpl_bmp)) != bpl_bmp)
847 if (m_format == DibFormat) {
848 QDataStream dibStream(device());
849 dibStream.setByteOrder(QDataStream::LittleEndian);
850 return qt_write_dib(dibStream, img, bpl, bpl_bmp, nbits);
853 QIODevice *d = device();
858 s.setByteOrder(QDataStream::LittleEndian);
861 memcpy(bf.bfType,
"BM", 2);
866 bf.bfOffBits = BMP_FILEHDR_SIZE + BMP_WIN + image.colorCount() * 4;
867 bf.bfSize = bf.bfOffBits + bpl_bmp*image.height();
868 if (qsizetype(bf.bfSize) != bf.bfOffBits + bpl_bmp*image.height())
873 return qt_write_dib(s, image, bpl, bpl_bmp, nbits);