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;
569 if (png_get_iCCP(png_ptr, info_ptr, &profile_name, &compression_type, &profile_data, &proflen)) {
570 QByteArray profile_rawdata;
572 profile_rawdata.resize(proflen);
573 memcpy(profile_rawdata.data(), profile_data, proflen);
575 Q_CHECK_PTR(profile);
579 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";
583 loadedImageIsHDR = strcmp(profile_name,
"ITUR_2100_PQ_FULL") == 0;
586 dbgFile <<
"no embedded profile, will use the default profile";
587 if (color_nb_bits == 16 && !fromBlender && !qAppName().toLower().contains(
"test") && !
m_batchMode) {
595 if (!dlg.
profile().isEmpty()) {
600 dbgFile <<
"no embedded profile, will use the default profile";
603 const QString colorSpaceId =
608 warnFile <<
"The profile " << profile->
name() <<
" is not compatible with the color space model " << csName.first <<
" " << csName.second;
616 if (loadedImageIsHDR &&
629 dbgFile <<
"image has embedded profile: " << profile->
name() <<
"\n";
649 png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
661 png_uint_32 x_resolution, y_resolution;
663 png_get_pHYs(png_ptr, info_ptr, &x_resolution, &y_resolution, &unit_type);
664 if (x_resolution > 0 && y_resolution > 0 && unit_type == PNG_RESOLUTION_METER) {
668 double coeff =
quint8_MAX / (double)(pow((
double)2, color_nb_bits) - 1);
672 png_get_text(png_ptr, info_ptr, &text_ptr, &num_comments);
675 dbgFile <<
"There are " << num_comments <<
" comments in the text";
676 for (
int i = 0; i < num_comments; i++) {
677 QString key = QString(text_ptr[i].key).toLower();
678 dbgFile <<
"key: " << text_ptr[i].key
679 <<
", containing: " << text_ptr[i].text
680 <<
": " << (key ==
"raw profile type exif " ?
"isExif" :
"something else");
681 if (key ==
"title") {
683 }
else if (key ==
"description") {
685 }
else if (key ==
"author") {
687 }
else if (key.contains(
"raw profile type exif")) {
688 decode_meta_data(text_ptr + i, layer->
metaData(),
"exif", 6);
689 }
else if (key.contains(
"raw profile type iptc")) {
690 decode_meta_data(text_ptr + i, layer->
metaData(),
"iptc", 14);
691 }
else if (key.contains(
"raw profile type xmp")) {
692 decode_meta_data(text_ptr + i, layer->
metaData(),
"xmp", 0);
693 }
else if (key ==
"version") {
695 }
else if (key ==
"preset") {
701 QScopedPointer<KisPNGReaderAbstract> reader;
703 if (interlace_type == PNG_INTERLACE_ADAM7) {
708 }
catch (
const std::bad_alloc& e) {
711 dbgFile <<
"bad alloc: " << e.what();
713 png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
720 if (color_type == PNG_COLOR_TYPE_PALETTE) {
721 png_get_PLTE(png_ptr, info_ptr, &
palette, &num_palette);
725 quint8 palette_alpha[256];
726 memset(palette_alpha, 255, 256);
727 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
728 if (color_type == PNG_COLOR_TYPE_PALETTE) {
731 png_get_tRNS(png_ptr, info_ptr, &alpha_ptr, &num_alpha, 0);
732 for (
int i = 0; i < num_alpha; ++i) {
733 palette_alpha[i] = alpha_ptr[i];
738 for (png_uint_32 y = 0; y < height; y++) {
741 png_bytep row_pointer = reader->readLine();
743 switch (color_type) {
744 case PNG_COLOR_TYPE_GRAY:
745 case PNG_COLOR_TYPE_GRAY_ALPHA:
746 if (color_nb_bits == 16) {
747 quint16 *src =
reinterpret_cast<quint16 *
>(row_pointer);
749 quint16 *d =
reinterpret_cast<quint16 *
>(it->rawData());
756 if (transform) transform->
transformInPlace(
reinterpret_cast<quint8*
>(d),
reinterpret_cast<quint8*
>(d), 1);
757 }
while (it->nextPixel());
761 quint8 *d = it->rawData();
762 d[0] = (quint8)(stream.
nextValue() * coeff);
764 d[1] = (quint8)(stream.
nextValue() * coeff);
769 }
while (it->nextPixel());
773 case PNG_COLOR_TYPE_RGB:
774 case PNG_COLOR_TYPE_RGB_ALPHA:
775 if (color_nb_bits == 16) {
776 quint16 *src =
reinterpret_cast<quint16 *
>(row_pointer);
778 quint16 *d =
reinterpret_cast<quint16 *
>(it->rawData());
782 if (hasalpha) d[3] = *(src++);
784 if (transform) transform->
transformInPlace(
reinterpret_cast<quint8 *
>(d),
reinterpret_cast<quint8*
>(d), 1);
785 }
while (it->nextPixel());
789 quint8 *d = it->rawData();
790 d[2] = (quint8)(stream.
nextValue() * coeff);
791 d[1] = (quint8)(stream.
nextValue() * coeff);
792 d[0] = (quint8)(stream.
nextValue() * coeff);
793 if (hasalpha) d[3] = (quint8)(stream.
nextValue() * coeff);
794 else d[3] = UCHAR_MAX;
796 }
while (it->nextPixel());
799 case PNG_COLOR_TYPE_PALETTE: {
802 quint8 *d = it->rawData();
804 quint8 alpha = palette_alpha[ index ];
808 png_color c =
palette[ index ];
814 }
while (it->nextPixel());
823 png_read_end(png_ptr, end_info);
827 png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
838 if (!fp.open(QIODevice::ReadOnly)) {
839 dbgFile <<
"Failed to open PNG File";
857 if (store->
open(filename)) {
859 if (!io.
open(QIODevice::WriteOnly)) {
860 dbgFile <<
"Could not open for writing:" << filename;
873 options.
alpha =
true;
883 if (!success.
isOk()) {
884 dbgFile <<
"Saving PNG failed:" << filename;
885 delete metaDataStore;
888 delete metaDataStore;
890 if (!store->
close()) {
894 dbgFile <<
"Opening of data file failed :" << filename;
904 dbgFile <<
"Start writing PNG File " << filename;
907 if (!fp.open(QIODevice::WriteOnly)) {
908 dbgFile <<
"Failed to open PNG File for writing";
921 if (!options.
alpha) {
924 tmp->fill(imageRect, c);
926 gc.
bitBlt(imageRect.topLeft(), device, imageRect);
939 bool needColorTransform =
false;
945 needColorTransform =
true;
958 needColorTransform =
true;
965 if (needColorTransform) {
981 png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
986#ifdef PNG_SET_USER_LIMITS_SUPPORTED
988 png_set_user_limits(png_ptr, 0x7fffffff, 0x7fffffff);
989 png_set_chunk_cache_max(png_ptr, 0);
990 png_set_chunk_malloc_max(png_ptr, 0);
994 #ifdef PNG_BENIGN_ERRORS_SUPPORTED
995 png_set_benign_errors(png_ptr, 1);
998#if defined(PNG_SKIP_sRGB_CHECK_PROFILE) && defined(PNG_SET_OPTION_SUPPORTED)
999 png_set_option(png_ptr, PNG_SKIP_sRGB_CHECK_PROFILE, PNG_OPTION_ON);
1003#ifdef PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED
1004 png_set_check_for_invalid_index(png_ptr, 0);
1007 png_infop info_ptr = png_create_info_struct(png_ptr);
1009 png_destroy_write_struct(&png_ptr, (png_infopp)0);
1014 if (setjmp(png_jmpbuf(png_ptr))) {
1015 png_destroy_write_struct(&png_ptr, &info_ptr);
1025 png_set_compression_level(png_ptr, options.
compression);
1030 png_set_compression_mem_level(png_ptr, 8);
1031 png_set_compression_strategy(png_ptr, Z_DEFAULT_STRATEGY);
1032 png_set_compression_window_bits(png_ptr, 15);
1033 png_set_compression_method(png_ptr, 8);
1034 png_set_compression_buffer_size(png_ptr, 8192);
1037 int color_type = getColorTypeforColorSpace(device->
colorSpace(), options.
alpha);
1039 Q_ASSERT(color_type > -1);
1042 QScopedArrayPointer<png_color>
palette;
1043 int num_palette = 0;
1045 palette.reset(
new png_color[255]);
1049 bool toomuchcolor =
false;
1052 bool findit =
false;
1053 for (
int i = 0; i < num_palette; i++) {
1062 if (num_palette == 255) {
1063 toomuchcolor =
true;
1066 palette[num_palette].red = c[2];
1067 palette[num_palette].green = c[1];
1068 palette[num_palette].blue = c[0];
1073 if (!toomuchcolor) {
1074 dbgFile <<
"Found a palette of " << num_palette <<
" colors";
1075 color_type = PNG_COLOR_TYPE_PALETTE;
1076 if (num_palette <= 2) {
1078 }
else if (num_palette <= 4) {
1080 }
else if (num_palette <= 16) {
1090 int interlace_type = options.
interlace ? PNG_INTERLACE_ADAM7 : PNG_INTERLACE_NONE;
1094 png_set_IHDR(png_ptr, info_ptr,
1098 color_type, interlace_type,
1099 PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
1126#if defined(PNG_GAMMA_SUPPORTED)
1130 png_set_gAMA_fixed(png_ptr, info_ptr, 15000);
1131 dbgFile <<
"gAMA" <<
"(Rec 2100)";
1134#if defined PNG_cHRM_SUPPORTED
1135 png_set_cHRM_fixed(png_ptr, info_ptr,
1141 dbgFile <<
"cHRM" <<
"(Rec 2100)";
1151 if (color_type == PNG_COLOR_TYPE_PALETTE) {
1152 png_set_PLTE(png_ptr, info_ptr,
palette.data(), num_palette);
1156 while (it != annotationsEnd) {
1157 if (!(*it) || (*it)->type().isEmpty()) {
1158 dbgFile <<
"Warning: empty annotation";
1163 dbgFile <<
"Trying to store annotation of type " << (*it) -> type() <<
" of size " << (*it) -> annotation() . size();
1165 if ((*it) -> type().startsWith(QString(
"krita_attribute:"))) {
1168 dbgFile <<
"cannot save this annotation : " << (*it) -> type();
1169 }
else if ((*it)->type() ==
"kpp_version" || (*it)->type() ==
"kpp_preset" ) {
1170 dbgFile <<
"Saving preset information " << (*it)->description();
1171 png_textp text = (png_textp) png_malloc(png_ptr, (png_uint_32)
sizeof(png_text));
1173 QByteArray keyData = (*it)->description().toLatin1();
1174 text[0].key = keyData.data();
1175 text[0].text = (
char*)(*it)->annotation().data();
1176 text[0].text_length = (*it)->annotation().size();
1177 text[0].compression = -1;
1179 png_set_text(png_ptr, info_ptr, text, 1);
1180 png_free(png_ptr, text);
1187 QByteArray colorProfileData = colorProfile->
rawData();
1190#if PNG_LIBPNG_VER_MAJOR >= 1 && PNG_LIBPNG_VER_MINOR >= 5
1191 const char *typeString = !options.
saveAsHDR ?
"icc" :
"ITUR_2100_PQ_FULL";
1192 png_set_iCCP(png_ptr, info_ptr, (png_const_charp)typeString, PNG_COMPRESSION_TYPE_BASE, (png_const_bytep)colorProfileData.constData(), colorProfileData . size());
1195 char typeStringICC[] =
"icc";
1196 char typeStringHDR[] =
"ITUR_2100_PQ_FULL";
1197 char *typeString = !options.
saveAsHDR ? typeStringICC : typeStringHDR;
1198 png_set_iCCP(png_ptr, info_ptr, typeString, PNG_COMPRESSION_TYPE_BASE, colorProfileData.data(), colorProfileData . size());
1208 QString title = info->
aboutInfo(
"title");
1210 fillText(texts + nbtexts,
"Title", title);
1213 QString abstract = info->
aboutInfo(
"subject");
1214 if (abstract.isEmpty()) {
1218 QString keywords = info->
aboutInfo(
"keyword");
1219 if (!keywords.isEmpty()) {
1220 abstract = abstract +
" keywords: " + keywords;
1222 fillText(texts + nbtexts,
"Description", abstract);
1226 QString license = info->
aboutInfo(
"license");
1228 fillText(texts + nbtexts,
"Copyright", license);
1232 QString author = info->
authorInfo(
"creator");
1236 if (!contact.isEmpty()) {
1237 author = author+
"("+contact+
")";
1240 fillText(texts + nbtexts,
"Author", author);
1244 png_set_text(png_ptr, info_ptr, texts, nbtexts);
1250 if (metaData && !metaData->
empty()) {
1252 dbgFile <<
"Trying to save exif information";
1259 writeRawProfile(png_ptr, info_ptr,
"exif", buffer.data());
1263 dbgFile <<
"Trying to save iptc information";
1270 dbgFile <<
"IPTC information size is" << buffer.data().size();
1271 writeRawProfile(png_ptr, info_ptr,
"iptc", buffer.data());
1275 dbgFile <<
"Trying to save XMP information";
1282 dbgFile <<
"XMP information size is" << buffer.data().size();
1283 writeRawProfile(png_ptr, info_ptr,
"xmp", buffer.data());
1289 png_uint_32 x_resolution, y_resolution;
1291 png_set_pHYs(png_ptr, info_ptr,
CM_TO_POINT(xRes) * 100.0,
CM_TO_POINT(yRes) * 100.0, PNG_RESOLUTION_METER);
1294 png_write_info(png_ptr, info_ptr);
1295 png_write_flush(png_ptr);
1298#ifndef WORDS_BIGENDIAN
1299 if (color_nb_bits > 8)
1300 png_set_swap(png_ptr);
1306 struct RowPointersStruct {
1307 RowPointersStruct(
const QSize &size,
int pixelSize)
1308 : numRows(size.height())
1310 rows =
new png_byte*[numRows];
1312 for (
int i = 0; i < numRows; i++) {
1313 rows[i] =
new png_byte[size.width() * pixelSize];
1317 ~RowPointersStruct() {
1318 for (
int i = 0; i < numRows; i++) {
1324 const int numRows = 0;
1325 png_byte** rows = 0;
1330 RowPointersStruct rowPointers(imageRect.size(), device->
pixelSize());
1333 for (
int y = imageRect.y(); y < imageRect.y() + imageRect.height(); y++, row++) {
1336 switch (color_type) {
1337 case PNG_COLOR_TYPE_GRAY:
1338 case PNG_COLOR_TYPE_GRAY_ALPHA:
1339 if (color_nb_bits == 16) {
1340 quint16 *dst =
reinterpret_cast<quint16 *
>(rowPointers.rows[row]);
1342 const quint16 *d =
reinterpret_cast<const quint16 *
>(it->
oldRawData());
1344 if (options.
alpha) *(dst++) = d[1];
1347 quint8 *dst = rowPointers.rows[row];
1351 if (options.
alpha) *(dst++) = d[1];
1355 case PNG_COLOR_TYPE_RGB:
1356 case PNG_COLOR_TYPE_RGB_ALPHA:
1357 if (color_nb_bits == 16) {
1358 quint16 *dst =
reinterpret_cast<quint16 *
>(rowPointers.rows[row]);
1360 const quint16 *d =
reinterpret_cast<const quint16 *
>(it->
oldRawData());
1364 if (options.
alpha) *(dst++) = d[3];
1367 quint8 *dst = rowPointers.rows[row];
1373 if (options.
alpha) *(dst++) = d[3];
1377 case PNG_COLOR_TYPE_PALETTE: {
1378 quint8 *dst = rowPointers.rows[row];
1383 for (i = 0; i < num_palette; i++) {
1399 png_write_image(png_ptr, rowPointers.rows);
1402 png_write_end(png_ptr, info_ptr);
1405 png_destroy_write_struct(&png_ptr, &info_ptr);
1417 if (png_ptr == 0 || row_number >
PNG_MAX_UINT || pass > 7)
return;
1423 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 QByteArray rawData() const
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)