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 902 of file kis_png_converter.cpp.

903{
904 dbgFile << "Start writing PNG File " << filename;
905 // Open a QIODevice for writing
906 QFile fp (filename);
907 if (!fp.open(QIODevice::WriteOnly)) {
908 dbgFile << "Failed to open PNG File for writing";
909 return (KisImportExportErrorCannotWrite(fp.error()));
910 }
911
912 KisImportExportErrorCode result = buildFile(&fp, imageRect, xRes, yRes, device, annotationsStart, annotationsEnd, options, metaData);
913
914 return result;
915}
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 917 of file kis_png_converter.cpp.

918{
920
921 if (!options.alpha) {
923 KoColor c(options.transparencyFillColor, device->colorSpace());
924 tmp->fill(imageRect, c);
925 KisPainter gc(tmp);
926 gc.bitBlt(imageRect.topLeft(), device, imageRect);
927 gc.end();
928 device = tmp;
929 }
930
931 KIS_SAFE_ASSERT_RECOVER(!options.saveAsHDR || !options.forceSRGB) {
932 options.forceSRGB = false;
933 }
934
936 QString dstModel = device->colorSpace()->colorModelId().id();
937 QString dstDepth = device->colorSpace()->colorDepthId().id();
938 const KoColorProfile *dstProfile = device->colorSpace()->profile();
939 bool needColorTransform = false;
940
941 if (options.saveAsHDR || options.forceSRGB || !colormodels.contains(device->colorSpace()->colorModelId().id())) {
942 dstModel = RGBAColorModelID.id();
944
945 needColorTransform = true;
946
947 if (options.saveAsHDR) {
949 }
950 }
951
952 if (options.downsample
956 dstDepth = Integer16BitsColorDepthID.id();
957
958 needColorTransform = true;
959
960 if (options.downsample) {
961 dstDepth = Integer8BitsColorDepthID.id();
962 }
963 }
964
965 if (needColorTransform) {
966 const KoColorSpace *dstCs = KoColorSpaceRegistry::instance()->colorSpace(dstModel, dstDepth, dstProfile);
967
968 if (!dstCs) {
970 }
971
972 device = new KisPaintDevice(*device);
973 device->convertTo(dstCs);
974 }
975
977 options.tryToSaveAsIndexed = false;
978 }
979
980 // Initialize structures
981 png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
982 if (!png_ptr) {
984 }
985
986#ifdef PNG_SET_USER_LIMITS_SUPPORTED
987 /* Remove the user limits, if any */
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);
991#endif
992
993 png_set_error_fn(png_ptr, nullptr, nullptr, kis_png_warning);
994 #ifdef PNG_BENIGN_ERRORS_SUPPORTED
995 png_set_benign_errors(png_ptr, 1);
996 #endif
997
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);
1000#endif
1001
1002
1003#ifdef PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED
1004 png_set_check_for_invalid_index(png_ptr, 0);
1005#endif
1006
1007 png_infop info_ptr = png_create_info_struct(png_ptr);
1008 if (!info_ptr) {
1009 png_destroy_write_struct(&png_ptr, (png_infopp)0);
1011 }
1012
1013 // If an error occurs during writing, libpng will jump here
1014 if (setjmp(png_jmpbuf(png_ptr))) {
1015 png_destroy_write_struct(&png_ptr, &info_ptr);
1017 }
1018 // Initialize the writing
1019 // png_init_io(png_ptr, fp);
1020 // Setup the progress function
1021 // XXX: Implement progress updating -- png_set_write_status_fn(png_ptr, progress);"
1022 // setProgressTotalSteps(100/*height*/);
1023
1024 /* set the zlib compression level */
1025 png_set_compression_level(png_ptr, options.compression);
1026
1027 png_set_write_fn(png_ptr, (void*)iodevice, _write_fn, _flush_fn);
1028
1029 /* set other zlib parameters */
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);
1035
1036 int color_nb_bits = 8 * device->pixelSize() / device->channelCount();
1037 int color_type = getColorTypeforColorSpace(device->colorSpace(), options.alpha);
1038
1039 Q_ASSERT(color_type > -1);
1040
1041 // Try to compute a table of color if the colorspace is RGB8f
1042 QScopedArrayPointer<png_color> palette;
1043 int num_palette = 0;
1044 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
1045 palette.reset(new png_color[255]);
1046
1047 KisSequentialIterator it(device, imageRect);
1048
1049 bool toomuchcolor = false;
1050 while (it.nextPixel()) {
1051 const quint8* c = it.oldRawData();
1052 bool findit = false;
1053 for (int i = 0; i < num_palette; i++) {
1054 if (palette[i].red == c[2] &&
1055 palette[i].green == c[1] &&
1056 palette[i].blue == c[0]) {
1057 findit = true;
1058 break;
1059 }
1060 }
1061 if (!findit) {
1062 if (num_palette == 255) {
1063 toomuchcolor = true;
1064 break;
1065 }
1066 palette[num_palette].red = c[2];
1067 palette[num_palette].green = c[1];
1068 palette[num_palette].blue = c[0];
1069 num_palette++;
1070 }
1071 }
1072
1073 if (!toomuchcolor) {
1074 dbgFile << "Found a palette of " << num_palette << " colors";
1075 color_type = PNG_COLOR_TYPE_PALETTE;
1076 if (num_palette <= 2) {
1077 color_nb_bits = 1;
1078 } else if (num_palette <= 4) {
1079 color_nb_bits = 2;
1080 } else if (num_palette <= 16) {
1081 color_nb_bits = 4;
1082 } else {
1083 color_nb_bits = 8;
1084 }
1085 } else {
1086 palette.reset();
1087 }
1088 }
1089
1090 int interlace_type = options.interlace ? PNG_INTERLACE_ADAM7 : PNG_INTERLACE_NONE;
1091
1093
1094 png_set_IHDR(png_ptr, info_ptr,
1095 imageRect.width(),
1096 imageRect.height(),
1097 color_nb_bits,
1098 color_type, interlace_type,
1099 PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
1100
1101 // set sRGB only if the profile is sRGB -- http://www.w3.org/TR/PNG/#11sRGB says sRGB and iCCP should not both be present
1102
1103 const bool sRGB = *device->colorSpace()->profile() == *KoColorSpaceRegistry::instance()->p709SRGBProfile();
1104 /*
1105 * This automatically writes the correct gamma and chroma chunks along with the sRGB chunk, but firefox's
1106 * color management is bugged, so once you give it any incentive to start color managing an sRGB image it
1107 * will turn, for example, a nice desaturated rusty red into bright poppy red. So this is disabled for now.
1108 */
1109 /*if (!options.saveSRGBProfile && sRGB) {
1110 png_set_sRGB_gAMA_and_cHRM(png_ptr, info_ptr, PNG_sRGB_INTENT_PERCEPTUAL);
1111 }*/
1112
1113
1123#if 0
1124 if (options.saveAsHDR) {
1125 // https://www.w3.org/TR/PNG/#11gAMA
1126#if defined(PNG_GAMMA_SUPPORTED)
1127 // the values are set in accordance of HDR-PNG standard:
1128 // https://www.w3.org/TR/png-hdr-pq/
1129
1130 png_set_gAMA_fixed(png_ptr, info_ptr, 15000);
1131 dbgFile << "gAMA" << "(Rec 2100)";
1132#endif
1133
1134#if defined PNG_cHRM_SUPPORTED
1135 png_set_cHRM_fixed(png_ptr, info_ptr,
1136 31270, 32900, // white point
1137 70800, 29200, // red
1138 17000, 79700, // green
1139 13100, 4600 // blue
1140 );
1141 dbgFile << "cHRM" << "(Rec 2100)";
1142#endif
1143 }
1144#endif
1145
1146
1147 // we should ensure we don't access non-existing palette object
1148 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(palette || color_type != PNG_COLOR_TYPE_PALETTE, ImportExportCodes::Failure);
1149
1150 // set the palette
1151 if (color_type == PNG_COLOR_TYPE_PALETTE) {
1152 png_set_PLTE(png_ptr, info_ptr, palette.data(), num_palette);
1153 }
1154 // Save annotation
1155 vKisAnnotationSP_it it = annotationsStart;
1156 while (it != annotationsEnd) {
1157 if (!(*it) || (*it)->type().isEmpty()) {
1158 dbgFile << "Warning: empty annotation";
1159 it++;
1160 continue;
1161 }
1162
1163 dbgFile << "Trying to store annotation of type " << (*it) -> type() << " of size " << (*it) -> annotation() . size();
1164
1165 if ((*it) -> type().startsWith(QString("krita_attribute:"))) { //
1166 // Attribute
1167 // XXX: it should be possible to save krita_attributes in the \"CHUNKs\""
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));
1172
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;
1178
1179 png_set_text(png_ptr, info_ptr, text, 1);
1180 png_free(png_ptr, text);
1181 }
1182 it++;
1183 }
1184
1185 // Save the color profile
1186 const KoColorProfile* colorProfile = device->colorSpace()->profile();
1187 QByteArray colorProfileData = colorProfile->rawData();
1188 if (!sRGB || options.saveSRGBProfile) {
1189
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());
1193#else
1194 // older version of libpng has a problem with constness on the parameters
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());
1199#endif
1200 }
1201
1202 // save comments from the document information
1203 // warning: according to the official png spec, the keys need to be capitalized!
1204 if (m_doc) {
1205 png_text texts[4];
1206 int nbtexts = 0;
1207 KoDocumentInfo * info = m_doc->documentInfo();
1208 QString title = info->aboutInfo("title");
1209 if (!title.isEmpty() && options.storeMetaData) {
1210 fillText(texts + nbtexts, "Title", title);
1211 nbtexts++;
1212 }
1213 QString abstract = info->aboutInfo("subject");
1214 if (abstract.isEmpty()) {
1215 abstract = info->aboutInfo("abstract");
1216 }
1217 if (!abstract.isEmpty() && options.storeMetaData) {
1218 QString keywords = info->aboutInfo("keyword");
1219 if (!keywords.isEmpty()) {
1220 abstract = abstract + " keywords: " + keywords;
1221 }
1222 fillText(texts + nbtexts, "Description", abstract);
1223 nbtexts++;
1224 }
1225
1226 QString license = info->aboutInfo("license");
1227 if (!license.isEmpty() && options.storeMetaData) {
1228 fillText(texts + nbtexts, "Copyright", license);
1229 nbtexts++;
1230 }
1231
1232 QString author = info->authorInfo("creator");
1233 if (!author.isEmpty() && options.storeAuthor) {
1234 if (!info->authorContactInfo().isEmpty()) {
1235 QString contact = info->authorContactInfo().at(0);
1236 if (!contact.isEmpty()) {
1237 author = author+"("+contact+")";
1238 }
1239 }
1240 fillText(texts + nbtexts, "Author", author);
1241 nbtexts++;
1242 }
1243
1244 png_set_text(png_ptr, info_ptr, texts, nbtexts);
1245 }
1246
1247 // Save metadata following imagemagick way
1248
1249 // Save exif
1250 if (metaData && !metaData->empty()) {
1251 if (options.exif) {
1252 dbgFile << "Trying to save exif information";
1253
1255 Q_ASSERT(exifIO);
1256
1257 QBuffer buffer;
1258 exifIO->saveTo(metaData, &buffer, KisMetaData::IOBackend::JpegHeader);
1259 writeRawProfile(png_ptr, info_ptr, "exif", buffer.data());
1260 }
1261 // Save IPTC
1262 if (options.iptc) {
1263 dbgFile << "Trying to save iptc information";
1265 Q_ASSERT(iptcIO);
1266
1267 QBuffer buffer;
1268 iptcIO->saveTo(metaData, &buffer, KisMetaData::IOBackend::JpegHeader);
1269
1270 dbgFile << "IPTC information size is" << buffer.data().size();
1271 writeRawProfile(png_ptr, info_ptr, "iptc", buffer.data());
1272 }
1273 // Save XMP
1274 if (options.xmp) {
1275 dbgFile << "Trying to save XMP information";
1277 Q_ASSERT(xmpIO);
1278
1279 QBuffer buffer;
1280 xmpIO->saveTo(metaData, &buffer, KisMetaData::IOBackend::NoHeader);
1281
1282 dbgFile << "XMP information size is" << buffer.data().size();
1283 writeRawProfile(png_ptr, info_ptr, "xmp", buffer.data());
1284 }
1285 }
1286#if 0 // Unimplemented?
1287 // Save resolution
1288 int unit_type;
1289 png_uint_32 x_resolution, y_resolution;
1290#endif
1291 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
1292
1293 // Save the information to the file
1294 png_write_info(png_ptr, info_ptr);
1295 png_write_flush(png_ptr);
1296
1297 // swap byteorder on little endian machines.
1298#ifndef WORDS_BIGENDIAN
1299 if (color_nb_bits > 8)
1300 png_set_swap(png_ptr);
1301#endif
1302
1303 // Write the PNG
1304 // png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, 0);
1305
1306 struct RowPointersStruct {
1307 RowPointersStruct(const QSize &size, int pixelSize)
1308 : numRows(size.height())
1309 {
1310 rows = new png_byte*[numRows];
1311
1312 for (int i = 0; i < numRows; i++) {
1313 rows[i] = new png_byte[size.width() * pixelSize];
1314 }
1315 }
1316
1317 ~RowPointersStruct() {
1318 for (int i = 0; i < numRows; i++) {
1319 delete[] rows[i];
1320 }
1321 delete[] rows;
1322 }
1323
1324 const int numRows = 0;
1325 png_byte** rows = 0;
1326 };
1327
1328
1329 // Fill the data structure
1330 RowPointersStruct rowPointers(imageRect.size(), device->pixelSize());
1331
1332 int row = 0;
1333 for (int y = imageRect.y(); y < imageRect.y() + imageRect.height(); y++, row++) {
1334 KisHLineConstIteratorSP it = device->createHLineConstIteratorNG(imageRect.x(), y, imageRect.width());
1335
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]);
1341 do {
1342 const quint16 *d = reinterpret_cast<const quint16 *>(it->oldRawData());
1343 *(dst++) = d[0];
1344 if (options.alpha) *(dst++) = d[1];
1345 } while (it->nextPixel());
1346 } else {
1347 quint8 *dst = rowPointers.rows[row];
1348 do {
1349 const quint8 *d = it->oldRawData();
1350 *(dst++) = d[0];
1351 if (options.alpha) *(dst++) = d[1];
1352 } while (it->nextPixel());
1353 }
1354 break;
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]);
1359 do {
1360 const quint16 *d = reinterpret_cast<const quint16 *>(it->oldRawData());
1361 *(dst++) = d[2];
1362 *(dst++) = d[1];
1363 *(dst++) = d[0];
1364 if (options.alpha) *(dst++) = d[3];
1365 } while (it->nextPixel());
1366 } else {
1367 quint8 *dst = rowPointers.rows[row];
1368 do {
1369 const quint8 *d = it->oldRawData();
1370 *(dst++) = d[2];
1371 *(dst++) = d[1];
1372 *(dst++) = d[0];
1373 if (options.alpha) *(dst++) = d[3];
1374 } while (it->nextPixel());
1375 }
1376 break;
1377 case PNG_COLOR_TYPE_PALETTE: {
1378 quint8 *dst = rowPointers.rows[row];
1379 KisPNGWriteStream writestream(dst, color_nb_bits);
1380 do {
1381 const quint8 *d = it->oldRawData();
1382 int i;
1383 for (i = 0; i < num_palette; i++) {
1384 if (palette[i].red == d[2] &&
1385 palette[i].green == d[1] &&
1386 palette[i].blue == d[0]) {
1387 break;
1388 }
1389 }
1390 writestream.setNextValue(i);
1391 } while (it->nextPixel());
1392 }
1393 break;
1394 default:
1396 }
1397 }
1398
1399 png_write_image(png_ptr, rowPointers.rows);
1400
1401 // Writing is over
1402 png_write_end(png_ptr, info_ptr);
1403
1404 // Free memory
1405 png_destroy_write_struct(&png_ptr, &info_ptr);
1406 return ImportExportCodes::OK;
1407}
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 832 of file kis_png_converter.cpp.

833{
834 m_path = filename;
835
836 QFile fp(filename);
837 if (fp.exists()) {
838 if (!fp.open(QIODevice::ReadOnly)) {
839 dbgFile << "Failed to open PNG File";
841 }
842
843 return buildImage(&fp);
844 }
846
847}
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 if (png_get_iCCP(png_ptr, info_ptr, &profile_name, &compression_type, &profile_data, &proflen)) {
570 QByteArray profile_rawdata;
571 // XXX: Hardcoded for icc type -- is that correct for us?
572 profile_rawdata.resize(proflen);
573 memcpy(profile_rawdata.data(), profile_data, proflen);
574 profile = KoColorSpaceRegistry::instance()->createColorProfile(csName.first, csName.second, profile_rawdata);
575 Q_CHECK_PTR(profile);
576 if (profile) {
577 // dbgFile << "profile name: " << profile->productName() << " profile description: " << profile->productDescription() << " information sur le produit: " << profile->productInfo();
578 if (!profile->isSuitableForOutput()) {
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"; // TODO: in ko2 popup a selection menu to inform the user
580 }
581 }
582
583 loadedImageIsHDR = strcmp(profile_name, "ITUR_2100_PQ_FULL") == 0;
584 }
585 else {
586 dbgFile << "no embedded profile, will use the default profile";
587 if (color_nb_bits == 16 && !fromBlender && !qAppName().toLower().contains("test") && !m_batchMode) {
588 KisConfig cfg(true);
589 quint32 behaviour = cfg.pasteBehaviour();
590 if (behaviour == KisClipboard::PASTE_ASK) {
591 KisDlgPngImport dlg(m_path, csName.first, csName.second);
593 Q_UNUSED(hijacker);
594 dlg.exec();
595 if (!dlg.profile().isEmpty()) {
596 profile = KoColorSpaceRegistry::instance()->profileByName(dlg.profile());
597 }
598 }
599 }
600 dbgFile << "no embedded profile, will use the default profile";
601 }
602
603 const QString colorSpaceId =
604 KoColorSpaceRegistry::instance()->colorSpaceId(csName.first, csName.second);
605
606 // Check that the profile is used by the color space
607 if (profile && !KoColorSpaceRegistry::instance()->profileIsCompatible(profile, colorSpaceId)) {
608 warnFile << "The profile " << profile->name() << " is not compatible with the color space model " << csName.first << " " << csName.second;
609 profile = 0;
610 }
611
612 // Retrieve a pointer to the colorspace
613 KoColorConversionTransformation* transform = 0;
614 const KoColorSpace* cs = 0;
615
616 if (loadedImageIsHDR &&
617 csName.first == RGBAColorModelID.id() &&
618 csName.second == Integer16BitsColorDepthID.id()) {
619
620 const KoColorSpace *p2020PQCS =
625
626 cs = p2020PQCS;
627
628 } else if (profile && profile->isSuitableForOutput()) {
629 dbgFile << "image has embedded profile: " << profile->name() << "\n";
630 cs = KoColorSpaceRegistry::instance()->colorSpace(csName.first, csName.second, profile);
631 }
632 else {
633 if (csName.first == RGBAColorModelID.id()) {
634 cs = KoColorSpaceRegistry::instance()->colorSpace(csName.first, csName.second, "sRGB-elle-V2-srgbtrc.icc");
635 } else if (csName.first == GrayAColorModelID.id()) {
636 cs = KoColorSpaceRegistry::instance()->colorSpace(csName.first, csName.second, "Gray-D50-elle-V2-srgbtrc.icc");
637 } else {
638 cs = KoColorSpaceRegistry::instance()->colorSpace(csName.first, csName.second, 0);
639 }
640
641 //TODO: two fixes : one tell the user about the problem and ask for a solution, and two once the kocolorspace include KoColorTransformation, use that instead of hacking a lcms transformation
642 // Create the cmsTransform if needed
643 if (profile) {
645 }
646 }
647
648 if (cs == 0) {
649 png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
651 }
652
653 // Creating the KisImageSP
654 if (m_image == 0) {
656 m_image = new KisImage(store, width, height, cs, "built image");
657 }
658
659 // Read resolution
660 int unit_type;
661 png_uint_32 x_resolution, y_resolution;
662
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) {
665 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
666 }
667
668 double coeff = quint8_MAX / (double)(pow((double)2, color_nb_bits) - 1);
669 KisPaintLayerSP layer = new KisPaintLayer(m_image.data(), m_image -> nextLayerName(), UCHAR_MAX);
670
671 // Read comments/texts...
672 png_get_text(png_ptr, info_ptr, &text_ptr, &num_comments);
673 if (m_doc) {
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") {
682 info->setAboutInfo("title", text_ptr[i].text);
683 } else if (key == "description") {
684 info->setAboutInfo("comment", text_ptr[i].text);
685 } else if (key == "author") {
686 info->setAuthorInfo("creator", text_ptr[i].text);
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") {
694 m_image->addAnnotation(new KisAnnotation("kpp_version", "version", QByteArray(text_ptr[i].text)));
695 } else if (key == "preset") {
696 m_image->addAnnotation(new KisAnnotation("kpp_preset", "preset", QByteArray(text_ptr[i].text)));
697 }
698 }
699 }
700 // Read image data
701 QScopedPointer<KisPNGReaderAbstract> reader;
702 try {
703 if (interlace_type == PNG_INTERLACE_ADAM7) {
704 reader.reset(new KisPNGReaderFullImage(png_ptr, info_ptr, width, height));
705 } else {
706 reader.reset(new KisPNGReaderLineByLine(png_ptr, info_ptr, width, height));
707 }
708 } catch (const std::bad_alloc& e) {
709 // new png_byte[] may raise such an exception if the image
710 // is invalid / to large.
711 dbgFile << "bad alloc: " << e.what();
712 // Free only the already allocated png_byte instances.
713 png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
715 }
716
717 // Read the palette if the file is indexed
718 png_colorp palette ;
719 int num_palette;
720 if (color_type == PNG_COLOR_TYPE_PALETTE) {
721 png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette);
722 }
723
724 // Read the transparency 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) {
729 png_bytep alpha_ptr;
730 int num_alpha;
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];
734 }
735 }
736 }
737
738 for (png_uint_32 y = 0; y < height; y++) {
739 KisHLineIteratorSP it = layer -> paintDevice() -> createHLineIteratorNG(0, y, width);
740
741 png_bytep row_pointer = reader->readLine();
742
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);
748 do {
749 quint16 *d = reinterpret_cast<quint16 *>(it->rawData());
750 d[0] = *(src++);
751 if (hasalpha) {
752 d[1] = *(src++);
753 } else {
754 d[1] = quint16_MAX;
755 }
756 if (transform) transform->transformInPlace(reinterpret_cast<quint8*>(d), reinterpret_cast<quint8*>(d), 1);
757 } while (it->nextPixel());
758 } else {
759 KisPNGReadStream stream(row_pointer, color_nb_bits);
760 do {
761 quint8 *d = it->rawData();
762 d[0] = (quint8)(stream.nextValue() * coeff);
763 if (hasalpha) {
764 d[1] = (quint8)(stream.nextValue() * coeff);
765 } else {
766 d[1] = UCHAR_MAX;
767 }
768 if (transform) transform->transformInPlace(d, d, 1);
769 } while (it->nextPixel());
770 }
771 // FIXME:should be able to read 1 and 4 bits depth and scale them to 8 bits"
772 break;
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);
777 do {
778 quint16 *d = reinterpret_cast<quint16 *>(it->rawData());
779 d[2] = *(src++);
780 d[1] = *(src++);
781 d[0] = *(src++);
782 if (hasalpha) d[3] = *(src++);
783 else d[3] = quint16_MAX;
784 if (transform) transform->transformInPlace(reinterpret_cast<quint8 *>(d), reinterpret_cast<quint8*>(d), 1);
785 } while (it->nextPixel());
786 } else {
787 KisPNGReadStream stream(row_pointer, color_nb_bits);
788 do {
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;
795 if (transform) transform->transformInPlace(d, d, 1);
796 } while (it->nextPixel());
797 }
798 break;
799 case PNG_COLOR_TYPE_PALETTE: {
800 KisPNGReadStream stream(row_pointer, color_nb_bits);
801 do {
802 quint8 *d = it->rawData();
803 quint8 index = stream.nextValue();
804 quint8 alpha = palette_alpha[ index ];
805 if (alpha == 0) {
806 memset(d, 0, 4);
807 } else {
808 png_color c = palette[ index ];
809 d[2] = c.red;
810 d[1] = c.green;
811 d[0] = c.blue;
812 d[3] = alpha;
813 }
814 } while (it->nextPixel());
815 }
816 break;
817 default:
819 }
820 }
821 m_image->addNode(layer.data(), m_image->rootLayer().data());
822
823 png_read_end(png_ptr, end_info);
824 iod->close();
825
826 // Freeing memory
827 png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
829
830}
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
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(), GrayAColorModelID, KoID::id(), KoColorSpaceRegistry::instance(), Integer16BitsColorDepthID, KoColorConversionTransformation::internalConversionFlags(), KoColorConversionTransformation::internalRenderingIntent(), KoColorProfile::isSuitableForOutput(), 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 1410 of file kis_png_converter.cpp.

1411{
1412 m_stop = true;
1413}

References m_stop.

◆ image()

KisImageSP KisPNGConverter::image ( )

Retrieve the constructed image

Definition at line 850 of file kis_png_converter.cpp.

851{
852 return m_image;
853}

References m_image.

◆ isColorSpaceSupported()

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

Definition at line 1421 of file kis_png_converter.cpp.

1422{
1423 return colorSpaceIdSupported(cs->id());
1424}

References KoColorSpace::id.

◆ progress()

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

Definition at line 1415 of file kis_png_converter.cpp.

1416{
1417 if (png_ptr == 0 || row_number > PNG_MAX_UINT || pass > 7) return;
1418 // setProgress(row_number);
1419}
#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 855 of file kis_png_converter.cpp.

856{
857 if (store->open(filename)) {
858 KoStoreDevice io(store);
859 if (!io.open(QIODevice::WriteOnly)) {
860 dbgFile << "Could not open for writing:" << filename;
861 return false;
862 }
863 KisPNGConverter pngconv(0);
864 vKisAnnotationSP_it annotIt;
865 KisMetaData::Store* metaDataStore = 0;
866 if (metaData) {
867 metaDataStore = new KisMetaData::Store(*metaData);
868 }
869 KisPNGOptions options;
870 options.compression = 3;
871 options.interlace = false;
872 options.tryToSaveAsIndexed = false;
873 options.alpha = true;
874 options.saveSRGBProfile = false;
875 options.downsample = false;
876
877 if (dev->colorSpace()->id() != "RGBA") {
878 dev = new KisPaintDevice(*dev.data());
880 }
881
882 KisImportExportErrorCode success = pngconv.buildFile(&io, imageRect, xRes, yRes, dev, annotIt, annotIt, options, metaDataStore);
883 if (!success.isOk()) {
884 dbgFile << "Saving PNG failed:" << filename;
885 delete metaDataStore;
886 return false;
887 }
888 delete metaDataStore;
889 io.close();
890 if (!store->close()) {
891 return false;
892 }
893 } else {
894 dbgFile << "Opening of data file failed :" << filename;
895 return false;
896 }
897 return true;
898
899}
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: