135#if LIBHEIF_HAVE_VERSION(1, 13, 0)
139#if LIBHEIF_HAVE_VERSION(1, 20, 2)
140 using HeifStrideType = size_t;
141 auto heifGetPlaneMethod = std::mem_fn(qNonConstOverload<heif_channel, HeifStrideType*>(&heif::Image::get_plane2));
142#elif LIBHEIF_HAVE_VERSION(1, 20, 0)
143 using HeifStrideType = size_t;
144 auto heifGetPlaneMethod = std::mem_fn(qNonConstOverload<heif_channel, HeifStrideType*>(&heif::Image::get_plane));
146 using HeifStrideType = int;
147 auto heifGetPlaneMethod = std::mem_fn(qNonConstOverload<heif_channel, HeifStrideType*>(&heif::Image::get_plane));
176 bool convertToRec2020 =
false;
179 QString conversionOption =
180 (configuration->getString(
"floatingPointConversionOption",
182 if (conversionOption ==
"Rec2100PQ") {
183 convertToRec2020 =
true;
185 }
else if (conversionOption ==
"Rec2100HLG") {
186 convertToRec2020 =
true;
188 }
else if (conversionOption ==
"ApplyPQ") {
190 }
else if (conversionOption ==
"ApplyHLG") {
192 }
else if (conversionOption ==
"ApplySMPTE428") {
210 int quality = configuration->getInt(
"quality", 50);
211 bool lossless = configuration->getBool(
"lossless",
false);
213 float hlgGamma = configuration->getFloat(
"HLGgamma", 1.2f);
214 float hlgNominalPeak = configuration->getFloat(
"HLGnominalPeak", 1000.0f);
215 bool removeHGLOOTF = configuration->getBool(
"removeHGLOOTF",
true);
224 heif::Encoder
encoder(heif_compression_HEVC);
228 encoder = heif::Encoder(heif_compression_AV1);
232 encoder.set_lossy_quality(quality);
235 encoder.set_lossy_quality(100);
237 encoder.set_lossless(lossless);
239 encoder.set_parameter(
"chroma", configuration->getString(
"chroma",
"444").toStdString());
244 int width = image->
width();
245 int height = image->
height();
249 heif_chroma chroma = hasAlpha? heif_chroma_interleaved_RRGGBBAA_LE: heif_chroma_interleaved_RRGGBB_LE;
250 if (QSysInfo::ByteOrder == QSysInfo::BigEndian) {
251 chroma = hasAlpha? heif_chroma_interleaved_RRGGBBAA_BE: heif_chroma_interleaved_RRGGBB_BE;
258 dbgFile <<
"saving as 8bit rgba";
259 img.create(width,height, heif_colorspace_RGB, heif_chroma_444);
260 img.add_plane(heif_channel_R, width,height, 8);
261 img.add_plane(heif_channel_G, width,height, 8);
262 img.add_plane(heif_channel_B, width,height, 8);
264 HeifStrideType strideR = 0;
265 HeifStrideType strideG = 0;
266 HeifStrideType strideB = 0;
267 HeifStrideType strideA = 0;
269 uint8_t *ptrR = heifGetPlaneMethod(img, heif_channel_R, &strideR);
270 uint8_t *ptrG = heifGetPlaneMethod(img, heif_channel_G, &strideG);
271 uint8_t *ptrB = heifGetPlaneMethod(img, heif_channel_B, &strideB);
273 uint8_t *ptrA = [&]() -> uint8_t * {
275 img.add_plane(heif_channel_Alpha, width, height, 8);
276 return heifGetPlaneMethod(img, heif_channel_Alpha, &strideA);
299 dbgFile <<
"Saving as 12bit rgba";
300 img.create(width, height, heif_colorspace_RGB, chroma);
301 img.add_plane(heif_channel_interleaved, width, height, 12);
303 HeifStrideType stride = 0;
305 uint8_t *ptr = heifGetPlaneMethod(img, heif_channel_interleaved, &stride);
339 dbgFile <<
"Saving as 8 bit monochrome.";
340 img.create(width, height, heif_colorspace_monochrome, heif_chroma_monochrome);
342 img.add_plane(heif_channel_Y, width, height, 8);
344 HeifStrideType strideG = 0;
345 HeifStrideType strideA = 0;
347 uint8_t *ptrG = heifGetPlaneMethod(img, heif_channel_Y, &strideG);
348 uint8_t *ptrA = [&]() -> uint8_t * {
350 img.add_plane(heif_channel_Alpha, width, height, 8);
351 return heifGetPlaneMethod(img, heif_channel_Alpha, &strideA);
372 dbgFile <<
"Saving as 12 bit monochrome";
373 img.create(width, height, heif_colorspace_monochrome, heif_chroma_monochrome);
375 img.add_plane(heif_channel_Y, width, height, 12);
377 HeifStrideType strideG = 0;
378 HeifStrideType strideA = 0;
380 uint8_t *ptrG = heifGetPlaneMethod(img, heif_channel_Y, &strideG);
381 uint8_t *ptrA = [&]() -> uint8_t * {
383 img.add_plane(heif_channel_Alpha, width, height, 12);
384 return heifGetPlaneMethod(img, heif_channel_Alpha, &strideA);
410 std::vector<uint8_t> rawProfile(rawProfileBA.begin(), rawProfileBA.end());
411 img.set_raw_color_profile(heif_color_profile_type_prof, rawProfile);
413 heif::ColorProfile_nclx nclxDescription;
414 nclxDescription.set_full_range_flag(
true);
415 nclxDescription.set_matrix_coefficients(heif_matrix_coefficients_RGB_GBR);
416 if (convertToRec2020) {
417#if LIBHEIF_HAVE_VERSION(1, 14, 1)
418 nclxDescription.set_color_primaries(heif_color_primaries_ITU_R_BT_2020_2_and_2100_0);
420 nclxDescription.set_color_primaties(heif_color_primaries_ITU_R_BT_2020_2_and_2100_0);
429 errFile <<
"Attempt to export a file with unsupported primaries" << primaries;
432#if LIBHEIF_HAVE_VERSION(1, 14, 1)
433 nclxDescription.set_color_primaries(heif_color_primaries(primaries));
435 nclxDescription.set_color_primaties(heif_color_primaries(primaries));
440 nclxDescription.set_transfer_characteristics(heif_transfer_characteristic_ITU_R_BT_2100_0_PQ);
442 nclxDescription.set_transfer_characteristics(heif_transfer_characteristic_ITU_R_BT_2100_0_HLG);
444 nclxDescription.set_transfer_characteristics(heif_transfer_characteristic_SMPTE_ST_428_1);
447 img.set_nclx_color_profile(nclxDescription);
453 heif::Context::EncodingOptions options;
458 options.macOS_compatibility_workaround_no_nclx_profile =
false;
461 heif::ImageHandle handle = ctx.encode_image(img,
encoder, options);
469 QScopedPointer<KisMetaData::Store> metaDataStore;
477 if (!metaDataStore->empty()) {
482 QByteArray data = buffer.data();
485 if (data.size() > 4) {
486 ctx.add_exif_metadata(handle, data.constData(), data.size());
493 QByteArray data = buffer.data();
496 if (data.size() > 0) {
497 ctx.add_XMP_metadata(handle, data.constData(), data.size());
508 }
catch (Error &err) {
537 chromaOptions <<
"420" <<
"422" <<
"444";
538 cmbChroma->addItems(chromaOptions);
539 cmbChroma->setItemData(0, i18nc(
"@tooltip",
"The brightness of the image will be at full resolution, while the colorfulness will be halved in both dimensions."), Qt::ToolTipRole);
540 cmbChroma->setItemData(1, i18nc(
"@tooltip",
"The brightness of the image will be at full resolution, while the colorfulness will be halved horizontally."), Qt::ToolTipRole);
541 cmbChroma->setItemData(2, i18nc(
"@tooltip",
"Both brightness and colorfulness of the image will be at full resolution."), Qt::ToolTipRole);
542 chkLossless->setChecked(cfg->getBool(
"lossless",
true));
543 sliderQuality->setValue(qreal(cfg->getInt(
"quality", 50)));
544 cmbChroma->setCurrentIndex(chromaOptions.indexOf(cfg->getString(
"chroma",
"444")));
555 QStringList conversionOptionsList = { i18nc(
"Color space name",
"Rec 2100 PQ"), i18nc(
"Color space name",
"Rec 2100 HLG")};
556 QStringList toolTipList = {i18nc(
"@tooltip",
"The image will be converted to Rec 2020 linear first, and then encoded with a perceptual quantizer curve"
557 " (also known as SMPTE 2048 curve). Recommended for HDR images where the absolute brightness is important."),
558 i18nc(
"@tooltip",
"The image will be converted to Rec 2020 linear first, and then encoded with a Hybrid Log Gamma curve."
559 " Recommended for HDR images where the display may not understand HDR.")};
560 QStringList conversionOptionName = {
"Rec2100PQ",
"Rec2100HLG"};
564 conversionOptionsList << i18nc(
"Color space option plus transfer function name",
"Keep colorants, encode PQ");
565 toolTipList << i18nc(
"@tooltip",
"The image will be linearized first, and then encoded with a perceptual quantizer curve"
566 " (also known as the SMPTE 2048 curve). Recommended for images where the absolute brightness is important.");
567 conversionOptionName <<
"ApplyPQ";
569 conversionOptionsList << i18nc(
"Color space option plus transfer function name",
"Keep colorants, encode HLG");
570 toolTipList << i18nc(
"@tooltip",
"The image will be linearized first, and then encoded with a Hybrid Log Gamma curve."
571 " Recommended for images intended for screens which cannot understand PQ");
572 conversionOptionName <<
"ApplyHLG";
574 conversionOptionsList << i18nc(
"Color space option plus transfer function name",
"Keep colorants, encode SMPTE ST 428");
575 toolTipList << i18nc(
"@tooltip",
"The image will be linearized first, and then encoded with SMPTE ST 428."
576 " Krita always opens images like these as linear floating point, this option is there to reverse that");
577 conversionOptionName <<
"ApplySMPTE428";
580 conversionOptionsList << i18nc(
"Color space option",
"No changes, clip");
581 toolTipList << i18nc(
"@tooltip",
"The image will be converted plainly to 12bit integer, and values that are out of bounds are clipped, the icc profile will be embedded.");
582 conversionOptionName <<
"KeepSame";
584 cmbConversionPolicy->addItems(conversionOptionsList);
585 for (
int i=0; i< toolTipList.size(); i++) {
586 cmbConversionPolicy->setItemData(i, toolTipList.at(i), Qt::ToolTipRole);
587 cmbConversionPolicy->setItemData(i, conversionOptionName.at(i), Qt::UserRole+1);
590 cfg->getString(
"floatingPointConversionOption",
"KeepSame");
591 if (conversionOptionName.contains(optionName)) {
592 cmbConversionPolicy->setCurrentIndex(
593 conversionOptionName.indexOf(optionName));
595 chkHLGOOTF->setChecked(cfg->getBool(
"removeHGLOOTF",
true));
596 spnNits->setValue(cfg->getDouble(
"HLGnominalPeak", 1000.0));
597 spnGamma->setValue(cfg->getDouble(
"HLGgamma", 1.2));
599 lossySettings->setEnabled(!chkLossless->isChecked());