Krita Source Code Documentation
Loading...
Searching...
No Matches
KisPNGConverter Class Reference

#include <kis_png_converter.h>

+ Inheritance diagram for KisPNGConverter:

Public Slots

virtual void cancel ()
 

Public Member Functions

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)
 
KisImportExportErrorCode buildFile (QIODevice *, const QRect &imageRect, const qreal xRes, const qreal yRes, KisPaintDeviceSP device, vKisAnnotationSP_it annotationsStart, vKisAnnotationSP_it annotationsEnd, KisPNGOptions options, KisMetaData::Store *metaData)
 
KisImportExportErrorCode buildImage (const QString &filename)
 
KisImportExportErrorCode buildImage (QIODevice *iod)
 
KisImageSP image ()
 
 KisPNGConverter (KisDocument *doc, bool batchMode=false)
 
 ~KisPNGConverter () override
 

Static Public Member Functions

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, it will be converted to 8 bits sRGB.
 

Private Member Functions

void progress (png_structp png_ptr, png_uint_32 row_number, int pass)
 

Private Attributes

bool m_batchMode
 
KisDocumentm_doc
 
KisImageSP m_image
 
png_uint_32 m_max_row
 
QString m_path
 
bool m_stop
 

Detailed Description

This class allows to import/export a PNG from either a file or a QIODevice.

Definition at line 70 of file kis_png_converter.h.

Constructor & Destructor Documentation

◆ KisPNGConverter()

KisPNGConverter::KisPNGConverter ( KisDocument * doc,
bool batchMode = false )

Initialize the converter.

Parameters
docthe KisDocument related to the image, can be null if you don't have a KisDocument
batchModewhether to use the batch mode

Definition at line 271 of file kis_png_converter.cpp.

272{
273 // Q_ASSERT(doc);
274 // Q_ASSERT(adapter);
275
276 m_doc = doc;
277 m_stop = false;
278 m_max_row = 0;
279 m_image = 0;
280 m_batchMode = batchMode;
281}
KisDocument * m_doc

References m_batchMode, m_doc, m_image, m_max_row, and m_stop.

◆ ~KisPNGConverter()

KisPNGConverter::~KisPNGConverter ( )
override

Definition at line 283 of file kis_png_converter.cpp.

284{
285}

Member Function Documentation

◆ buildFile() [1/2]

KisImportExportErrorCode KisPNGConverter::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 )

Save a layer to a PNG

Parameters
filenamethe name of the destination file
imageRectthe image rectangle to save
xResresolution along x axis
yResresolution along y axis
devicethe paint device to save
annotationsStartan iterator on the first annotation
annotationsEndan iterator on the last annotation
optionsPNG formatting options
metaDataimage metadata

Definition at line 894 of file kis_png_converter.cpp.

895{
896 dbgFile << "Start writing PNG File " << filename;
897 // Open a QIODevice for writing
898 QFile fp (filename);
899 if (!fp.open(QIODevice::WriteOnly)) {
900 dbgFile << "Failed to open PNG File for writing";
901 return (KisImportExportErrorCannotWrite(fp.error()));
902 }
903
904 KisImportExportErrorCode result = buildFile(&fp, imageRect, xRes, yRes, device, annotationsStart, annotationsEnd, options, metaData);
905
906 return result;
907}
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)
#define dbgFile
Definition kis_debug.h:53

References buildFile(), and dbgFile.

◆ buildFile() [2/2]

KisImportExportErrorCode KisPNGConverter::buildFile ( QIODevice * iodevice,
const QRect & imageRect,
const qreal xRes,
const qreal yRes,
KisPaintDeviceSP device,
vKisAnnotationSP_it annotationsStart,
vKisAnnotationSP_it annotationsEnd,
KisPNGOptions options,
KisMetaData::Store * metaData )

TODO: Firefox still opens the image incorrectly if there is gAMA+cHRM tags present. According to the standard it should use iCCP tag with higher priority, but it doesn't:

"When the iCCP chunk is present, PNG decoders that recognize it and are capable of color management [ICC] shall ignore the gAMA and cHRM chunks and use the iCCP chunk instead and interpret it according to [ICC-1] and [ICC-1A]"

Definition at line 909 of file kis_png_converter.cpp.

910{
912
913 if (!options.alpha) {
915 KoColor c(options.transparencyFillColor, device->colorSpace());
916 tmp->fill(imageRect, c);
917 KisPainter gc(tmp);
918 gc.bitBlt(imageRect.topLeft(), device, imageRect);
919 gc.end();
920 device = tmp;
921 }
922
923 KIS_SAFE_ASSERT_RECOVER(!options.saveAsHDR || !options.forceSRGB) {
924 options.forceSRGB = false;
925 }
926
928 QString dstModel = device->colorSpace()->colorModelId().id();
929 QString dstDepth = device->colorSpace()->colorDepthId().id();
930 const KoColorProfile *dstProfile = device->colorSpace()->profile();
931 bool needColorTransform = false;
932
933 if (options.saveAsHDR || options.forceSRGB || !colormodels.contains(device->colorSpace()->colorModelId().id())) {
934 dstModel = RGBAColorModelID.id();
936
937 needColorTransform = true;
938
939 if (options.saveAsHDR) {
941 }
942 }
943
944 if (options.downsample
948 dstDepth = Integer16BitsColorDepthID.id();
949
950 needColorTransform = true;
951
952 if (options.downsample) {
953 dstDepth = Integer8BitsColorDepthID.id();
954 }
955 }
956
957 if (needColorTransform) {
958 const KoColorSpace *dstCs = KoColorSpaceRegistry::instance()->colorSpace(dstModel, dstDepth, dstProfile);
959
960 if (!dstCs) {
962 }
963
964 device = new KisPaintDevice(*device);
965 device->convertTo(dstCs);
966 }
967
969 options.tryToSaveAsIndexed = false;
970 }
971
972 // Initialize structures
973 png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
974 if (!png_ptr) {
976 }
977
978#ifdef PNG_SET_USER_LIMITS_SUPPORTED
979 /* Remove the user limits, if any */
980 png_set_user_limits(png_ptr, 0x7fffffff, 0x7fffffff);
981 png_set_chunk_cache_max(png_ptr, 0);
982 png_set_chunk_malloc_max(png_ptr, 0);
983#endif
984
985 png_set_error_fn(png_ptr, nullptr, nullptr, kis_png_warning);
986 #ifdef PNG_BENIGN_ERRORS_SUPPORTED
987 png_set_benign_errors(png_ptr, 1);
988 #endif
989
990#if defined(PNG_SKIP_sRGB_CHECK_PROFILE) && defined(PNG_SET_OPTION_SUPPORTED)
991 png_set_option(png_ptr, PNG_SKIP_sRGB_CHECK_PROFILE, PNG_OPTION_ON);
992#endif
993
994
995#ifdef PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED
996 png_set_check_for_invalid_index(png_ptr, 0);
997#endif
998
999 png_infop info_ptr = png_create_info_struct(png_ptr);
1000 if (!info_ptr) {
1001 png_destroy_write_struct(&png_ptr, (png_infopp)0);
1003 }
1004
1005 // If an error occurs during writing, libpng will jump here
1006 if (setjmp(png_jmpbuf(png_ptr))) {
1007 png_destroy_write_struct(&png_ptr, &info_ptr);
1009 }
1010 // Initialize the writing
1011 // png_init_io(png_ptr, fp);
1012 // Setup the progress function
1013 // XXX: Implement progress updating -- png_set_write_status_fn(png_ptr, progress);"
1014 // setProgressTotalSteps(100/*height*/);
1015
1016 /* set the zlib compression level */
1017 png_set_compression_level(png_ptr, options.compression);
1018
1019 png_set_write_fn(png_ptr, (void*)iodevice, _write_fn, _flush_fn);
1020
1021 /* set other zlib parameters */
1022 png_set_compression_mem_level(png_ptr, 8);
1023 png_set_compression_strategy(png_ptr, Z_DEFAULT_STRATEGY);
1024 png_set_compression_window_bits(png_ptr, 15);
1025 png_set_compression_method(png_ptr, 8);
1026 png_set_compression_buffer_size(png_ptr, 8192);
1027
1028 int color_nb_bits = 8 * device->pixelSize() / device->channelCount();
1029 int color_type = getColorTypeforColorSpace(device->colorSpace(), options.alpha);
1030
1031 Q_ASSERT(color_type > -1);
1032
1033 // Try to compute a table of color if the colorspace is RGB8f
1034 QScopedArrayPointer<png_color> palette;
1035 int num_palette = 0;
1036 if (!options.alpha && options.tryToSaveAsIndexed && KoID(device->colorSpace()->id()) == KoID("RGBA")) { // png doesn't handle indexed images and alpha, and only have indexed for RGB8
1037 palette.reset(new png_color[255]);
1038
1039 KisSequentialIterator it(device, imageRect);
1040
1041 bool toomuchcolor = false;
1042 while (it.nextPixel()) {
1043 const quint8* c = it.oldRawData();
1044 bool findit = false;
1045 for (int i = 0; i < num_palette; i++) {
1046 if (palette[i].red == c[2] &&
1047 palette[i].green == c[1] &&
1048 palette[i].blue == c[0]) {
1049 findit = true;
1050 break;
1051 }
1052 }
1053 if (!findit) {
1054 if (num_palette == 255) {
1055 toomuchcolor = true;
1056 break;
1057 }
1058 palette[num_palette].red = c[2];
1059 palette[num_palette].green = c[1];
1060 palette[num_palette].blue = c[0];
1061 num_palette++;
1062 }
1063 }
1064
1065 if (!toomuchcolor) {
1066 dbgFile << "Found a palette of " << num_palette << " colors";
1067 color_type = PNG_COLOR_TYPE_PALETTE;
1068 if (num_palette <= 2) {
1069 color_nb_bits = 1;
1070 } else if (num_palette <= 4) {
1071 color_nb_bits = 2;
1072 } else if (num_palette <= 16) {
1073 color_nb_bits = 4;
1074 } else {
1075 color_nb_bits = 8;
1076 }
1077 } else {
1078 palette.reset();
1079 }
1080 }
1081
1082 int interlace_type = options.interlace ? PNG_INTERLACE_ADAM7 : PNG_INTERLACE_NONE;
1083
1085
1086 png_set_IHDR(png_ptr, info_ptr,
1087 imageRect.width(),
1088 imageRect.height(),
1089 color_nb_bits,
1090 color_type, interlace_type,
1091 PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
1092
1093 // set sRGB only if the profile is sRGB -- http://www.w3.org/TR/PNG/#11sRGB says sRGB and iCCP should not both be present
1094
1095 const bool sRGB = *device->colorSpace()->profile() == *KoColorSpaceRegistry::instance()->p709SRGBProfile();
1096 /*
1097 * This automatically writes the correct gamma and chroma chunks along with the sRGB chunk, but firefox's
1098 * color management is bugged, so once you give it any incentive to start color managing an sRGB image it
1099 * will turn, for example, a nice desaturated rusty red into bright poppy red. So this is disabled for now.
1100 */
1101 /*if (!options.saveSRGBProfile && sRGB) {
1102 png_set_sRGB_gAMA_and_cHRM(png_ptr, info_ptr, PNG_sRGB_INTENT_PERCEPTUAL);
1103 }*/
1104
1105
1115#if 0
1116 if (options.saveAsHDR) {
1117 // https://www.w3.org/TR/PNG/#11gAMA
1118#if defined(PNG_GAMMA_SUPPORTED)
1119 // the values are set in accordance of HDR-PNG standard:
1120 // https://www.w3.org/TR/png-hdr-pq/
1121
1122 png_set_gAMA_fixed(png_ptr, info_ptr, 15000);
1123 dbgFile << "gAMA" << "(Rec 2100)";
1124#endif
1125
1126#if defined PNG_cHRM_SUPPORTED
1127 png_set_cHRM_fixed(png_ptr, info_ptr,
1128 31270, 32900, // white point
1129 70800, 29200, // red
1130 17000, 79700, // green
1131 13100, 4600 // blue
1132 );
1133 dbgFile << "cHRM" << "(Rec 2100)";
1134#endif
1135 }
1136#endif
1137
1138
1139 // we should ensure we don't access non-existing palette object
1140 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(palette || color_type != PNG_COLOR_TYPE_PALETTE, ImportExportCodes::Failure);
1141
1142 // set the palette
1143 if (color_type == PNG_COLOR_TYPE_PALETTE) {
1144 png_set_PLTE(png_ptr, info_ptr, palette.data(), num_palette);
1145 }
1146 // Save annotation
1147 vKisAnnotationSP_it it = annotationsStart;
1148 while (it != annotationsEnd) {
1149 if (!(*it) || (*it)->type().isEmpty()) {
1150 dbgFile << "Warning: empty annotation";
1151 it++;
1152 continue;
1153 }
1154
1155 dbgFile << "Trying to store annotation of type " << (*it) -> type() << " of size " << (*it) -> annotation() . size();
1156
1157 if ((*it) -> type().startsWith(QString("krita_attribute:"))) { //
1158 // Attribute
1159 // XXX: it should be possible to save krita_attributes in the \"CHUNKs\""
1160 dbgFile << "cannot save this annotation : " << (*it) -> type();
1161 } else if ((*it)->type() == "kpp_version" || (*it)->type() == "kpp_preset" ) {
1162 dbgFile << "Saving preset information " << (*it)->description();
1163 png_textp text = (png_textp) png_malloc(png_ptr, (png_uint_32) sizeof(png_text));
1164
1165 QByteArray keyData = (*it)->description().toLatin1();
1166 text[0].key = keyData.data();
1167 text[0].text = (char*)(*it)->annotation().data();
1168 text[0].text_length = (*it)->annotation().size();
1169 text[0].compression = -1;
1170
1171 png_set_text(png_ptr, info_ptr, text, 1);
1172 png_free(png_ptr, text);
1173 }
1174 it++;
1175 }
1176
1177 // Save the color profile
1178 const KoColorProfile* colorProfile = device->colorSpace()->profile();
1179 QByteArray colorProfileData = colorProfile->rawData();
1180 if (!sRGB || options.saveSRGBProfile) {
1181
1182#if PNG_LIBPNG_VER_MAJOR >= 1 && PNG_LIBPNG_VER_MINOR >= 5
1183 const char *typeString = !options.saveAsHDR ? "icc" : "ITUR_2100_PQ_FULL";
1184 png_set_iCCP(png_ptr, info_ptr, (png_const_charp)typeString, PNG_COMPRESSION_TYPE_BASE, (png_const_bytep)colorProfileData.constData(), colorProfileData . size());
1185#else
1186 // older version of libpng has a problem with constness on the parameters
1187 char typeStringICC[] = "icc";
1188 char typeStringHDR[] = "ITUR_2100_PQ_FULL";
1189 char *typeString = !options.saveAsHDR ? typeStringICC : typeStringHDR;
1190 png_set_iCCP(png_ptr, info_ptr, typeString, PNG_COMPRESSION_TYPE_BASE, colorProfileData.data(), colorProfileData . size());
1191#endif
1192 }
1193
1194 // save comments from the document information
1195 // warning: according to the official png spec, the keys need to be capitalized!
1196 if (m_doc) {
1197 png_text texts[4];
1198 int nbtexts = 0;
1199 KoDocumentInfo * info = m_doc->documentInfo();
1200 QString title = info->aboutInfo("title");
1201 if (!title.isEmpty() && options.storeMetaData) {
1202 fillText(texts + nbtexts, "Title", title);
1203 nbtexts++;
1204 }
1205 QString abstract = info->aboutInfo("subject");
1206 if (abstract.isEmpty()) {
1207 abstract = info->aboutInfo("abstract");
1208 }
1209 if (!abstract.isEmpty() && options.storeMetaData) {
1210 QString keywords = info->aboutInfo("keyword");
1211 if (!keywords.isEmpty()) {
1212 abstract = abstract + " keywords: " + keywords;
1213 }
1214 fillText(texts + nbtexts, "Description", abstract);
1215 nbtexts++;
1216 }
1217
1218 QString license = info->aboutInfo("license");
1219 if (!license.isEmpty() && options.storeMetaData) {
1220 fillText(texts + nbtexts, "Copyright", license);
1221 nbtexts++;
1222 }
1223
1224 QString author = info->authorInfo("creator");
1225 if (!author.isEmpty() && options.storeAuthor) {
1226 if (!info->authorContactInfo().isEmpty()) {
1227 QString contact = info->authorContactInfo().at(0);
1228 if (!contact.isEmpty()) {
1229 author = author+"("+contact+")";
1230 }
1231 }
1232 fillText(texts + nbtexts, "Author", author);
1233 nbtexts++;
1234 }
1235
1236 png_set_text(png_ptr, info_ptr, texts, nbtexts);
1237 }
1238
1239 // Save metadata following imagemagick way
1240
1241 // Save exif
1242 if (metaData && !metaData->empty()) {
1243 if (options.exif) {
1244 dbgFile << "Trying to save exif information";
1245
1247 Q_ASSERT(exifIO);
1248
1249 QBuffer buffer;
1250 exifIO->saveTo(metaData, &buffer, KisMetaData::IOBackend::JpegHeader);
1251 writeRawProfile(png_ptr, info_ptr, "exif", buffer.data());
1252 }
1253 // Save IPTC
1254 if (options.iptc) {
1255 dbgFile << "Trying to save iptc information";
1257 Q_ASSERT(iptcIO);
1258
1259 QBuffer buffer;
1260 iptcIO->saveTo(metaData, &buffer, KisMetaData::IOBackend::JpegHeader);
1261
1262 dbgFile << "IPTC information size is" << buffer.data().size();
1263 writeRawProfile(png_ptr, info_ptr, "iptc", buffer.data());
1264 }
1265 // Save XMP
1266 if (options.xmp) {
1267 dbgFile << "Trying to save XMP information";
1269 Q_ASSERT(xmpIO);
1270
1271 QBuffer buffer;
1272 xmpIO->saveTo(metaData, &buffer, KisMetaData::IOBackend::NoHeader);
1273
1274 dbgFile << "XMP information size is" << buffer.data().size();
1275 writeRawProfile(png_ptr, info_ptr, "xmp", buffer.data());
1276 }
1277 }
1278#if 0 // Unimplemented?
1279 // Save resolution
1280 int unit_type;
1281 png_uint_32 x_resolution, y_resolution;
1282#endif
1283 png_set_pHYs(png_ptr, info_ptr, CM_TO_POINT(xRes) * 100.0, CM_TO_POINT(yRes) * 100.0, PNG_RESOLUTION_METER); // It is the "invert" macro because we convert from point-per-inch to points
1284
1285 // Save the information to the file
1286 png_write_info(png_ptr, info_ptr);
1287 png_write_flush(png_ptr);
1288
1289 // swap byteorder on little endian machines.
1290#ifndef WORDS_BIGENDIAN
1291 if (color_nb_bits > 8)
1292 png_set_swap(png_ptr);
1293#endif
1294
1295 // Write the PNG
1296 // png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, 0);
1297
1298 struct RowPointersStruct {
1299 RowPointersStruct(const QSize &size, int pixelSize)
1300 : numRows(size.height())
1301 {
1302 rows = new png_byte*[numRows];
1303
1304 for (int i = 0; i < numRows; i++) {
1305 rows[i] = new png_byte[size.width() * pixelSize];
1306 }
1307 }
1308
1309 ~RowPointersStruct() {
1310 for (int i = 0; i < numRows; i++) {
1311 delete[] rows[i];
1312 }
1313 delete[] rows;
1314 }
1315
1316 const int numRows = 0;
1317 png_byte** rows = 0;
1318 };
1319
1320
1321 // Fill the data structure
1322 RowPointersStruct rowPointers(imageRect.size(), device->pixelSize());
1323
1324 int row = 0;
1325 for (int y = imageRect.y(); y < imageRect.y() + imageRect.height(); y++, row++) {
1326 KisHLineConstIteratorSP it = device->createHLineConstIteratorNG(imageRect.x(), y, imageRect.width());
1327
1328 switch (color_type) {
1329 case PNG_COLOR_TYPE_GRAY:
1330 case PNG_COLOR_TYPE_GRAY_ALPHA:
1331 if (color_nb_bits == 16) {
1332 quint16 *dst = reinterpret_cast<quint16 *>(rowPointers.rows[row]);
1333 do {
1334 const quint16 *d = reinterpret_cast<const quint16 *>(it->oldRawData());
1335 *(dst++) = d[0];
1336 if (options.alpha) *(dst++) = d[1];
1337 } while (it->nextPixel());
1338 } else {
1339 quint8 *dst = rowPointers.rows[row];
1340 do {
1341 const quint8 *d = it->oldRawData();
1342 *(dst++) = d[0];
1343 if (options.alpha) *(dst++) = d[1];
1344 } while (it->nextPixel());
1345 }
1346 break;
1347 case PNG_COLOR_TYPE_RGB:
1348 case PNG_COLOR_TYPE_RGB_ALPHA:
1349 if (color_nb_bits == 16) {
1350 quint16 *dst = reinterpret_cast<quint16 *>(rowPointers.rows[row]);
1351 do {
1352 const quint16 *d = reinterpret_cast<const quint16 *>(it->oldRawData());
1353 *(dst++) = d[2];
1354 *(dst++) = d[1];
1355 *(dst++) = d[0];
1356 if (options.alpha) *(dst++) = d[3];
1357 } while (it->nextPixel());
1358 } else {
1359 quint8 *dst = rowPointers.rows[row];
1360 do {
1361 const quint8 *d = it->oldRawData();
1362 *(dst++) = d[2];
1363 *(dst++) = d[1];
1364 *(dst++) = d[0];
1365 if (options.alpha) *(dst++) = d[3];
1366 } while (it->nextPixel());
1367 }
1368 break;
1369 case PNG_COLOR_TYPE_PALETTE: {
1370 quint8 *dst = rowPointers.rows[row];
1371 KisPNGWriteStream writestream(dst, color_nb_bits);
1372 do {
1373 const quint8 *d = it->oldRawData();
1374 int i;
1375 for (i = 0; i < num_palette; i++) {
1376 if (palette[i].red == d[2] &&
1377 palette[i].green == d[1] &&
1378 palette[i].blue == d[0]) {
1379 break;
1380 }
1381 }
1382 writestream.setNextValue(i);
1383 } while (it->nextPixel());
1384 }
1385 break;
1386 default:
1388 }
1389 }
1390
1391 png_write_image(png_ptr, rowPointers.rows);
1392
1393 // Writing is over
1394 png_write_end(png_ptr, info_ptr);
1395
1396 // Free memory
1397 png_destroy_write_struct(&png_ptr, &info_ptr);
1398 return ImportExportCodes::OK;
1399}
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 CM_TO_POINT(qreal cm)
Definition KoUnit.h:34
virtual const quint8 * oldRawData() const =0
virtual bool nextPixel()=0
KoDocumentInfo * documentInfo() const
@ JpegHeader
Append Jpeg-style header.
@ NoHeader
Don't append any header.
virtual bool saveTo(const Store *store, QIODevice *ioDevice, HeaderType headerType=NoHeader) const =0
static KisMetadataBackendRegistry * instance()
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
virtual KoID colorModelId() const =0
virtual KoID colorDepthId() const =0
virtual const KoColorProfile * profile() const =0
The class containing all meta information about a document.
QStringList authorContactInfo() const
authorContactInfo
QString authorInfo(const QString &info) const
QString aboutInfo(const QString &info) const
const T value(const QString &id) const
Definition KoID.h:30
QString id() const
Definition KoID.cpp:63
#define KIS_SAFE_ASSERT_RECOVER(cond)
Definition kis_assert.h:126
#define KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(cond, val)
Definition kis_assert.h:129
static void _flush_fn(png_structp png_ptr)
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)
vKisAnnotationSP::iterator vKisAnnotationSP_it
Definition kis_types.h:181
int size(const Forest< T > &forest)
Definition KisForest.h:1232
rgba palette[MAX_PALETTE]
Definition palette.c:35
QColor transparencyFillColor
virtual QByteArray rawData() const
const KoColorSpace * colorSpace(const QString &colorModelId, const QString &colorDepthId, const KoColorProfile *profile)
static KoColorSpaceRegistry * instance()
const KoColorProfile * p709SRGBProfile() const
const KoColorProfile * p2020PQProfile() const

References _flush_fn(), _write_fn(), KoDocumentInfo::aboutInfo(), KisPNGOptions::alpha, KoDocumentInfo::authorContactInfo(), KoDocumentInfo::authorInfo(), KisPainter::bitBlt(), KisPaintDevice::channelCount(), CM_TO_POINT(), KoColorSpace::colorDepthId(), KoColorSpace::colorModelId(), KisPaintDevice::colorSpace(), KoColorSpaceRegistry::colorSpace(), KisPNGOptions::compression, KisPaintDevice::convertTo(), KisPaintDevice::createHLineConstIteratorNG(), dbgFile, KisDocument::documentInfo(), KisPNGOptions::downsample, KisMetaData::Store::empty(), KisPainter::end(), KisPNGOptions::exif, ImportExportCodes::Failure, Float16BitsColorDepthID, Float32BitsColorDepthID, Float64BitsColorDepthID, KisPNGOptions::forceSRGB, ImportExportCodes::FormatColorSpaceUnsupported, GrayAColorModelID, KoID::id(), KoColorSpace::id, KisMetadataBackendRegistry::instance(), KoColorSpaceRegistry::instance(), Integer16BitsColorDepthID, Integer8BitsColorDepthID, KisPNGOptions::interlace, ImportExportCodes::InternalError, KisPNGOptions::iptc, KisMetaData::IOBackend::JpegHeader, kis_png_warning(), KIS_SAFE_ASSERT_RECOVER, KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE, m_doc, KisSequentialIteratorBase< IteratorPolicy, SourcePolicy, ProgressPolicy >::nextPixel(), KisBaseConstIteratorNG::nextPixel(), KisMetaData::IOBackend::NoHeader, ImportExportCodes::OK, KisSequentialIteratorBase< IteratorPolicy, SourcePolicy, ProgressPolicy >::oldRawData(), KisBaseConstAccessor::oldRawData(), KoColorSpaceRegistry::p2020PQProfile(), KoColorSpaceRegistry::p709SRGBProfile(), palette, KisPaintDevice::pixelSize(), KoColorSpace::profile(), KoColorProfile::rawData(), RGBAColorModelID, KisPNGOptions::saveAsHDR, KisPNGOptions::saveSRGBProfile, KisMetaData::IOBackend::saveTo(), KisPNGWriteStream::setNextValue(), KisPNGOptions::storeAuthor, KisPNGOptions::storeMetaData, KisPNGOptions::transparencyFillColor, KisPNGOptions::tryToSaveAsIndexed, KoGenericRegistry< T >::value(), and KisPNGOptions::xmp.

◆ buildImage() [1/2]

KisImportExportErrorCode KisPNGConverter::buildImage ( const QString & filename)

Load an image from an URL. If the image is not on a local drive, the image is first downloaded to a temporary location.

Parameters
filenamethe file name of the image

Definition at line 824 of file kis_png_converter.cpp.

825{
826 m_path = filename;
827
828 QFile fp(filename);
829 if (fp.exists()) {
830 if (!fp.open(QIODevice::ReadOnly)) {
831 dbgFile << "Failed to open PNG File";
833 }
834
835 return buildImage(&fp);
836 }
838
839}
KisImportExportErrorCode buildImage(const QString &filename)

References buildImage(), dbgFile, ImportExportCodes::FileFormatIncorrect, ImportExportCodes::FileNotExist, and m_path.

◆ buildImage() [2/2]

KisImportExportErrorCode KisPNGConverter::buildImage ( QIODevice * iod)

Load an image from a QIODevice.

Parameters
ioddevice to access the data

Definition at line 413 of file kis_png_converter.cpp.

414{
415 dbgFile << "Start decoding PNG File";
416
417 png_byte signature[8];
418 iod->peek((char*)signature, 8);
419
420#if PNG_LIBPNG_VER < 10400
421 if (!png_check_sig(signature, 8)) {
422#else
423 if (png_sig_cmp(signature, 0, 8) != 0) {
424#endif
425 iod->close();
427 }
428
429 // Initialize the internal structures
430 png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
431
432 if (!png_ptr) {
433 iod->close();
434 }
435
436#ifdef PNG_SET_USER_LIMITS_SUPPORTED
437 /* Remove the user limits, if any */
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);
441#endif
442
443 png_set_error_fn(png_ptr, nullptr, nullptr, kis_png_warning);
444 #ifdef PNG_BENIGN_ERRORS_SUPPORTED
445 png_set_benign_errors(png_ptr, 1);
446 #endif
447
448 png_infop info_ptr = png_create_info_struct(png_ptr);
449 if (!info_ptr) {
450 png_destroy_read_struct(&png_ptr, (png_infopp)0, (png_infopp)0);
451 iod->close();
453 }
454
455 png_infop end_info = png_create_info_struct(png_ptr);
456 if (!end_info) {
457 png_destroy_read_struct(&png_ptr, &info_ptr, (png_infopp)0);
458 iod->close();
460 }
461
462 // Catch errors
463 if (setjmp(png_jmpbuf(png_ptr))) {
464 png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
465 iod->close();
467 }
468
469 // Initialize the special
470 png_set_read_fn(png_ptr, iod, _read_fn);
471
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);
474#endif
475
476 // read all PNG info up to image data
477 png_read_info(png_ptr, info_ptr);
478
479
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);
482 }
483
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);
486 }
487
488
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);
492 }
493 png_read_update_info(png_ptr, info_ptr);
494
495 // Read information about the png
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;
500 // swap byte order on little endian machines.
501#ifndef WORDS_BIGENDIAN
502 if (color_nb_bits > 8)
503 png_set_swap(png_ptr);
504#endif
505
506 // Determine the colorspace
507 QPair<QString, QString> csName = getColorSpaceForColorType(color_type, color_nb_bits);
508 if (csName.first.isEmpty()) {
509 png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
510 iod->close();
512 }
513 bool hasalpha = (color_type == PNG_COLOR_TYPE_RGB_ALPHA || color_type == PNG_COLOR_TYPE_GRAY_ALPHA);
514
515 // Read image profile
516 png_charp profile_name;
517#if PNG_LIBPNG_VER_MAJOR >= 1 && PNG_LIBPNG_VER_MINOR >= 5
518 png_bytep profile_data;
519#else
520 png_charp profile_data;
521#endif
522 int compression_type;
523 png_uint_32 proflen;
524
525 // Get the various optional chunks
526
527 // https://www.w3.org/TR/PNG/#11cHRM
528#if defined(PNG_cHRM_SUPPORTED)
529 double whitePointX, whitePointY;
530 double redX, redY;
531 double greenX, greenY;
532 double blueX, blueY;
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;
535#endif
536
537 // https://www.w3.org/TR/PNG/#11gAMA
538#if defined(PNG_GAMMA_SUPPORTED)
539 double gamma;
540 png_get_gAMA(png_ptr, info_ptr, &gamma);
541 dbgFile << "gAMA" << gamma;
542#endif
543
544 // https://www.w3.org/TR/PNG/#11sRGB
545#if defined(PNG_sRGB_SUPPORTED)
546 int sRGBIntent;
547 png_get_sRGB(png_ptr, info_ptr, &sRGBIntent);
548 dbgFile << "sRGB" << sRGBIntent;
549#endif
550
551 bool fromBlender = false;
552
553 png_text* text_ptr;
554 int num_comments;
555 png_get_text(png_ptr, info_ptr, &text_ptr, &num_comments);
556
557 for (int i = 0; i < num_comments; i++) {
558 QString key = QString(text_ptr[i].key).toLower();
559 if (key == "file") {
560 QString relatedFile = text_ptr[i].text;
561 if (relatedFile.contains(".blend", Qt::CaseInsensitive)){
562 fromBlender=true;
563 }
564 }
565 }
566
567 bool loadedImageIsHDR = false;
568 const KoColorProfile* profile = 0;
569
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);
572 profile = KoColorSpaceRegistry::instance()->createColorProfile(csName.first, csName.second, profile_rawdata);
573 if (profile) {
574 if (!profile->isSuitableForWorkspace()) {
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";
576 }
577 }
578
579 loadedImageIsHDR = strcmp(profile_name, "ITUR_2100_PQ_FULL") == 0;
580 }
581 else if (color_nb_bits == 16 && !fromBlender && !qAppName().toLower().contains("test") && !m_batchMode) {
582 // Ask the user which color profile to use
583 KisConfig cfg(true);
584 quint32 behaviour = cfg.pasteBehaviour();
585 if (behaviour == KisClipboard::PASTE_ASK) {
586 KisDlgPngImport dlg(m_path, csName.first, csName.second);
588 Q_UNUSED(hijacker);
589 dlg.exec();
590 if (!dlg.profile().isEmpty()) {
591 profile = KoColorSpaceRegistry::instance()->profileByName(dlg.profile());
592 }
593 }
594 }
595 else {
596 dbgFile << "no embedded profile, will use the default profile";
597 }
598
599 const QString colorSpaceId =
600 KoColorSpaceRegistry::instance()->colorSpaceId(csName.first, csName.second);
601
602 // Check that the profile is used by the color space
603 if (profile
604 && (!KoColorSpaceRegistry::instance()->profileIsCompatible(profile, colorSpaceId)
605 || !(profile->isSuitableForOutput() || profile->isSuitableForInput()))) {
606 warnFile << "The profile " << profile->name() << " is not compatible with the color space model " << csName.first << " " << csName.second;
607 profile = 0;
608 }
609
610 // Retrieve a pointer to the colorspace
611 KoColorConversionTransformation* transform = 0;
612 const KoColorSpace* cs = 0;
613
614 if (loadedImageIsHDR &&
615 csName.first == RGBAColorModelID.id() &&
616 csName.second == Integer16BitsColorDepthID.id()) {
617
618 const KoColorSpace *p2020PQCS =
623
624 cs = p2020PQCS;
625
626 } else if (profile && profile->isSuitableForWorkspace()) {
627 dbgFile << "image has embedded profile: " << profile->name() << "\n";
628 cs = KoColorSpaceRegistry::instance()->colorSpace(csName.first, csName.second, profile);
629 }
630 else {
631 // Loading a backup colorspace
632 cs = KoColorSpaceRegistry::instance()->colorSpace(csName.first, csName.second, "");
633 }
634
635 // Create the cmsTransform if needed
636 if (profile && !profile->isSuitableForWorkspace() && profile->isSuitableForInput()) {
638 }
639
640 if (cs == 0) {
641 png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
643 }
644
645 // Creating the KisImageSP
646 if (m_image == 0) {
648 m_image = new KisImage(store, width, height, cs, "built image");
649 }
650
651 // Read resolution
652 int unit_type;
653 png_uint_32 x_resolution, y_resolution;
654
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) {
657 m_image->setResolution((double) POINT_TO_CM(x_resolution) / 100.0, (double) POINT_TO_CM(y_resolution) / 100.0); // It is the "invert" macro because we convert from point-per-inch to points
658 }
659
660 double coeff = quint8_MAX / (double)(pow((double)2, color_nb_bits) - 1);
661 KisPaintLayerSP layer = new KisPaintLayer(m_image.data(), m_image -> nextLayerName(), UCHAR_MAX);
662
663 // Read comments/texts...
664 png_get_text(png_ptr, info_ptr, &text_ptr, &num_comments);
665 if (m_doc) {
667 dbgFile << "There are " << num_comments << " comments in the text";
668 for (int i = 0; i < num_comments; i++) {
669 QString key = QString(text_ptr[i].key).toLower();
670 dbgFile << "key: " << text_ptr[i].key
671 << ", containing: " << text_ptr[i].text
672 << ": " << (key == "raw profile type exif " ? "isExif" : "something else");
673 if (key == "title") {
674 info->setAboutInfo("title", text_ptr[i].text);
675 } else if (key == "description") {
676 info->setAboutInfo("comment", text_ptr[i].text);
677 } else if (key == "author") {
678 info->setAuthorInfo("creator", text_ptr[i].text);
679 } else if (key.contains("raw profile type exif")) {
680 decode_meta_data(text_ptr + i, layer->metaData(), "exif", 6);
681 } else if (key.contains("raw profile type iptc")) {
682 decode_meta_data(text_ptr + i, layer->metaData(), "iptc", 14);
683 } else if (key.contains("raw profile type xmp")) {
684 decode_meta_data(text_ptr + i, layer->metaData(), "xmp", 0);
685 } else if (key == "version") {
686 m_image->addAnnotation(new KisAnnotation("kpp_version", "version", QByteArray(text_ptr[i].text)));
687 } else if (key == "preset") {
688 m_image->addAnnotation(new KisAnnotation("kpp_preset", "preset", QByteArray(text_ptr[i].text)));
689 }
690 }
691 }
692 // Read image data
693 QScopedPointer<KisPNGReaderAbstract> reader;
694 try {
695 if (interlace_type == PNG_INTERLACE_ADAM7) {
696 reader.reset(new KisPNGReaderFullImage(png_ptr, info_ptr, width, height));
697 } else {
698 reader.reset(new KisPNGReaderLineByLine(png_ptr, info_ptr, width, height));
699 }
700 } catch (const std::bad_alloc& e) {
701 // new png_byte[] may raise such an exception if the image
702 // is invalid / to large.
703 dbgFile << "bad alloc: " << e.what();
704 // Free only the already allocated png_byte instances.
705 png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
707 }
708
709 // Read the palette if the file is indexed
710 png_colorp palette ;
711 int num_palette;
712 if (color_type == PNG_COLOR_TYPE_PALETTE) {
713 png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette);
714 }
715
716 // Read the transparency palette
717 quint8 palette_alpha[256];
718 memset(palette_alpha, 255, 256);
719 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
720 if (color_type == PNG_COLOR_TYPE_PALETTE) {
721 png_bytep alpha_ptr;
722 int num_alpha;
723 png_get_tRNS(png_ptr, info_ptr, &alpha_ptr, &num_alpha, 0);
724 for (int i = 0; i < num_alpha; ++i) {
725 palette_alpha[i] = alpha_ptr[i];
726 }
727 }
728 }
729
730 for (png_uint_32 y = 0; y < height; y++) {
731 KisHLineIteratorSP it = layer -> paintDevice() -> createHLineIteratorNG(0, y, width);
732
733 png_bytep row_pointer = reader->readLine();
734
735 switch (color_type) {
736 case PNG_COLOR_TYPE_GRAY:
737 case PNG_COLOR_TYPE_GRAY_ALPHA:
738 if (color_nb_bits == 16) {
739 quint16 *src = reinterpret_cast<quint16 *>(row_pointer);
740 do {
741 quint16 *d = reinterpret_cast<quint16 *>(it->rawData());
742 d[0] = *(src++);
743 if (hasalpha) {
744 d[1] = *(src++);
745 } else {
746 d[1] = quint16_MAX;
747 }
748 if (transform) transform->transformInPlace(reinterpret_cast<quint8*>(d), reinterpret_cast<quint8*>(d), 1);
749 } while (it->nextPixel());
750 } else {
751 KisPNGReadStream stream(row_pointer, color_nb_bits);
752 do {
753 quint8 *d = it->rawData();
754 d[0] = (quint8)(stream.nextValue() * coeff);
755 if (hasalpha) {
756 d[1] = (quint8)(stream.nextValue() * coeff);
757 } else {
758 d[1] = UCHAR_MAX;
759 }
760 if (transform) transform->transformInPlace(d, d, 1);
761 } while (it->nextPixel());
762 }
763 // FIXME:should be able to read 1 and 4 bits depth and scale them to 8 bits"
764 break;
765 case PNG_COLOR_TYPE_RGB:
766 case PNG_COLOR_TYPE_RGB_ALPHA:
767 if (color_nb_bits == 16) {
768 quint16 *src = reinterpret_cast<quint16 *>(row_pointer);
769 do {
770 quint16 *d = reinterpret_cast<quint16 *>(it->rawData());
771 d[2] = *(src++);
772 d[1] = *(src++);
773 d[0] = *(src++);
774 if (hasalpha) d[3] = *(src++);
775 else d[3] = quint16_MAX;
776 if (transform) transform->transformInPlace(reinterpret_cast<quint8 *>(d), reinterpret_cast<quint8*>(d), 1);
777 } while (it->nextPixel());
778 } else {
779 KisPNGReadStream stream(row_pointer, color_nb_bits);
780 do {
781 quint8 *d = it->rawData();
782 d[2] = (quint8)(stream.nextValue() * coeff);
783 d[1] = (quint8)(stream.nextValue() * coeff);
784 d[0] = (quint8)(stream.nextValue() * coeff);
785 if (hasalpha) d[3] = (quint8)(stream.nextValue() * coeff);
786 else d[3] = UCHAR_MAX;
787 if (transform) transform->transformInPlace(d, d, 1);
788 } while (it->nextPixel());
789 }
790 break;
791 case PNG_COLOR_TYPE_PALETTE: {
792 KisPNGReadStream stream(row_pointer, color_nb_bits);
793 do {
794 quint8 *d = it->rawData();
795 quint8 index = stream.nextValue();
796 quint8 alpha = palette_alpha[ index ];
797 if (alpha == 0) {
798 memset(d, 0, 4);
799 } else {
800 png_color c = palette[ index ];
801 d[2] = c.red;
802 d[1] = c.green;
803 d[0] = c.blue;
804 d[3] = alpha;
805 }
806 } while (it->nextPixel());
807 }
808 break;
809 default:
811 }
812 }
813 m_image->addNode(layer.data(), m_image->rootLayer().data());
814
815 png_read_end(png_ptr, end_info);
816 iod->close();
817
818 // Freeing memory
819 png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
821
822}
constexpr qreal POINT_TO_CM(qreal px)
Definition KoUnit.h:33
A data extension mechanism for Krita.
The KisCursorOverrideHijacker class stores all override cursors in a stack, and resets them back afte...
KisUndoStore * createUndoStore()
void addAnnotation(KisAnnotationSP annotation)
KisGroupLayerSP rootLayer() const
void setResolution(double xres, double yres)
virtual KoColorConversionTransformation * createColorConverter(const KoColorSpace *dstColorSpace, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags) const
void setAboutInfo(const QString &info, const QString &data)
void setAuthorInfo(const QString &info, const QString &data)
#define warnFile
Definition kis_debug.h:95
const quint16 quint16_MAX
Definition kis_global.h:25
const quint8 quint8_MAX
Definition kis_global.h:24
static void _read_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)
KisMetaData::Store * metaData()
bool addNode(KisNodeSP node, KisNodeSP parent=KisNodeSP(), KisNodeAdditionFlags flags=KisNodeAdditionFlag::None)
void transformInPlace(const quint8 *src, quint8 *dst, qint32 nPixels) const
virtual bool isSuitableForOutput() const =0
virtual bool isSuitableForWorkspace() const =0
virtual bool isSuitableForInput() const =0
const KoColorProfile * profileByName(const QString &name) const
QString colorSpaceId(const QString &colorModelId, const QString &colorDepthId) const
const KoColorProfile * createColorProfile(const QString &colorModelId, const QString &colorDepthId, const QByteArray &rawData)

References _read_fn(), KisImage::addAnnotation(), KisNodeFacade::addNode(), KoColorSpaceRegistry::colorSpace(), KoColorSpaceRegistry::colorSpaceId(), KoColorSpace::createColorConverter(), KoColorSpaceRegistry::createColorProfile(), KisDocument::createUndoStore(), KisSharedPtr< T >::data(), dbgFile, KisDocument::documentInfo(), ImportExportCodes::Failure, ImportExportCodes::FileFormatIncorrect, ImportExportCodes::FormatColorSpaceUnsupported, ImportExportCodes::FormatFeaturesUnsupported, getColorSpaceForColorType(), KoID::id(), KoColorSpaceRegistry::instance(), Integer16BitsColorDepthID, KoColorConversionTransformation::internalConversionFlags(), KoColorConversionTransformation::internalRenderingIntent(), KoColorProfile::isSuitableForInput(), KoColorProfile::isSuitableForOutput(), KoColorProfile::isSuitableForWorkspace(), kis_png_warning(), m_batchMode, m_doc, m_image, m_path, KisLayer::metaData(), KoColorProfile::name, KisPNGReadStream::nextValue(), ImportExportCodes::OK, KoColorSpaceRegistry::p2020PQProfile(), palette, KisClipboard::PASTE_ASK, KisConfig::pasteBehaviour(), POINT_TO_CM(), KisDlgPngImport::profile(), KoColorSpaceRegistry::profileByName(), quint16_MAX, quint8_MAX, RGBAColorModelID, KisImage::rootLayer(), KoDocumentInfo::setAboutInfo(), KoDocumentInfo::setAuthorInfo(), KisImage::setResolution(), KoColorConversionTransformation::transformInPlace(), and warnFile.

◆ cancel

void KisPNGConverter::cancel ( )
virtualslot

Definition at line 1402 of file kis_png_converter.cpp.

1403{
1404 m_stop = true;
1405}

References m_stop.

◆ image()

KisImageSP KisPNGConverter::image ( )

Retrieve the constructed image

Definition at line 842 of file kis_png_converter.cpp.

843{
844 return m_image;
845}

References m_image.

◆ isColorSpaceSupported()

bool KisPNGConverter::isColorSpaceSupported ( const KoColorSpace * cs)
static

Definition at line 1413 of file kis_png_converter.cpp.

1414{
1415 return colorSpaceIdSupported(cs->id());
1416}

References KoColorSpace::id.

◆ progress()

void KisPNGConverter::progress ( png_structp png_ptr,
png_uint_32 row_number,
int pass )
private

Definition at line 1407 of file kis_png_converter.cpp.

1408{
1409 if (png_ptr == 0 || row_number > PNG_MAX_UINT || pass > 7) return;
1410 // setProgress(row_number);
1411}
#define PNG_MAX_UINT

References PNG_MAX_UINT.

◆ saveDeviceToStore()

bool KisPNGConverter::saveDeviceToStore ( const QString & filename,
const QRect & imageRect,
const qreal xRes,
const qreal yRes,
KisPaintDeviceSP dev,
KoStore * store,
KisMetaData::Store * metaData = 0 )
static

saveDeviceToStore saves the given paint device to the KoStore. If the device is not 8 bits sRGB, it will be converted to 8 bits sRGB.

Returns
true if the saving succeeds

Definition at line 847 of file kis_png_converter.cpp.

848{
849 if (store->open(filename)) {
850 KoStoreDevice io(store);
851 if (!io.open(QIODevice::WriteOnly)) {
852 dbgFile << "Could not open for writing:" << filename;
853 return false;
854 }
855 KisPNGConverter pngconv(0);
856 vKisAnnotationSP_it annotIt;
857 KisMetaData::Store* metaDataStore = 0;
858 if (metaData) {
859 metaDataStore = new KisMetaData::Store(*metaData);
860 }
861 KisPNGOptions options;
862 options.compression = 3;
863 options.interlace = false;
864 options.tryToSaveAsIndexed = false;
865 options.alpha = true;
866 options.saveSRGBProfile = false;
867 options.downsample = false;
868
869 if (dev->colorSpace()->id() != "RGBA") {
870 dev = new KisPaintDevice(*dev.data());
872 }
873
874 KisImportExportErrorCode success = pngconv.buildFile(&io, imageRect, xRes, yRes, dev, annotIt, annotIt, options, metaDataStore);
875 if (!success.isOk()) {
876 dbgFile << "Saving PNG failed:" << filename;
877 delete metaDataStore;
878 return false;
879 }
880 delete metaDataStore;
881 io.close();
882 if (!store->close()) {
883 return false;
884 }
885 } else {
886 dbgFile << "Opening of data file failed :" << filename;
887 return false;
888 }
889 return true;
890
891}
bool close()
Definition KoStore.cpp:156
bool open(const QString &name)
Definition KoStore.cpp:109

References KisPNGOptions::alpha, buildFile(), KoStore::close(), KoStoreDevice::close(), KisPaintDevice::colorSpace(), KisPNGOptions::compression, KisPaintDevice::convertTo(), KisSharedPtr< T >::data(), dbgFile, KisPNGOptions::downsample, KoColorSpace::id, KoColorSpaceRegistry::instance(), KisPNGOptions::interlace, KisImportExportErrorCode::isOk(), KoStore::open(), KoStoreDevice::open(), KisPNGOptions::saveSRGBProfile, and KisPNGOptions::tryToSaveAsIndexed.

Member Data Documentation

◆ m_batchMode

bool KisPNGConverter::m_batchMode
private

Definition at line 129 of file kis_png_converter.h.

◆ m_doc

KisDocument* KisPNGConverter::m_doc
private

Definition at line 127 of file kis_png_converter.h.

◆ m_image

KisImageSP KisPNGConverter::m_image
private

Definition at line 126 of file kis_png_converter.h.

◆ m_max_row

png_uint_32 KisPNGConverter::m_max_row
private

Definition at line 125 of file kis_png_converter.h.

◆ m_path

QString KisPNGConverter::m_path
private

Definition at line 130 of file kis_png_converter.h.

◆ m_stop

bool KisPNGConverter::m_stop
private

Definition at line 128 of file kis_png_converter.h.


The documentation for this class was generated from the following files: