5#include "private/qpnghandler_p.h"
7#ifndef QT_NO_IMAGEFORMAT_PNG
15#include <private/qimage_p.h>
18#include <private/qcolorspace_p.h>
23#if PNG_LIBPNG_VER >= 10400 && PNG_LIBPNG_VER <= 10502 \
24 && defined(PNG_PEDANTIC_WARNINGS_SUPPORTED)
37# ifdef PNG_SETJMP_SUPPORTED
38# define png_jmpbuf(png_ptr) \
39 (*png_set_longjmp_fn((png_ptr), (png_longjmp_ptr)longjmp, sizeof(jmp_buf)))
41# define png_jmpbuf(png_ptr) \
42 (LIBPNG_WAS_COMPILED_WITH__PNG_NO_SETJMP)
53#define FAST_SCAN_LINE(data, bpl, y) (data + (y) * bpl)
170 uchar endcrc[4] = { 0xae, 0x42, 0x60, 0x82 };
171 memcpy(
data, endcrc, 4);
172 in->seek(
in->size());
179 png_error(png_ptr,
"Read Error");
195 png_error(png_ptr,
"Write Error");
211 png_uint_32
width = 0;
215 png_bytep trans_alpha =
nullptr;
216 png_color_16p trans_color_p =
nullptr;
220 int interlace_method = PNG_INTERLACE_LAST;
221 png_get_IHDR(png_ptr, info_ptr, &
width, &
height, &bit_depth, &color_type, &interlace_method,
nullptr,
nullptr);
223 png_set_interlace_handling(png_ptr);
225 if (color_type == PNG_COLOR_TYPE_GRAY) {
227 if (bit_depth == 1 && png_get_channels(png_ptr, info_ptr) == 1) {
228 png_set_invert_mono(png_ptr);
229 png_read_update_info(png_ptr, info_ptr);
232 image.setColorCount(2);
235 if (png_get_tRNS(png_ptr, info_ptr, &trans_alpha, &num_trans, &trans_color_p) && trans_color_p) {
236 const int g = trans_color_p->gray;
244 }
else if (bit_depth == 16
245 && png_get_channels(png_ptr, info_ptr) == 1
246 && !png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
249 png_read_update_info(png_ptr, info_ptr);
251 png_set_swap(png_ptr);
252 }
else if (bit_depth == 16) {
253 bool hasMask = png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS);
255 png_set_filler(png_ptr, 0xffff, PNG_FILLER_AFTER);
257 png_set_expand(png_ptr);
258 png_set_gray_to_rgb(png_ptr);
262 png_read_update_info(png_ptr, info_ptr);
264 png_set_swap(png_ptr);
265 }
else if (bit_depth == 8 && !png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
266 png_set_expand(png_ptr);
269 png_read_update_info(png_ptr, info_ptr);
272 png_set_packing(png_ptr);
273 int ncols = bit_depth < 8 ? 1 << bit_depth : 256;
274 png_read_update_info(png_ptr, info_ptr);
277 image.setColorCount(ncols);
278 for (
int i=0;
i<ncols;
i++) {
279 int c =
i*255/(ncols-1);
282 if (png_get_tRNS(png_ptr, info_ptr, &trans_alpha, &num_trans, &trans_color_p) && trans_color_p) {
283 const int g = trans_color_p->gray;
289 }
else if (color_type == PNG_COLOR_TYPE_PALETTE
290 && png_get_PLTE(png_ptr, info_ptr, &
palette, &num_palette)
291 && num_palette <= 256)
295 png_set_packing(png_ptr);
296 png_read_update_info(png_ptr, info_ptr);
297 png_get_IHDR(png_ptr, info_ptr, &
width, &
height, &bit_depth, &color_type,
nullptr,
nullptr,
nullptr);
302 png_get_PLTE(png_ptr, info_ptr, &
palette, &num_palette);
305 if (png_get_tRNS(png_ptr, info_ptr, &trans_alpha, &num_trans, &trans_color_p) && trans_alpha) {
306 while (
i < num_trans) {
317 while (
i < num_palette) {
329 png_set_bgr(png_ptr);
331 }
else if (bit_depth == 16 && !(color_type & PNG_COLOR_MASK_PALETTE)) {
333 if (!(color_type & PNG_COLOR_MASK_ALPHA) && !png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
334 png_set_filler(png_ptr, 0xffff, PNG_FILLER_AFTER);
337 if (!(color_type & PNG_COLOR_MASK_COLOR))
338 png_set_gray_to_rgb(png_ptr);
341 png_read_update_info(png_ptr, info_ptr);
343 png_set_swap(png_ptr);
347 png_set_strip_16(png_ptr);
349 png_set_expand(png_ptr);
351 if (color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
352 png_set_gray_to_rgb(png_ptr);
356 if (!(color_type & PNG_COLOR_MASK_ALPHA)
357 && !png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
359 PNG_FILLER_BEFORE : PNG_FILLER_AFTER);
365 quint32(scaledSize.
height()) <=
height && scaledSize != outSize && interlace_method == PNG_INTERLACE_NONE) {
367 outSize = scaledSize;
369 *doScaledRead =
true;
375 png_set_swap_alpha(png_ptr);
379 png_set_bgr(png_ptr);
382 png_read_update_info(png_ptr, info_ptr);
391 png_uint_32
width = 0;
393 png_int_32 offset_x = 0;
394 png_int_32 offset_y = 0;
398 int unit_type = PNG_OFFSET_PIXEL;
399 png_get_IHDR(png_ptr, info_ptr, &
width, &
height, &bit_depth, &color_type,
nullptr,
nullptr,
nullptr);
400 png_get_oFFs(png_ptr, info_ptr, &offset_x, &offset_y, &unit_type);
414 amp.
inRow =
new png_byte[ibw];
415 memset(amp.
inRow, 0, ibw*
sizeof(png_byte));
419 for (
quint32 oy=0; oy<oysz; oy++) {
424 for (rval = iysz-rval; rval > 0; rval-=oysz) {
425 png_read_row(png_ptr, amp.
inRow,
nullptr);
439 for (
quint32 ox=0; ox<oxsz; ox++) {
442 for (cval = ixsz - cval; cval > 0; cval-=oxsz) {
458 outImage->
setDotsPerMeterX((png_get_x_pixels_per_meter(png_ptr,info_ptr)*oxsz)/ixsz);
459 outImage->
setDotsPerMeterY((png_get_y_pixels_per_meter(png_ptr,info_ptr)*oysz)/iysz);
461 if (unit_type == PNG_OFFSET_PIXEL)
477#ifndef QT_NO_IMAGEIO_TEXT_LOADING
485#if defined(PNG_iTXt_SUPPORTED)
486 if (text_ptr->itxt_length) {
509 png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
nullptr,
nullptr,
nullptr);
515#if defined(PNG_SET_OPTION_SUPPORTED) && defined(PNG_MAXIMUM_INFLATE_WINDOW)
518 png_set_option(
png_ptr, PNG_MAXIMUM_INFLATE_WINDOW, PNG_OPTION_ON);
523 png_destroy_read_struct(&
png_ptr,
nullptr,
nullptr);
535 if (setjmp(png_jmpbuf(
png_ptr))) {
546#ifdef PNG_iCCP_SUPPORTED
548 png_charp
name =
nullptr;
549 int compressionType = 0;
550#if (PNG_LIBPNG_VER < 10500)
551 png_charp profileData =
nullptr;
553 png_bytep profileData =
nullptr;
559 qCDebug(lcImageIo) <<
"QPngHandler: Failed to parse ICC profile";
569 int rendering_intent = -1;
572 if (rendering_intent >= 0 && rendering_intent <= 3) {
578 double file_gamma = 0.0;
584 double white_x, white_y, red_x, red_y;
585 double green_x, green_y, blue_x, blue_y;
587 &white_x, &white_y, &red_x, &red_y,
588 &green_x, &green_y, &blue_x, &blue_y);
619 if (setjmp(png_jmpbuf(
png_ptr))) {
635 bool doScaledRead =
false;
647 png_uint_32
width = 0;
649 png_int_32 offset_x = 0;
650 png_int_32 offset_y = 0;
654 int unit_type = PNG_OFFSET_PIXEL;
670 if (unit_type == PNG_OFFSET_PIXEL)
675 int color_table_size = outImage->
colorCount();
680 if (*
p >= color_table_size)
713 int bit_depth = 0, color_type = 0;
717 if (color_type == PNG_COLOR_TYPE_GRAY) {
721 }
else if (bit_depth == 16) {
723 }
else if (bit_depth == 8 && !png_get_valid(
png_ptr,
info_ptr, PNG_INFO_tRNS)) {
728 }
else if (color_type == PNG_COLOR_TYPE_PALETTE
730 && num_palette <= 256)
734 }
else if (bit_depth == 16 && !(color_type & PNG_COLOR_MASK_PALETTE)) {
736 if (!(color_type & PNG_COLOR_MASK_ALPHA) && !png_get_valid(
png_ptr,
info_ptr, PNG_INFO_tRNS))
742 if (!(color_type & PNG_COLOR_MASK_ALPHA)
794 png_textp text_ptr =
new png_text[
text.
size()];
795 memset(text_ptr, 0,
text.
size() *
sizeof(png_text));
801 bool noCompress = (
it.value().
size() < 40);
803#ifdef PNG_iTXt_SUPPORTED
804 bool needsItxt =
false;
807 if (
c.row() || (
ch < 0x20 &&
ch !=
'\n') || (
ch > 0x7e &&
ch < 0xa0)) {
814 text_ptr[
i].compression = noCompress ? PNG_ITXT_COMPRESSION_NONE : PNG_ITXT_COMPRESSION_zTXt;
817 text_ptr[
i].itxt_length =
value.size();
818 text_ptr[
i].lang =
const_cast<char*
>(
"UTF-8");
819 text_ptr[
i].lang_key =
qstrdup(
it.key().toUtf8().constData());
824 text_ptr[
i].compression = noCompress ? PNG_TEXT_COMPRESSION_NONE : PNG_TEXT_COMPRESSION_zTXt;
827 text_ptr[
i].text_length =
value.size();
833 png_set_text(png_ptr, info_ptr, text_ptr,
i);
835 delete [] text_ptr[
i].key;
836 delete [] text_ptr[
i].text;
837#ifdef PNG_iTXt_SUPPORTED
838 delete [] text_ptr[
i].lang_key;
850 int off_x_in,
int off_y_in)
853 int off_x = off_x_in +
offset.x();
854 int off_y = off_y_in +
offset.y();
859 png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
nullptr,
nullptr,
nullptr);
865#ifdef PNG_BENIGN_ERRORS_SUPPORTED
866 png_set_benign_errors(png_ptr, 1);
869 info_ptr = png_create_info_struct(png_ptr);
871 png_destroy_write_struct(&png_ptr,
nullptr);
875 if (setjmp(png_jmpbuf(png_ptr))) {
876 png_destroy_write_struct(&png_ptr, &info_ptr);
880 int compression = compression_in;
881 if (compression >= 0) {
882 if (compression > 9) {
883 qCWarning(lcImageIo,
"PNG: Compression %d out of range", compression);
886 png_set_compression_level(png_ptr, compression);
894 if (
image.isGrayscale())
895 color_type = PNG_COLOR_TYPE_GRAY;
897 color_type = PNG_COLOR_TYPE_PALETTE;
901 color_type = PNG_COLOR_TYPE_GRAY;
902 else if (
image.hasAlphaChannel())
903 color_type = PNG_COLOR_TYPE_RGB_ALPHA;
905 color_type = PNG_COLOR_TYPE_RGB;
908 switch (
image.format()) {
924 png_set_IHDR(png_ptr, info_ptr,
image.width(),
image.height(),
926 color_type, 0, 0, 0);
928#ifdef PNG_iCCP_SUPPORTED
929 if (
image.colorSpace().isValid()) {
938 png_set_iCCP(png_ptr, info_ptr,
939 #
if PNG_LIBPNG_VER < 10500
940 iccProfileName.
data(), PNG_COMPRESSION_TYPE_BASE, iccProfile.
data(),
942 iccProfileName.
constData(), PNG_COMPRESSION_TYPE_BASE,
949 png_set_gAMA(png_ptr, info_ptr, 1.0/gamma);
953 png_set_packswap(png_ptr);
955 if (color_type == PNG_COLOR_TYPE_PALETTE) {
957 int num_palette =
qMin(256,
image.colorCount());
961 for (
int i=0;
i<num_palette;
i++) {
967 if (trans[
i] < 255) {
971 png_set_PLTE(png_ptr, info_ptr,
palette, num_palette);
974 png_set_tRNS(png_ptr, info_ptr, trans, num_trans,
nullptr);
981 switch (
image.format()) {
989 png_set_swap_alpha(png_ptr);
995 switch (
image.format()) {
1004 png_set_bgr(png_ptr);
1008 if (off_x || off_y) {
1009 png_set_oFFs(png_ptr, info_ptr, off_x, off_y, PNG_OFFSET_PIXEL);
1012 if (frames_written > 0)
1013 png_set_sig_bytes(png_ptr, 8);
1015 if (
image.dotsPerMeterX() > 0 ||
image.dotsPerMeterY() > 0) {
1016 png_set_pHYs(png_ptr, info_ptr,
1017 image.dotsPerMeterX(),
image.dotsPerMeterY(),
1018 PNG_RESOLUTION_METER);
1023 png_write_info(png_ptr, info_ptr);
1025 if (
image.depth() != 1)
1026 png_set_packing(png_ptr);
1028 if (color_type == PNG_COLOR_TYPE_RGB) {
1029 switch (
image.format()) {
1035 png_set_filler(png_ptr, 0, PNG_FILLER_AFTER);
1038 png_set_filler(png_ptr, 0,
1040 PNG_FILLER_BEFORE : PNG_FILLER_AFTER);
1045 switch (
image.format()) {
1050 png_set_swap(png_ptr);
1057 if (looping >= 0 && frames_written == 0) {
1060 data[0xB] = looping%0x100;
1061 data[0xC] = looping/0x100;
1062 png_write_chunk(png_ptr,
const_cast<png_bytep
>((
const png_byte *)
"gIFx"),
data, 13);
1068 data[2] = (ms_delay/10)/0x100;
1069 data[3] = (ms_delay/10)%0x100;
1070 png_write_chunk(png_ptr,
const_cast<png_bytep
>((
const png_byte *)
"gIFg"),
data, 4);
1075 switch (
image.format()) {
1090 png_bytep* row_pointers =
new png_bytep[
height];
1092 row_pointers[
y] =
const_cast<png_bytep
>(
image.constScanLine(
y));
1093 png_write_image(png_ptr, row_pointers);
1094 delete [] row_pointers;
1100 png_bytep row_pointers[1];
1103 row_pointers[0] =
const_cast<png_bytep
>(
row.constScanLine(0));
1104 png_write_rows(png_ptr, row_pointers, 1);
1112 png_bytep row_pointers[1];
1115 row_pointers[0] =
const_cast<png_bytep
>(
row.constScanLine(0));
1116 png_write_rows(png_ptr, row_pointers, 1);
1122 png_write_end(png_ptr, info_ptr);
1125 png_destroy_write_struct(&png_ptr, &info_ptr);
1131 int compression,
int quality,
float gamma,
const QString &description)
1136 if (compression >= 0)
1137 compression =
qMin(compression, 100);
1138 else if (quality >= 0)
1139 compression = 100 -
qMin(quality, 100);
1141 if (compression >= 0)
1142 compression = (compression * 9) / 91;
1176 qCWarning(lcImageIo,
"QPngHandler::canRead() called with no device");
1180 return device->
peek(8) ==
"\x89\x50\x4E\x47\x0D\x0A\x1A\x0A";
IOBluetoothDevice * device
char * data()
\macro QT_NO_CAST_FROM_BYTEARRAY
qsizetype size() const noexcept
Returns the number of bytes in this byte array.
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
bool isEmpty() const noexcept
Returns true if the byte array has size 0; otherwise returns false.
static const QColorSpacePrivate * get(const QColorSpace &colorSpace)
The QColorSpace class provides a color space abstraction.
bool isValid() const noexcept
Returns true if the color space is valid.
void setTransferFunction(TransferFunction transferFunction, float gamma=0.0f)
Sets the transfer function to transferFunction and gamma.
float gamma() const noexcept
Returns the gamma value of color spaces with TransferFunction::Gamma, an approximate gamma value for ...
static QColorSpace fromIccProfile(const QByteArray &iccProfile)
Creates a QColorSpace from ICC profile iccProfile.
QColorSpace withTransferFunction(TransferFunction transferFunction, float gamma=0.0f) const
Returns a copy of this color space, except using the transfer function transferFunction and gamma.
QString description() const noexcept
Returns the name or short description.
QByteArray iccProfile() const
Returns an ICC profile representing the color space.
\inmodule QtCore \reentrant
qint64 peek(char *data, qint64 maxlen)
ImageOption
This enum describes the different options supported by QImageIOHandler.
static bool allocateImage(QSize size, QImage::Format format, QImage *image)
QIODevice * device() const
Returns the device currently assigned to the QImageIOHandler.
void setFormat(const QByteArray &format)
Sets the format of the QImageIOHandler to format.
void setDotsPerMeterY(int)
Sets the number of pixels that fit vertically in a physical meter, to y.
QImage scaled(int w, int h, Qt::AspectRatioMode aspectMode=Qt::IgnoreAspectRatio, Qt::TransformationMode mode=Qt::FastTransformation) const
This is an overloaded member function, provided for convenience. It differs from the above function o...
void setText(const QString &key, const QString &value)
Sets the image text to the given text and associate it with the given key.
qsizetype bytesPerLine() const
Returns the number of bytes per image scanline.
QSize size() const
Returns the size of the image, i.e.
uchar * bits()
Returns a pointer to the first pixel data.
Format
The following image formats are available in Qt.
@ Format_RGBA64_Premultiplied
Format format() const
Returns the format of the image.
void setDotsPerMeterX(int)
Sets the number of pixels that fit horizontally in a physical meter, to x.
int colorCount() const
Returns the depth of the image.
void setColorSpace(const QColorSpace &)
void setOffset(const QPoint &)
Sets the number of pixels by which the image is intended to be offset by when positioning relative to...
void setLooping(int loops=0)
void setDisposalMethod(DisposalMethod)
bool writeImage(const QImage &img)
void setFrameDelay(int msecs)
QPNGImageWriter(QIODevice *)
bool writeImage(const QImage &img, int compression, const QString &description)
bool writeImage(const QImage &img, int x, int y)
void readPngTexts(png_info *info)
QPngHandlerPrivate(QPngHandler *qq)
ColorSpaceState colorSpaceState
AllocatedMemoryPointers amp
QImage::Format readImageFormat()
bool readPngImage(QImage *image)
void setOption(ImageOption option, const QVariant &value) override
Sets the option option with the value value.
bool write(const QImage &image) override
Writes the image image to the assigned device.
bool supportsOption(ImageOption option) const override
Returns true if the QImageIOHandler supports the option option; otherwise returns false.
QVariant option(ImageOption option) const override
Returns the value assigned to option as a QVariant.
bool read(QImage *image) override
Read an image from the device, and stores it in image.
bool canRead() const override
Returns true if an image can be read from the device (i.e., the image format is supported,...
\inmodule QtCore\reentrant
\inmodule QtCore\reentrant
constexpr int height() const noexcept
Returns the height.
constexpr int width() const noexcept
Returns the width.
constexpr bool isEmpty() const noexcept
Returns true if either of the width and height is less than or equal to 0; otherwise returns false.
constexpr bool isValid() const noexcept
Returns true if both the width and height is equal to or greater than 0; otherwise returns false.
\macro QT_RESTRICTED_CAST_FROM_ASCII
QByteArray toLatin1() const &
const_iterator constEnd() const
Returns a const \l{STL-style iterators}{STL-style iterator} pointing just after the last character in...
static QString fromLatin1(QByteArrayView ba)
This is an overloaded member function, provided for convenience. It differs from the above function o...
qsizetype size() const
Returns the number of characters in this string.
static QString fromUtf8(QByteArrayView utf8)
This is an overloaded member function, provided for convenience. It differs from the above function o...
QString simplified() const &
bool isEmpty() const
Returns true if the string has no characters; otherwise returns false.
const_iterator constBegin() const
Returns a const \l{STL-style iterators}{STL-style iterator} pointing to the first character in the st...
QSet< QString >::iterator it
Combined button and popup list for selecting options.
#define QByteArrayLiteral(str)
Q_CORE_EXPORT char * qstrdup(const char *)
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
bool qFuzzyCompare(qfloat16 p1, qfloat16 p2) noexcept
QMap< QString, QString > qt_getImageText(const QImage &image, const QString &description)
#define qCInfo(category,...)
#define qCWarning(category,...)
#define qCDebug(category,...)
#define Q_DECLARE_LOGGING_CATEGORY(name)
constexpr const T & qMin(const T &a, const T &b)
GLint GLint GLint GLint GLint x
[0]
GLint GLsizei GLsizei height
GLboolean GLboolean GLboolean GLboolean a
[7]
GLenum GLuint GLintptr GLsizeiptr size
[1]
GLenum GLuint GLenum GLsizei length
GLuint GLsizei const GLchar * message
GLint GLsizei GLsizei GLenum GLenum GLsizei void * data
GLenum GLuint GLintptr offset
GLint GLsizei GLsizei GLenum format
GLdouble GLdouble GLdouble GLdouble q
GLenum GLenum GLsizei void * row
static void qpiw_write_fn(png_structp png_ptr, png_bytep data, png_size_t length)
static void set_text(const QImage &image, png_structp png_ptr, png_infop info_ptr, const QString &description)
static bool setup_qt(QImage &image, png_structp png_ptr, png_infop info_ptr, QSize scaledSize, bool *doScaledRead)
static void qpiw_flush_fn(png_structp)
static void qt_png_warning(png_structp, png_const_charp message)
#define FAST_SCAN_LINE(data, bpl, y)
static void read_image_scaled(QImage *outImage, png_structp png_ptr, png_infop info_ptr, QPngHandlerPrivate::AllocatedMemoryPointers &, QSize scaledSize)
static bool write_png_image(const QImage &image, QIODevice *device, int compression, int quality, float gamma, const QString &description)
static void iod_read_fn(png_structp png_ptr, png_bytep data, png_size_t length)
QT_BEGIN_NAMESPACE typedef unsigned int QRgb
constexpr QRgb qRgb(int r, int g, int b)
constexpr int qRed(QRgb rgb)
constexpr int qGreen(QRgb rgb)
constexpr QRgb qRgba(int r, int g, int b, int a)
constexpr int qBlue(QRgb rgb)
constexpr int qAlpha(QRgb rgb)
QVideoFrameFormat::PixelFormat fmt
QFileInfo info(fileName)
[8]
QTextStream out(stdout)
[7]
AllocatedMemoryPointers()