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

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

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

827{
828 m_path = filename;
829
830 QFile fp(filename);
831 if (fp.exists()) {
832 if (!fp.open(QIODevice::ReadOnly)) {
833 dbgFile << "Failed to open PNG File";
835 }
836
837 return buildImage(&fp);
838 }
840
841}
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;
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 sRGB 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 = 0, y_resolution = 0;
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 } else if (unit_type == PNG_RESOLUTION_UNKNOWN) {
659 m_image->setResolution(100.0, 100.0);
660 }
661
662 double coeff = quint8_MAX / (double)(pow((double)2, color_nb_bits) - 1);
663 KisPaintLayerSP layer = new KisPaintLayer(m_image.data(), m_image -> nextLayerName(), UCHAR_MAX);
664
665 // Read comments/texts...
666 png_get_text(png_ptr, info_ptr, &text_ptr, &num_comments);
667 if (m_doc) {
669 dbgFile << "There are " << num_comments << " comments in the text";
670 for (int i = 0; i < num_comments; i++) {
671 QString key = QString(text_ptr[i].key).toLower();
672 dbgFile << "key: " << text_ptr[i].key
673 << ", containing: " << text_ptr[i].text
674 << ": " << (key == "raw profile type exif " ? "isExif" : "something else");
675 if (key == "title") {
676 info->setAboutInfo("title", text_ptr[i].text);
677 } else if (key == "description") {
678 info->setAboutInfo("comment", text_ptr[i].text);
679 } else if (key == "author") {
680 info->setAuthorInfo("creator", text_ptr[i].text);
681 } else if (key.contains("raw profile type exif")) {
682 decode_meta_data(text_ptr + i, layer->metaData(), "exif", 6);
683 } else if (key.contains("raw profile type iptc")) {
684 decode_meta_data(text_ptr + i, layer->metaData(), "iptc", 14);
685 } else if (key.contains("raw profile type xmp")) {
686 decode_meta_data(text_ptr + i, layer->metaData(), "xmp", 0);
687 } else if (key == "version") {
688 m_image->addAnnotation(new KisAnnotation("kpp_version", "version", QByteArray(text_ptr[i].text)));
689 } else if (key == "preset") {
690 m_image->addAnnotation(new KisAnnotation("kpp_preset", "preset", QByteArray(text_ptr[i].text)));
691 }
692 }
693 }
694 // Read image data
695 QScopedPointer<KisPNGReaderAbstract> reader;
696 try {
697 if (interlace_type == PNG_INTERLACE_ADAM7) {
698 reader.reset(new KisPNGReaderFullImage(png_ptr, info_ptr, width, height));
699 } else {
700 reader.reset(new KisPNGReaderLineByLine(png_ptr, info_ptr, width, height));
701 }
702 } catch (const std::bad_alloc& e) {
703 // new png_byte[] may raise such an exception if the image
704 // is invalid / to large.
705 dbgFile << "bad alloc: " << e.what();
706 // Free only the already allocated png_byte instances.
707 png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
709 }
710
711 // Read the palette if the file is indexed
712 png_colorp palette ;
713 int num_palette;
714 if (color_type == PNG_COLOR_TYPE_PALETTE) {
715 png_get_PLTE(png_ptr, info_ptr, &palette, &num_palette);
716 }
717
718 // Read the transparency palette
719 quint8 palette_alpha[256];
720 memset(palette_alpha, 255, 256);
721 if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
722 if (color_type == PNG_COLOR_TYPE_PALETTE) {
723 png_bytep alpha_ptr;
724 int num_alpha;
725 png_get_tRNS(png_ptr, info_ptr, &alpha_ptr, &num_alpha, 0);
726 for (int i = 0; i < num_alpha; ++i) {
727 palette_alpha[i] = alpha_ptr[i];
728 }
729 }
730 }
731
732 for (png_uint_32 y = 0; y < height; y++) {
733 KisHLineIteratorSP it = layer -> paintDevice() -> createHLineIteratorNG(0, y, width);
734
735 png_bytep row_pointer = reader->readLine();
736
737 switch (color_type) {
738 case PNG_COLOR_TYPE_GRAY:
739 case PNG_COLOR_TYPE_GRAY_ALPHA:
740 if (color_nb_bits == 16) {
741 quint16 *src = reinterpret_cast<quint16 *>(row_pointer);
742 do {
743 quint16 *d = reinterpret_cast<quint16 *>(it->rawData());
744 d[0] = *(src++);
745 if (hasalpha) {
746 d[1] = *(src++);
747 } else {
748 d[1] = quint16_MAX;
749 }
750 if (transform) transform->transformInPlace(reinterpret_cast<quint8*>(d), reinterpret_cast<quint8*>(d), 1);
751 } while (it->nextPixel());
752 } else {
753 KisPNGReadStream stream(row_pointer, color_nb_bits);
754 do {
755 quint8 *d = it->rawData();
756 d[0] = (quint8)(stream.nextValue() * coeff);
757 if (hasalpha) {
758 d[1] = (quint8)(stream.nextValue() * coeff);
759 } else {
760 d[1] = UCHAR_MAX;
761 }
762 if (transform) transform->transformInPlace(d, d, 1);
763 } while (it->nextPixel());
764 }
765 // FIXME:should be able to read 1 and 4 bits depth and scale them to 8 bits"
766 break;
767 case PNG_COLOR_TYPE_RGB:
768 case PNG_COLOR_TYPE_RGB_ALPHA:
769 if (color_nb_bits == 16) {
770 quint16 *src = reinterpret_cast<quint16 *>(row_pointer);
771 do {
772 quint16 *d = reinterpret_cast<quint16 *>(it->rawData());
773 d[2] = *(src++);
774 d[1] = *(src++);
775 d[0] = *(src++);
776 if (hasalpha) d[3] = *(src++);
777 else d[3] = quint16_MAX;
778 if (transform) transform->transformInPlace(reinterpret_cast<quint8 *>(d), reinterpret_cast<quint8*>(d), 1);
779 } while (it->nextPixel());
780 } else {
781 KisPNGReadStream stream(row_pointer, color_nb_bits);
782 do {
783 quint8 *d = it->rawData();
784 d[2] = (quint8)(stream.nextValue() * coeff);
785 d[1] = (quint8)(stream.nextValue() * coeff);
786 d[0] = (quint8)(stream.nextValue() * coeff);
787 if (hasalpha) d[3] = (quint8)(stream.nextValue() * coeff);
788 else d[3] = UCHAR_MAX;
789 if (transform) transform->transformInPlace(d, d, 1);
790 } while (it->nextPixel());
791 }
792 break;
793 case PNG_COLOR_TYPE_PALETTE: {
794 KisPNGReadStream stream(row_pointer, color_nb_bits);
795 do {
796 quint8 *d = it->rawData();
797 quint8 index = stream.nextValue();
798 quint8 alpha = palette_alpha[ index ];
799 if (alpha == 0) {
800 memset(d, 0, 4);
801 } else {
802 png_color c = palette[ index ];
803 d[2] = c.red;
804 d[1] = c.green;
805 d[0] = c.blue;
806 d[3] = alpha;
807 }
808 } while (it->nextPixel());
809 }
810 break;
811 default:
813 }
814 }
815 m_image->addNode(layer.data(), m_image->rootLayer().data());
816
817 png_read_end(png_ptr, end_info);
818 iod->close();
819
820 // Freeing memory
821 png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
823
824}
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(), KoColorSpaceRegistry::p709SRGBProfile(), 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 1404 of file kis_png_converter.cpp.

1405{
1406 m_stop = true;
1407}

References m_stop.

◆ image()

KisImageSP KisPNGConverter::image ( )

Retrieve the constructed image

Definition at line 844 of file kis_png_converter.cpp.

845{
846 return m_image;
847}

References m_image.

◆ isColorSpaceSupported()

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

Definition at line 1415 of file kis_png_converter.cpp.

1416{
1417 return colorSpaceIdSupported(cs->id());
1418}

References KoColorSpace::id.

◆ progress()

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

Definition at line 1409 of file kis_png_converter.cpp.

1410{
1411 if (png_ptr == 0 || row_number > PNG_MAX_UINT || pass > 7) return;
1412 // setProgress(row_number);
1413}
#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 849 of file kis_png_converter.cpp.

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