14#define PNG_MAX_UINT PNG_UINT_31_MAX
27#include <QApplication>
29#include <klocalizedstring.h>
63int getColorTypeforColorSpace(
const KoColorSpace * cs ,
bool alpha)
66 QString
id = cs->
id();
68 if (
id ==
"GRAYA" ||
id ==
"GRAYAU16" ||
id ==
"GRAYA16") {
69 return alpha ? PNG_COLOR_TYPE_GRAY_ALPHA : PNG_COLOR_TYPE_GRAY;
71 if (
id ==
"RGBA" ||
id ==
"RGBA16") {
72 return alpha ? PNG_COLOR_TYPE_RGB_ALPHA : PNG_COLOR_TYPE_RGB;
79bool colorSpaceIdSupported(
const QString &
id)
81 return id ==
"RGBA" ||
id ==
"RGBA16" ||
82 id ==
"GRAYA" ||
id ==
"GRAYAU16" ||
id ==
"GRAYA16";
87 QPair<QString, QString> r;
89 if (color_type == PNG_COLOR_TYPE_PALETTE) {
93 if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA) {
95 }
else if (color_type == PNG_COLOR_TYPE_RGB_ALPHA || color_type == PNG_COLOR_TYPE_RGB) {
98 if (color_nb_bits == 16) {
100 }
else if (color_nb_bits <= 8) {
108void fillText(png_text* p_text,
const char* key, QString& text)
110 p_text->compression = PNG_TEXT_COMPRESSION_zTXt;
111 p_text->key =
const_cast<char *
>(key);
112 char* textc =
new char[text.length()+1];
113 strcpy(textc, text.toLatin1());
114 p_text->text = textc;
115 p_text->text_length = text.length() + 1;
118long formatStringList(
char *
string,
const size_t length,
const char *format, va_list operands)
120 int n = vsnprintf(
string,
length, format, operands);
128long formatString(
char *
string,
const size_t length,
const char *format, ...)
134 va_start(operands, format);
135 n = (long) formatStringList(
string,
length, format, operands);
140void writeRawProfile(png_struct *ping, png_info *ping_info, QString profile_type, QByteArray profile_data)
145 png_uint_32 allocated_length, description_length;
147 const uchar hex[16] = {
'0',
'1',
'2',
'3',
'4',
'5',
'6',
'7',
'8',
'9',
'a',
'b',
'c',
'd',
'e',
'f'};
149 dbgFile <<
"Writing Raw profile: type=" << profile_type <<
", length=" << profile_data.length() << Qt::endl;
151 text = (png_textp) png_malloc(ping, (png_uint_32)
sizeof(png_text));
152 description_length = profile_type.length();
153 allocated_length = (png_uint_32)(profile_data.length() * 2 + (profile_data.length() >> 5) + 20 + description_length);
155 text[0].text = (png_charp) png_malloc(ping, allocated_length);
156 memset(text[0].text, 0, allocated_length);
158 QString key = QLatin1String(
"Raw profile type ") + profile_type.toLatin1();
159 QByteArray keyData = key.toLatin1();
160 text[0].key = keyData.data();
162 uchar* sp = (uchar*)profile_data.data();
163 png_charp dp = text[0].text;
166 memcpy(dp, profile_type.toLatin1().constData(), profile_type.length());
168 dp += description_length;
171 formatString(dp, allocated_length - strlen(text[0].text),
"%8lu ", (
unsigned long)profile_data.length());
175 for (
long i = 0; i < (long) profile_data.length(); i++) {
179 *(dp++) = (
char) hex[((*sp >> 4) & 0x0f)];
180 *(dp++) = (
char) hex[((*sp++) & 0x0f)];
185 text[0].text_length = (png_size_t)(dp - text[0].text);
186 text[0].compression = -1;
188 if (text[0].text_length <= allocated_length)
189 png_set_text(ping, ping_info, text, 1);
191 png_free(ping, text[0].text);
192 png_free(ping, text);
195QByteArray png_read_raw_profile(png_textp text)
199 static const unsigned char unhex[103] = {
200 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
201 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
202 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0,
203 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
204 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 11, 12,
208 png_charp sp = text[0].text + 1;
213 while (*sp ==
'\0' || *sp ==
' ' || *sp ==
'\n')
215 png_uint_32
length = (png_uint_32) atol(sp);
216 while (*sp !=
' ' && *sp !=
'\n')
223 unsigned char *dp = (
unsigned char*)profile.data();
224 png_uint_32 nibbles =
length * 2;
225 for (png_uint_32 i = 0; i < nibbles; i++) {
226 while (*sp <
'0' || (*sp >
'9' && *sp <
'a') || *sp >
'f') {
233 *dp = (
unsigned char)(16 * unhex[(
int) *sp++]);
235 (*dp++) += unhex[(int) *sp++];
240void decode_meta_data(png_textp text,
KisMetaData::Store* store, QString type,
int headerSize)
242 dbgFile <<
"Decoding " << type <<
" " << text[0].key;
246 QByteArray rawProfile = png_read_raw_profile(text);
247 if (headerSize > 0) {
248 rawProfile.remove(0, headerSize);
250 if (rawProfile.size() > 0) {
252 buffer.setData(rawProfile);
263 qWarning(
"libpng warning: %s", message);
340 std::size_t rowbytes = png_get_rowbytes(
png_ptr, info_ptr);
359 std::size_t rowbytes = png_get_rowbytes(
png_ptr, info_ptr);
360 for (
int i = 0; i <
height; i++) {
366 for (
int i = 0; i <
height; i++) {
383 QIODevice *in = (QIODevice *)png_get_io_ptr(png_ptr);
386 int nr = in->read((
char*)data,
length);
388 png_error(png_ptr,
"Read Error");
398 QIODevice* out = (QIODevice*)png_get_io_ptr(png_ptr);
402 png_error(png_ptr,
"Write Error");
415 dbgFile <<
"Start decoding PNG File";
417 png_byte signature[8];
418 iod->peek((
char*)signature, 8);
420#if PNG_LIBPNG_VER < 10400
421 if (!png_check_sig(signature, 8)) {
423 if (png_sig_cmp(signature, 0, 8) != 0) {
430 png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
436#ifdef PNG_SET_USER_LIMITS_SUPPORTED
438 png_set_user_limits(png_ptr, 0x7fffffff, 0x7fffffff);
439 png_set_chunk_cache_max(png_ptr, 0);
440 png_set_chunk_malloc_max(png_ptr, 0);
444 #ifdef PNG_BENIGN_ERRORS_SUPPORTED
445 png_set_benign_errors(png_ptr, 1);
448 png_infop info_ptr = png_create_info_struct(png_ptr);
450 png_destroy_read_struct(&png_ptr, (png_infopp)0, (png_infopp)0);
455 png_infop end_info = png_create_info_struct(png_ptr);
457 png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)0);
463 if (setjmp(png_jmpbuf(png_ptr))) {
464 png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
470 png_set_read_fn(png_ptr, iod,
_read_fn);
472#if defined(PNG_SKIP_sRGB_CHECK_PROFILE) && defined(PNG_SET_OPTION_SUPPORTED)
473 png_set_option(png_ptr, PNG_SKIP_sRGB_CHECK_PROFILE, PNG_OPTION_ON);
477 png_read_info(png_ptr, info_ptr);
480 if (png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_GRAY && png_get_bit_depth(png_ptr, info_ptr) < 8) {
481 png_set_expand(png_ptr);
484 if (png_get_color_type(png_ptr, info_ptr) == PNG_COLOR_TYPE_PALETTE && png_get_bit_depth(png_ptr, info_ptr) < 8) {
485 png_set_packing(png_ptr);
489 if (png_get_color_type(png_ptr, info_ptr) != PNG_COLOR_TYPE_PALETTE &&
490 (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))) {
491 png_set_expand(png_ptr);
493 png_read_update_info(png_ptr, info_ptr);
496 png_uint_32 width, height;
497 int color_nb_bits, color_type, interlace_type;
498 png_get_IHDR(png_ptr, info_ptr, &width, &height, &color_nb_bits, &color_type, &interlace_type, 0, 0);
499 dbgFile <<
"width = " << width <<
" height = " << height <<
" color_nb_bits = " << color_nb_bits <<
" color_type = " << color_type <<
" interlace_type = " << interlace_type << Qt::endl;
501#ifndef WORDS_BIGENDIAN
502 if (color_nb_bits > 8)
503 png_set_swap(png_ptr);
508 if (csName.first.isEmpty()) {
509 png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
513 bool hasalpha = (color_type == PNG_COLOR_TYPE_RGB_ALPHA || color_type == PNG_COLOR_TYPE_GRAY_ALPHA);
516 png_charp profile_name;
517#if PNG_LIBPNG_VER_MAJOR >= 1 && PNG_LIBPNG_VER_MINOR >= 5
518 png_bytep profile_data;
520 png_charp profile_data;
522 int compression_type;
528#if defined(PNG_cHRM_SUPPORTED)
529 double whitePointX, whitePointY;
531 double greenX, greenY;
533 png_get_cHRM(png_ptr,info_ptr, &whitePointX, &whitePointY, &redX, &redY, &greenX, &greenY, &blueX, &blueY);
534 dbgFile <<
"cHRM:" << whitePointX << whitePointY << redX << redY << greenX << greenY << blueX << blueY;
538#if defined(PNG_GAMMA_SUPPORTED)
540 png_get_gAMA(png_ptr, info_ptr, &gamma);
545#if defined(PNG_sRGB_SUPPORTED)
547 png_get_sRGB(png_ptr, info_ptr, &sRGBIntent);
548 dbgFile <<
"sRGB" << sRGBIntent;
551 bool fromBlender =
false;
555 png_get_text(png_ptr, info_ptr, &text_ptr, &num_comments);
557 for (
int i = 0; i < num_comments; i++) {
558 QString key = QString(text_ptr[i].key).toLower();
560 QString relatedFile = text_ptr[i].text;
561 if (relatedFile.contains(
".blend", Qt::CaseInsensitive)){
567 bool loadedImageIsHDR =
false;
570 if (png_get_iCCP(png_ptr, info_ptr, &profile_name, &compression_type, &profile_data, &proflen)) {
571 QByteArray profile_rawdata(
reinterpret_cast<char*
>(profile_data), proflen);
575 dbgFile <<
"the profile is not suitable for output and therefore cannot be used in krita, we need to convert the image to a standard profile";
579 loadedImageIsHDR = strcmp(profile_name,
"ITUR_2100_PQ_FULL") == 0;
581 else if (color_nb_bits == 16 && !fromBlender && !qAppName().toLower().contains(
"test") && !
m_batchMode) {
590 if (!dlg.
profile().isEmpty()) {
596 dbgFile <<
"no embedded profile, will use the default sRGB profile";
599 const QString colorSpaceId =
606 warnFile <<
"The profile " << profile->
name() <<
" is not compatible with the color space model " << csName.first <<
" " << csName.second;
614 if (loadedImageIsHDR &&
627 dbgFile <<
"image has embedded profile: " << profile->
name() <<
"\n";
641 png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
653 png_uint_32 x_resolution = 0, y_resolution = 0;
655 png_get_pHYs(png_ptr, info_ptr, &x_resolution, &y_resolution, &unit_type);
656 if (x_resolution > 0 && y_resolution > 0 && unit_type == PNG_RESOLUTION_METER) {
658 }
else if (unit_type == PNG_RESOLUTION_UNKNOWN) {
662 double coeff =
quint8_MAX / (double)(pow((
double)2, color_nb_bits) - 1);
666 png_get_text(png_ptr, info_ptr, &text_ptr, &num_comments);
669 dbgFile <<
"There are " << num_comments <<
" comments in the text";
670 for (
int i = 0; i < num_comments; i++) {
671 QString key = QString(text_ptr[i].key).toLower();
672 dbgFile <<
"key: " << text_ptr[i].key
673 <<
", containing: " << text_ptr[i].text
674 <<
": " << (key ==
"raw profile type exif " ?
"isExif" :
"something else");
675 if (key ==
"title") {
677 }
else if (key ==
"description") {
679 }
else if (key ==
"author") {
681 }
else if (key.contains(
"raw profile type exif")) {
682 decode_meta_data(text_ptr + i, layer->
metaData(),
"exif", 6);
683 }
else if (key.contains(
"raw profile type iptc")) {
684 decode_meta_data(text_ptr + i, layer->
metaData(),
"iptc", 14);
685 }
else if (key.contains(
"raw profile type xmp")) {
686 decode_meta_data(text_ptr + i, layer->
metaData(),
"xmp", 0);
687 }
else if (key ==
"version") {
689 }
else if (key ==
"preset") {
695 QScopedPointer<KisPNGReaderAbstract> reader;
697 if (interlace_type == PNG_INTERLACE_ADAM7) {
702 }
catch (
const std::bad_alloc& e) {
705 dbgFile <<
"bad alloc: " << e.what();
707 png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
714 if (color_type == PNG_COLOR_TYPE_PALETTE) {
715 png_get_PLTE(png_ptr, info_ptr, &
palette, &num_palette);
719 quint8 palette_alpha[256];
720 memset(palette_alpha, 255, 256);
721 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
722 if (color_type == PNG_COLOR_TYPE_PALETTE) {
725 png_get_tRNS(png_ptr, info_ptr, &alpha_ptr, &num_alpha, 0);
726 for (
int i = 0; i < num_alpha; ++i) {
727 palette_alpha[i] = alpha_ptr[i];
732 for (png_uint_32 y = 0; y < height; y++) {
735 png_bytep row_pointer = reader->readLine();
737 switch (color_type) {
738 case PNG_COLOR_TYPE_GRAY:
739 case PNG_COLOR_TYPE_GRAY_ALPHA:
740 if (color_nb_bits == 16) {
741 quint16 *src =
reinterpret_cast<quint16 *
>(row_pointer);
743 quint16 *d =
reinterpret_cast<quint16 *
>(it->rawData());
750 if (transform) transform->
transformInPlace(
reinterpret_cast<quint8*
>(d),
reinterpret_cast<quint8*
>(d), 1);
751 }
while (it->nextPixel());
755 quint8 *d = it->rawData();
756 d[0] = (quint8)(stream.
nextValue() * coeff);
758 d[1] = (quint8)(stream.
nextValue() * coeff);
763 }
while (it->nextPixel());
767 case PNG_COLOR_TYPE_RGB:
768 case PNG_COLOR_TYPE_RGB_ALPHA:
769 if (color_nb_bits == 16) {
770 quint16 *src =
reinterpret_cast<quint16 *
>(row_pointer);
772 quint16 *d =
reinterpret_cast<quint16 *
>(it->rawData());
776 if (hasalpha) d[3] = *(src++);
778 if (transform) transform->
transformInPlace(
reinterpret_cast<quint8 *
>(d),
reinterpret_cast<quint8*
>(d), 1);
779 }
while (it->nextPixel());
783 quint8 *d = it->rawData();
784 d[2] = (quint8)(stream.
nextValue() * coeff);
785 d[1] = (quint8)(stream.
nextValue() * coeff);
786 d[0] = (quint8)(stream.
nextValue() * coeff);
787 if (hasalpha) d[3] = (quint8)(stream.
nextValue() * coeff);
788 else d[3] = UCHAR_MAX;
790 }
while (it->nextPixel());
793 case PNG_COLOR_TYPE_PALETTE: {
796 quint8 *d = it->rawData();
798 quint8 alpha = palette_alpha[ index ];
802 png_color c =
palette[ index ];
808 }
while (it->nextPixel());
817 png_read_end(png_ptr, end_info);
821 png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
832 if (!fp.open(QIODevice::ReadOnly)) {
833 dbgFile <<
"Failed to open PNG File";
851 if (store->
open(filename)) {
853 if (!io.
open(QIODevice::WriteOnly)) {
854 dbgFile <<
"Could not open for writing:" << filename;
867 options.
alpha =
true;
877 if (!success.
isOk()) {
878 dbgFile <<
"Saving PNG failed:" << filename;
879 delete metaDataStore;
882 delete metaDataStore;
884 if (!store->
close()) {
888 dbgFile <<
"Opening of data file failed :" << filename;
898 dbgFile <<
"Start writing PNG File " << filename;
901 if (!fp.open(QIODevice::WriteOnly)) {
902 dbgFile <<
"Failed to open PNG File for writing";
915 if (!options.
alpha) {
918 tmp->fill(imageRect, c);
920 gc.
bitBlt(imageRect.topLeft(), device, imageRect);
933 bool needColorTransform =
false;
939 needColorTransform =
true;
952 needColorTransform =
true;
959 if (needColorTransform) {
975 png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
980#ifdef PNG_SET_USER_LIMITS_SUPPORTED
982 png_set_user_limits(png_ptr, 0x7fffffff, 0x7fffffff);
983 png_set_chunk_cache_max(png_ptr, 0);
984 png_set_chunk_malloc_max(png_ptr, 0);
988 #ifdef PNG_BENIGN_ERRORS_SUPPORTED
989 png_set_benign_errors(png_ptr, 1);
992#if defined(PNG_SKIP_sRGB_CHECK_PROFILE) && defined(PNG_SET_OPTION_SUPPORTED)
993 png_set_option(png_ptr, PNG_SKIP_sRGB_CHECK_PROFILE, PNG_OPTION_ON);
997#ifdef PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED
998 png_set_check_for_invalid_index(png_ptr, 0);
1001 png_infop info_ptr = png_create_info_struct(png_ptr);
1003 png_destroy_write_struct(&png_ptr, (png_infopp)0);
1008 if (setjmp(png_jmpbuf(png_ptr))) {
1009 png_destroy_write_struct(&png_ptr, &info_ptr);
1019 png_set_compression_level(png_ptr, options.
compression);
1024 png_set_compression_mem_level(png_ptr, 8);
1025 png_set_compression_strategy(png_ptr, Z_DEFAULT_STRATEGY);
1026 png_set_compression_window_bits(png_ptr, 15);
1027 png_set_compression_method(png_ptr, 8);
1028 png_set_compression_buffer_size(png_ptr, 8192);
1031 int color_type = getColorTypeforColorSpace(device->
colorSpace(), options.
alpha);
1033 Q_ASSERT(color_type > -1);
1036 QScopedArrayPointer<png_color>
palette;
1037 int num_palette = 0;
1039 palette.reset(
new png_color[255]);
1043 bool toomuchcolor =
false;
1046 bool findit =
false;
1047 for (
int i = 0; i < num_palette; i++) {
1056 if (num_palette == 255) {
1057 toomuchcolor =
true;
1060 palette[num_palette].red = c[2];
1061 palette[num_palette].green = c[1];
1062 palette[num_palette].blue = c[0];
1067 if (!toomuchcolor) {
1068 dbgFile <<
"Found a palette of " << num_palette <<
" colors";
1069 color_type = PNG_COLOR_TYPE_PALETTE;
1070 if (num_palette <= 2) {
1072 }
else if (num_palette <= 4) {
1074 }
else if (num_palette <= 16) {
1084 int interlace_type = options.
interlace ? PNG_INTERLACE_ADAM7 : PNG_INTERLACE_NONE;
1088 png_set_IHDR(png_ptr, info_ptr,
1092 color_type, interlace_type,
1093 PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
1120#if defined(PNG_GAMMA_SUPPORTED)
1124 png_set_gAMA_fixed(png_ptr, info_ptr, 15000);
1125 dbgFile <<
"gAMA" <<
"(Rec 2100)";
1128#if defined PNG_cHRM_SUPPORTED
1129 png_set_cHRM_fixed(png_ptr, info_ptr,
1135 dbgFile <<
"cHRM" <<
"(Rec 2100)";
1145 if (color_type == PNG_COLOR_TYPE_PALETTE) {
1146 png_set_PLTE(png_ptr, info_ptr,
palette.data(), num_palette);
1150 while (it != annotationsEnd) {
1151 if (!(*it) || (*it)->type().isEmpty()) {
1152 dbgFile <<
"Warning: empty annotation";
1157 dbgFile <<
"Trying to store annotation of type " << (*it) -> type() <<
" of size " << (*it) -> annotation() . size();
1159 if ((*it) -> type().startsWith(QString(
"krita_attribute:"))) {
1162 dbgFile <<
"cannot save this annotation : " << (*it) -> type();
1163 }
else if ((*it)->type() ==
"kpp_version" || (*it)->type() ==
"kpp_preset" ) {
1164 dbgFile <<
"Saving preset information " << (*it)->description();
1165 png_textp text = (png_textp) png_malloc(png_ptr, (png_uint_32)
sizeof(png_text));
1167 QByteArray keyData = (*it)->description().toLatin1();
1168 text[0].key = keyData.data();
1169 text[0].text = (
char*)(*it)->annotation().data();
1170 text[0].text_length = (*it)->annotation().size();
1171 text[0].compression = -1;
1173 png_set_text(png_ptr, info_ptr, text, 1);
1174 png_free(png_ptr, text);
1181 QByteArray colorProfileData = colorProfile->
rawData();
1184#if PNG_LIBPNG_VER_MAJOR >= 1 && PNG_LIBPNG_VER_MINOR >= 5
1185 const char *typeString = !options.
saveAsHDR ?
"icc" :
"ITUR_2100_PQ_FULL";
1186 png_set_iCCP(png_ptr, info_ptr, (png_const_charp)typeString, PNG_COMPRESSION_TYPE_BASE, (png_const_bytep)colorProfileData.constData(), colorProfileData . size());
1189 char typeStringICC[] =
"icc";
1190 char typeStringHDR[] =
"ITUR_2100_PQ_FULL";
1191 char *typeString = !options.
saveAsHDR ? typeStringICC : typeStringHDR;
1192 png_set_iCCP(png_ptr, info_ptr, typeString, PNG_COMPRESSION_TYPE_BASE, colorProfileData.data(), colorProfileData . size());
1202 QString title = info->
aboutInfo(
"title");
1204 fillText(texts + nbtexts,
"Title", title);
1207 QString abstract = info->
aboutInfo(
"subject");
1208 if (abstract.isEmpty()) {
1212 QString keywords = info->
aboutInfo(
"keyword");
1213 if (!keywords.isEmpty()) {
1214 abstract = abstract +
" keywords: " + keywords;
1216 fillText(texts + nbtexts,
"Description", abstract);
1220 QString license = info->
aboutInfo(
"license");
1222 fillText(texts + nbtexts,
"Copyright", license);
1226 QString author = info->
authorInfo(
"creator");
1230 if (!contact.isEmpty()) {
1231 author = author+
"("+contact+
")";
1234 fillText(texts + nbtexts,
"Author", author);
1238 png_set_text(png_ptr, info_ptr, texts, nbtexts);
1244 if (metaData && !metaData->
empty()) {
1246 dbgFile <<
"Trying to save exif information";
1253 writeRawProfile(png_ptr, info_ptr,
"exif", buffer.data());
1257 dbgFile <<
"Trying to save iptc information";
1264 dbgFile <<
"IPTC information size is" << buffer.data().size();
1265 writeRawProfile(png_ptr, info_ptr,
"iptc", buffer.data());
1269 dbgFile <<
"Trying to save XMP information";
1276 dbgFile <<
"XMP information size is" << buffer.data().size();
1277 writeRawProfile(png_ptr, info_ptr,
"xmp", buffer.data());
1283 png_uint_32 x_resolution, y_resolution;
1285 png_set_pHYs(png_ptr, info_ptr,
CM_TO_POINT(xRes) * 100.0,
CM_TO_POINT(yRes) * 100.0, PNG_RESOLUTION_METER);
1288 png_write_info(png_ptr, info_ptr);
1289 png_write_flush(png_ptr);
1292#ifndef WORDS_BIGENDIAN
1293 if (color_nb_bits > 8)
1294 png_set_swap(png_ptr);
1300 struct RowPointersStruct {
1301 RowPointersStruct(
const QSize &size,
int pixelSize)
1302 : numRows(size.height())
1304 rows =
new png_byte*[numRows];
1306 for (
int i = 0; i < numRows; i++) {
1307 rows[i] =
new png_byte[size.width() * pixelSize];
1311 ~RowPointersStruct() {
1312 for (
int i = 0; i < numRows; i++) {
1318 const int numRows = 0;
1319 png_byte** rows = 0;
1324 RowPointersStruct rowPointers(imageRect.size(), device->
pixelSize());
1327 for (
int y = imageRect.y(); y < imageRect.y() + imageRect.height(); y++, row++) {
1330 switch (color_type) {
1331 case PNG_COLOR_TYPE_GRAY:
1332 case PNG_COLOR_TYPE_GRAY_ALPHA:
1333 if (color_nb_bits == 16) {
1334 quint16 *dst =
reinterpret_cast<quint16 *
>(rowPointers.rows[row]);
1336 const quint16 *d =
reinterpret_cast<const quint16 *
>(it->
oldRawData());
1338 if (options.
alpha) *(dst++) = d[1];
1341 quint8 *dst = rowPointers.rows[row];
1345 if (options.
alpha) *(dst++) = d[1];
1349 case PNG_COLOR_TYPE_RGB:
1350 case PNG_COLOR_TYPE_RGB_ALPHA:
1351 if (color_nb_bits == 16) {
1352 quint16 *dst =
reinterpret_cast<quint16 *
>(rowPointers.rows[row]);
1354 const quint16 *d =
reinterpret_cast<const quint16 *
>(it->
oldRawData());
1358 if (options.
alpha) *(dst++) = d[3];
1361 quint8 *dst = rowPointers.rows[row];
1367 if (options.
alpha) *(dst++) = d[3];
1371 case PNG_COLOR_TYPE_PALETTE: {
1372 quint8 *dst = rowPointers.rows[row];
1377 for (i = 0; i < num_palette; i++) {
1393 png_write_image(png_ptr, rowPointers.rows);
1396 png_write_end(png_ptr, info_ptr);
1399 png_destroy_write_struct(&png_ptr, &info_ptr);
1411 if (png_ptr == 0 || row_number >
PNG_MAX_UINT || pass > 7)
return;
1417 return colorSpaceIdSupported(cs->
id());
qreal length(const QPointF &vec)
QList< QString > QStringList
const KoID Float32BitsColorDepthID("F32", ki18n("32-bit float/channel"))
const KoID Float64BitsColorDepthID("F64", ki18n("64-bit float/channel"))
const KoID GrayAColorModelID("GRAYA", ki18n("Grayscale/Alpha"))
const KoID Float16BitsColorDepthID("F16", ki18n("16-bit float/channel"))
const KoID Integer8BitsColorDepthID("U8", ki18n("8-bit integer/channel"))
const KoID Integer16BitsColorDepthID("U16", ki18n("16-bit integer/channel"))
const KoID RGBAColorModelID("RGBA", ki18n("RGB/Alpha"))
constexpr qreal POINT_TO_CM(qreal px)
constexpr qreal CM_TO_POINT(qreal cm)
A data extension mechanism for Krita.
virtual const quint8 * oldRawData() const =0
virtual bool nextPixel()=0
qint32 pasteBehaviour(bool defaultValue=false) const
The KisCursorOverrideHijacker class stores all override cursors in a stack, and resets them back afte...
KisUndoStore * createUndoStore()
KoDocumentInfo * documentInfo() const
void addAnnotation(KisAnnotationSP annotation)
KisGroupLayerSP rootLayer() const
void setResolution(double xres, double yres)
~KisPNGConverter() override
void progress(png_structp png_ptr, png_uint_32 row_number, int pass)
static bool isColorSpaceSupported(const KoColorSpace *cs)
static bool saveDeviceToStore(const QString &filename, const QRect &imageRect, const qreal xRes, const qreal yRes, KisPaintDeviceSP dev, KoStore *store, KisMetaData::Store *metaData=0)
saveDeviceToStore saves the given paint device to the KoStore. If the device is not 8 bits sRGB,...
KisPNGConverter(KisDocument *doc, bool batchMode=false)
KisImportExportErrorCode buildImage(const QString &filename)
KisImportExportErrorCode buildFile(const QString &filename, const QRect &imageRect, const qreal xRes, const qreal yRes, KisPaintDeviceSP device, vKisAnnotationSP_it annotationsStart, vKisAnnotationSP_it annotationsEnd, KisPNGOptions options, KisMetaData::Store *metaData)
KisPNGReadStream(quint8 *buf, quint32 depth)
KisPNGReaderAbstract(png_structp _png_ptr, int _width, int _height)
virtual png_bytep readLine()=0
virtual ~KisPNGReaderAbstract()
~KisPNGReaderFullImage() override
png_bytep readLine() override
KisPNGReaderFullImage(png_structp _png_ptr, png_infop info_ptr, int _width, int _height)
KisPNGReaderLineByLine(png_structp _png_ptr, png_infop info_ptr, int _width, int _height)
~KisPNGReaderLineByLine() override
png_bytep readLine() override
KisPNGWriteStream(quint8 *buf, quint32 depth)
quint32 pixelSize() const
quint32 channelCount() const
const KoColorSpace * colorSpace() const
void convertTo(const KoColorSpace *dstColorSpace, KoColorConversionTransformation::Intent renderingIntent=KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::ConversionFlags conversionFlags=KoColorConversionTransformation::internalConversionFlags(), KUndo2Command *parentCommand=nullptr, KoUpdater *progressUpdater=nullptr)
KisHLineConstIteratorSP createHLineConstIteratorNG(qint32 x, qint32 y, qint32 w) const
void bitBlt(qint32 dstX, qint32 dstY, const KisPaintDeviceSP srcDev, qint32 srcX, qint32 srcY, qint32 srcWidth, qint32 srcHeight)
ALWAYS_INLINE const quint8 * oldRawData() const
virtual KoID colorModelId() const =0
virtual KoID colorDepthId() const =0
virtual const KoColorProfile * profile() const =0
virtual KoColorConversionTransformation * createColorConverter(const KoColorSpace *dstColorSpace, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags) const
The class containing all meta information about a document.
void setAboutInfo(const QString &info, const QString &data)
QStringList authorContactInfo() const
authorContactInfo
QString authorInfo(const QString &info) const
void setAuthorInfo(const QString &info, const QString &data)
QString aboutInfo(const QString &info) const
const T value(const QString &id) const
bool open(OpenMode m) override
bool open(const QString &name)
#define KIS_SAFE_ASSERT_RECOVER(cond)
#define KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(cond, val)
const quint16 quint16_MAX
static void _flush_fn(png_structp png_ptr)
static void _read_fn(png_structp png_ptr, png_bytep data, png_size_t length)
static void kis_png_warning(png_structp, png_const_charp message)
static void _write_fn(png_structp png_ptr, png_bytep data, png_size_t length)
QString getColorSpaceForColorType(uint16_t sampletype, uint16_t color_type, uint16_t color_nb_bits, TIFF *image, uint16_t &nbchannels, uint16_t &extrasamplescount, uint8_t &destDepth)
vKisAnnotationSP::iterator vKisAnnotationSP_it
@ FormatFeaturesUnsupported
@ FormatColorSpaceUnsupported
rgba palette[MAX_PALETTE]
KisMetaData::Store * metaData()
bool addNode(KisNodeSP node, KisNodeSP parent=KisNodeSP(), KisNodeAdditionFlags flags=KisNodeAdditionFlag::None)
QColor transparencyFillColor
virtual bool isSuitableForOutput() const =0
virtual bool isSuitableForWorkspace() const =0
virtual QByteArray rawData() const
virtual bool isSuitableForInput() const =0
const KoColorProfile * profileByName(const QString &name) const
QString colorSpaceId(const QString &colorModelId, const QString &colorDepthId) const
const KoColorSpace * colorSpace(const QString &colorModelId, const QString &colorDepthId, const KoColorProfile *profile)
static KoColorSpaceRegistry * instance()
const KoColorProfile * p709SRGBProfile() const
const KoColorProfile * p2020PQProfile() const
const KoColorProfile * createColorProfile(const QString &colorModelId, const QString &colorDepthId, const QByteArray &rawData)