diff options
Diffstat (limited to 'src/gui/image/qpnghandler.cpp')
-rw-r--r-- | src/gui/image/qpnghandler.cpp | 154 |
1 files changed, 125 insertions, 29 deletions
diff --git a/src/gui/image/qpnghandler.cpp b/src/gui/image/qpnghandler.cpp index 42b9e71087..242d8cd63b 100644 --- a/src/gui/image/qpnghandler.cpp +++ b/src/gui/image/qpnghandler.cpp @@ -245,7 +245,7 @@ void setup_qt(QImage& image, png_structp png_ptr, png_infop info_ptr, QSize scal png_set_interlace_handling(png_ptr); if (color_type == PNG_COLOR_TYPE_GRAY) { - // Black & White or 8-bit grayscale + // Black & White or grayscale if (bit_depth == 1 && png_get_channels(png_ptr, info_ptr) == 1) { png_set_invert_mono(png_ptr); png_read_update_info(png_ptr, info_ptr); @@ -266,19 +266,22 @@ void setup_qt(QImage& image, png_structp png_ptr, png_infop info_ptr, QSize scal else if (g == 1) image.setColor(0, qRgba(255, 255, 255, 0)); } - } else if (bit_depth == 16 && png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { - png_set_expand(png_ptr); - png_set_strip_16(png_ptr); + } else if (bit_depth == 16) { + bool hasMask = png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS); + if (!hasMask) + png_set_filler(png_ptr, 0xffff, PNG_FILLER_AFTER); + else + png_set_expand(png_ptr); png_set_gray_to_rgb(png_ptr); - if (image.size() != QSize(width, height) || image.format() != QImage::Format_ARGB32) { - image = QImage(width, height, QImage::Format_ARGB32); + QImage::Format format = hasMask ? QImage::Format_RGBA64 : QImage::Format_RGBX64; + if (image.size() != QSize(width, height) || image.format() != format) { + image = QImage(width, height, format); if (image.isNull()) return; } - if (QSysInfo::ByteOrder == QSysInfo::BigEndian) - png_set_swap_alpha(png_ptr); - png_read_update_info(png_ptr, info_ptr); + if (QSysInfo::ByteOrder == QSysInfo::LittleEndian) + png_set_swap(png_ptr); } else if (bit_depth == 8 && !png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { png_set_expand(png_ptr); if (image.size() != QSize(width, height) || image.format() != QImage::Format_Grayscale8) { @@ -289,9 +292,7 @@ void setup_qt(QImage& image, png_structp png_ptr, png_infop info_ptr, QSize scal png_read_update_info(png_ptr, info_ptr); } else { - if (bit_depth == 16) - png_set_strip_16(png_ptr); - else if (bit_depth < 8) + if (bit_depth < 8) png_set_packing(png_ptr); int ncols = bit_depth < 8 ? 1 << bit_depth : 256; png_read_update_info(png_ptr, info_ptr); @@ -352,6 +353,26 @@ void setup_qt(QImage& image, png_structp png_ptr, png_infop info_ptr, QSize scal ); i++; } + // Qt==ARGB==Big(ARGB)==Little(BGRA) + if (QSysInfo::ByteOrder == QSysInfo::LittleEndian) { + png_set_bgr(png_ptr); + } + } else if (bit_depth == 16 && !(color_type & PNG_COLOR_MASK_PALETTE)) { + QImage::Format format = QImage::Format_RGBA64; + if (!(color_type & PNG_COLOR_MASK_ALPHA) && !png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { + png_set_filler(png_ptr, 0xffff, PNG_FILLER_AFTER); + format = QImage::Format_RGBX64; + } + if (!(color_type & PNG_COLOR_MASK_COLOR)) + png_set_gray_to_rgb(png_ptr); + if (image.size() != QSize(width, height) || image.format() != format) { + image = QImage(width, height, format); + if (image.isNull()) + return; + } + png_read_update_info(png_ptr, info_ptr); + if (QSysInfo::ByteOrder == QSysInfo::LittleEndian) + png_set_swap(png_ptr); } else { // 32-bit if (bit_depth == 16) @@ -388,12 +409,12 @@ void setup_qt(QImage& image, png_structp png_ptr, png_infop info_ptr, QSize scal if (QSysInfo::ByteOrder == QSysInfo::BigEndian) png_set_swap_alpha(png_ptr); - png_read_update_info(png_ptr, info_ptr); - } + // Qt==ARGB==Big(ARGB)==Little(BGRA) + if (QSysInfo::ByteOrder == QSysInfo::LittleEndian) { + png_set_bgr(png_ptr); + } - // Qt==ARGB==Big(ARGB)==Little(BGRA) - if (QSysInfo::ByteOrder == QSysInfo::LittleEndian) { - png_set_bgr(png_ptr); + png_read_update_info(png_ptr, info_ptr); } } @@ -662,11 +683,11 @@ QImage::Format QPngHandlerPrivate::readImageFormat() int num_palette; png_get_IHDR(png_ptr, info_ptr, &width, &height, &bit_depth, &color_type, 0, 0, 0); if (color_type == PNG_COLOR_TYPE_GRAY) { - // Black & White or 8-bit grayscale + // Black & White or grayscale if (bit_depth == 1 && png_get_channels(png_ptr, info_ptr) == 1) { format = QImage::Format_Mono; - } else if (bit_depth == 16 && png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { - format = QImage::Format_ARGB32; + } else if (bit_depth == 16) { + format = png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS) ? QImage::Format_RGBA64 : QImage::Format_RGBX64; } else if (bit_depth == 8 && !png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) { format = QImage::Format_Grayscale8; } else { @@ -678,6 +699,10 @@ QImage::Format QPngHandlerPrivate::readImageFormat() { // 1-bit and 8-bit color format = bit_depth == 1 ? QImage::Format_Mono : QImage::Format_Indexed8; + } else if (bit_depth == 16 && !(color_type & PNG_COLOR_MASK_PALETTE)) { + format = QImage::Format_RGBA64; + if (!(color_type & PNG_COLOR_MASK_ALPHA) && !png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) + format = QImage::Format_RGBX64; } else { // 32-bit format = QImage::Format_ARGB32; @@ -843,8 +868,24 @@ bool QPNGImageWriter::writeImage(const QImage& image, volatile int quality_in, c else color_type = PNG_COLOR_TYPE_RGB; + int bpc = 0; + switch (image.format()) { + case QImage::Format_Mono: + case QImage::Format_MonoLSB: + bpc = 1; + break; + case QImage::Format_RGBX64: + case QImage::Format_RGBA64: + case QImage::Format_RGBA64_Premultiplied: + bpc = 16; + break; + default: + bpc = 8; + break; + } + png_set_IHDR(png_ptr, info_ptr, image.width(), image.height(), - image.depth() == 1 ? 1 : 8, // per channel + bpc, // per channel color_type, 0, 0, 0); // sets #channels if (gamma != 0.0) { @@ -880,13 +921,31 @@ bool QPNGImageWriter::writeImage(const QImage& image, volatile int quality_in, c // Swap ARGB to RGBA (normal PNG format) before saving on // BigEndian machines if (QSysInfo::ByteOrder == QSysInfo::BigEndian) { - png_set_swap_alpha(png_ptr); + switch (image.format()) { + case QImage::Format_RGBX8888: + case QImage::Format_RGBA8888: + case QImage::Format_RGBX64: + case QImage::Format_RGBA64: + case QImage::Format_RGBA64_Premultiplied: + break; + default: + png_set_swap_alpha(png_ptr); + } } // Qt==ARGB==Big(ARGB)==Little(BGRA). But RGB888 is RGB regardless - if (QSysInfo::ByteOrder == QSysInfo::LittleEndian - && image.format() != QImage::Format_RGB888) { - png_set_bgr(png_ptr); + if (QSysInfo::ByteOrder == QSysInfo::LittleEndian) { + switch (image.format()) { + case QImage::Format_RGB888: + case QImage::Format_RGBX8888: + case QImage::Format_RGBA8888: + case QImage::Format_RGBX64: + case QImage::Format_RGBA64: + case QImage::Format_RGBA64_Premultiplied: + break; + default: + png_set_bgr(png_ptr); + } } if (off_x || off_y) { @@ -909,10 +968,32 @@ bool QPNGImageWriter::writeImage(const QImage& image, volatile int quality_in, c if (image.depth() != 1) png_set_packing(png_ptr); - if (color_type == PNG_COLOR_TYPE_RGB && image.format() != QImage::Format_RGB888) - png_set_filler(png_ptr, 0, - QSysInfo::ByteOrder == QSysInfo::BigEndian ? - PNG_FILLER_BEFORE : PNG_FILLER_AFTER); + if (color_type == PNG_COLOR_TYPE_RGB) { + switch (image.format()) { + case QImage::Format_RGB888: + break; + case QImage::Format_RGBX8888: + case QImage::Format_RGBX64: + png_set_filler(png_ptr, 0, PNG_FILLER_AFTER); + break; + default: + png_set_filler(png_ptr, 0, + QSysInfo::ByteOrder == QSysInfo::BigEndian ? + PNG_FILLER_BEFORE : PNG_FILLER_AFTER); + } + } + + if (QSysInfo::ByteOrder == QSysInfo::LittleEndian) { + switch (image.format()) { + case QImage::Format_RGBX64: + case QImage::Format_RGBA64: + case QImage::Format_RGBA64_Premultiplied: + png_set_swap(png_ptr); + break; + default: + break; + } + } if (looping >= 0 && frames_written == 0) { uchar data[13] = "NETSCAPE2.0"; @@ -940,6 +1021,10 @@ bool QPNGImageWriter::writeImage(const QImage& image, volatile int quality_in, c case QImage::Format_RGB32: case QImage::Format_ARGB32: case QImage::Format_RGB888: + case QImage::Format_RGBX8888: + case QImage::Format_RGBA8888: + case QImage::Format_RGBX64: + case QImage::Format_RGBA64: { png_bytep* row_pointers = new png_bytep[height]; for (int y=0; y<height; y++) @@ -948,6 +1033,17 @@ bool QPNGImageWriter::writeImage(const QImage& image, volatile int quality_in, c delete [] row_pointers; } break; + case QImage::Format_RGBA64_Premultiplied: + { + QImage row; + png_bytep row_pointers[1]; + for (int y=0; y<height; y++) { + row = image.copy(0, y, width, 1).convertToFormat(QImage::Format_RGBA64); + row_pointers[0] = const_cast<png_bytep>(row.constScanLine(0)); + png_write_rows(png_ptr, row_pointers, 1); + } + } + break; default: { QImage::Format fmt = image.hasAlphaChannel() ? QImage::Format_ARGB32 : QImage::Format_RGB32; |