136#if LIBHEIF_HAVE_VERSION(1, 13, 0)
140#if LIBHEIF_HAVE_VERSION(1, 20, 2)
141 using HeifStrideType = size_t;
142 auto heifGetPlaneMethod = std::mem_fn(qNonConstOverload<heif_channel, HeifStrideType*>(&heif::Image::get_plane2));
143#elif LIBHEIF_HAVE_VERSION(1, 20, 0)
144 using HeifStrideType = size_t;
145 auto heifGetPlaneMethod = std::mem_fn(qNonConstOverload<heif_channel, HeifStrideType*>(&heif::Image::get_plane));
147 using HeifStrideType = int;
148 auto heifGetPlaneMethod = std::mem_fn(qNonConstOverload<heif_channel, HeifStrideType*>(&heif::Image::get_plane));
177 bool convertToRec2020 =
false;
180 QString conversionOption =
181 (configuration->getString(
"floatingPointConversionOption",
183 if (conversionOption ==
"Rec2100PQ") {
184 convertToRec2020 =
true;
186 }
else if (conversionOption ==
"Rec2100HLG") {
187 convertToRec2020 =
true;
189 }
else if (conversionOption ==
"ApplyPQ") {
191 }
else if (conversionOption ==
"ApplyHLG") {
193 }
else if (conversionOption ==
"ApplySMPTE428") {
211 int quality = configuration->getInt(
"quality", 50);
212 bool lossless = configuration->getBool(
"lossless",
false);
214 float hlgGamma = configuration->getFloat(
"HLGgamma", 1.2f);
215 float hlgNominalPeak = configuration->getFloat(
"HLGnominalPeak", 1000.0f);
216 bool removeHGLOOTF = configuration->getBool(
"removeHGLOOTF",
true);
225 heif::Encoder
encoder(heif_compression_HEVC);
229 encoder = heif::Encoder(heif_compression_AV1);
233 encoder.set_lossy_quality(quality);
236 encoder.set_lossy_quality(100);
238 encoder.set_lossless(lossless);
240 encoder.set_parameter(
"chroma", configuration->getString(
"chroma",
"444").toStdString());
245 int width = image->
width();
246 int height = image->
height();
250 heif_chroma chroma = hasAlpha? heif_chroma_interleaved_RRGGBBAA_LE: heif_chroma_interleaved_RRGGBB_LE;
251 if (QSysInfo::ByteOrder == QSysInfo::BigEndian) {
252 chroma = hasAlpha? heif_chroma_interleaved_RRGGBBAA_BE: heif_chroma_interleaved_RRGGBB_BE;
259 dbgFile <<
"saving as 8bit rgba";
260 img.create(width,height, heif_colorspace_RGB, heif_chroma_444);
261 img.add_plane(heif_channel_R, width,height, 8);
262 img.add_plane(heif_channel_G, width,height, 8);
263 img.add_plane(heif_channel_B, width,height, 8);
265 HeifStrideType strideR = 0;
266 HeifStrideType strideG = 0;
267 HeifStrideType strideB = 0;
268 HeifStrideType strideA = 0;
270 uint8_t *ptrR = heifGetPlaneMethod(img, heif_channel_R, &strideR);
271 uint8_t *ptrG = heifGetPlaneMethod(img, heif_channel_G, &strideG);
272 uint8_t *ptrB = heifGetPlaneMethod(img, heif_channel_B, &strideB);
274 uint8_t *ptrA = [&]() -> uint8_t * {
276 img.add_plane(heif_channel_Alpha, width, height, 8);
277 return heifGetPlaneMethod(img, heif_channel_Alpha, &strideA);
300 dbgFile <<
"Saving as 12bit rgba";
301 img.create(width, height, heif_colorspace_RGB, chroma);
302 img.add_plane(heif_channel_interleaved, width, height, 12);
304 HeifStrideType stride = 0;
306 uint8_t *ptr = heifGetPlaneMethod(img, heif_channel_interleaved, &stride);
340 dbgFile <<
"Saving as 8 bit monochrome.";
341 img.create(width, height, heif_colorspace_monochrome, heif_chroma_monochrome);
343 img.add_plane(heif_channel_Y, width, height, 8);
345 HeifStrideType strideG = 0;
346 HeifStrideType strideA = 0;
348 uint8_t *ptrG = heifGetPlaneMethod(img, heif_channel_Y, &strideG);
349 uint8_t *ptrA = [&]() -> uint8_t * {
351 img.add_plane(heif_channel_Alpha, width, height, 8);
352 return heifGetPlaneMethod(img, heif_channel_Alpha, &strideA);
373 dbgFile <<
"Saving as 12 bit monochrome";
374 img.create(width, height, heif_colorspace_monochrome, heif_chroma_monochrome);
376 img.add_plane(heif_channel_Y, width, height, 12);
378 HeifStrideType strideG = 0;
379 HeifStrideType strideA = 0;
381 uint8_t *ptrG = heifGetPlaneMethod(img, heif_channel_Y, &strideG);
382 uint8_t *ptrA = [&]() -> uint8_t * {
384 img.add_plane(heif_channel_Alpha, width, height, 12);
385 return heifGetPlaneMethod(img, heif_channel_Alpha, &strideA);
411 std::vector<uint8_t> rawProfile(rawProfileBA.begin(), rawProfileBA.end());
412 img.set_raw_color_profile(heif_color_profile_type_prof, rawProfile);
414 heif::ColorProfile_nclx nclxDescription;
415 nclxDescription.set_full_range_flag(
true);
416 nclxDescription.set_matrix_coefficients(heif_matrix_coefficients_RGB_GBR);
417 if (convertToRec2020) {
418#if LIBHEIF_HAVE_VERSION(1, 14, 1)
419 nclxDescription.set_color_primaries(heif_color_primaries_ITU_R_BT_2020_2_and_2100_0);
421 nclxDescription.set_color_primaties(heif_color_primaries_ITU_R_BT_2020_2_and_2100_0);
430 errFile <<
"Attempt to export a file with unsupported primaries" << primaries;
433#if LIBHEIF_HAVE_VERSION(1, 14, 1)
434 nclxDescription.set_color_primaries(heif_color_primaries(primaries));
436 nclxDescription.set_color_primaties(heif_color_primaries(primaries));
441 nclxDescription.set_transfer_characteristics(heif_transfer_characteristic_ITU_R_BT_2100_0_PQ);
443 nclxDescription.set_transfer_characteristics(heif_transfer_characteristic_ITU_R_BT_2100_0_HLG);
445 nclxDescription.set_transfer_characteristics(heif_transfer_characteristic_SMPTE_ST_428_1);
448 img.set_nclx_color_profile(nclxDescription);
454 heif::Context::EncodingOptions options;
459 options.macOS_compatibility_workaround_no_nclx_profile =
false;
462 heif::ImageHandle handle = ctx.encode_image(img,
encoder, options);
470 QScopedPointer<KisMetaData::Store> metaDataStore;
478 if (!metaDataStore->empty()) {
483 QByteArray data = buffer.data();
486 if (data.size() > 4) {
487 ctx.add_exif_metadata(handle, data.constData(), data.size());
494 QByteArray data = buffer.data();
497 if (data.size() > 0) {
498 ctx.add_XMP_metadata(handle, data.constData(), data.size());
509 }
catch (Error &err) {
538 chromaOptions <<
"420" <<
"422" <<
"444";
539 cmbChroma->addItems(chromaOptions);
540 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);
541 cmbChroma->setItemData(1, i18nc(
"@tooltip",
"The brightness of the image will be at full resolution, while the colorfulness will be halved horizontally."), Qt::ToolTipRole);
542 cmbChroma->setItemData(2, i18nc(
"@tooltip",
"Both brightness and colorfulness of the image will be at full resolution."), Qt::ToolTipRole);
543 chkLossless->setChecked(cfg->getBool(
"lossless",
true));
544 sliderQuality->setValue(qreal(cfg->getInt(
"quality", 50)));
545 cmbChroma->setCurrentIndex(chromaOptions.indexOf(cfg->getString(
"chroma",
"444")));
556 QStringList conversionOptionsList = { i18nc(
"Color space name",
"Rec 2100 PQ"), i18nc(
"Color space name",
"Rec 2100 HLG")};
557 QStringList toolTipList = {i18nc(
"@tooltip",
"The image will be converted to Rec 2020 linear first, and then encoded with a perceptual quantizer curve"
558 " (also known as SMPTE 2048 curve). Recommended for HDR images where the absolute brightness is important."),
559 i18nc(
"@tooltip",
"The image will be converted to Rec 2020 linear first, and then encoded with a Hybrid Log Gamma curve."
560 " Recommended for HDR images where the display may not understand HDR.")};
561 QStringList conversionOptionName = {
"Rec2100PQ",
"Rec2100HLG"};
565 conversionOptionsList << i18nc(
"Color space option plus transfer function name",
"Keep colorants, encode PQ");
566 toolTipList << i18nc(
"@tooltip",
"The image will be linearized first, and then encoded with a perceptual quantizer curve"
567 " (also known as the SMPTE 2048 curve). Recommended for images where the absolute brightness is important.");
568 conversionOptionName <<
"ApplyPQ";
570 conversionOptionsList << i18nc(
"Color space option plus transfer function name",
"Keep colorants, encode HLG");
571 toolTipList << i18nc(
"@tooltip",
"The image will be linearized first, and then encoded with a Hybrid Log Gamma curve."
572 " Recommended for images intended for screens which cannot understand PQ");
573 conversionOptionName <<
"ApplyHLG";
575 conversionOptionsList << i18nc(
"Color space option plus transfer function name",
"Keep colorants, encode SMPTE ST 428");
576 toolTipList << i18nc(
"@tooltip",
"The image will be linearized first, and then encoded with SMPTE ST 428."
577 " Krita always opens images like these as linear floating point, this option is there to reverse that");
578 conversionOptionName <<
"ApplySMPTE428";
581 conversionOptionsList << i18nc(
"Color space option",
"No changes, clip");
582 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.");
583 conversionOptionName <<
"KeepSame";
585 cmbConversionPolicy->addItems(conversionOptionsList);
586 for (
int i=0; i< toolTipList.size(); i++) {
587 cmbConversionPolicy->setItemData(i, toolTipList.at(i), Qt::ToolTipRole);
588 cmbConversionPolicy->setItemData(i, conversionOptionName.at(i), Qt::UserRole+1);
591 cfg->getString(
"floatingPointConversionOption",
"KeepSame");
592 if (conversionOptionName.contains(optionName)) {
593 cmbConversionPolicy->setCurrentIndex(
594 conversionOptionName.indexOf(optionName));
596 chkHLGOOTF->setChecked(cfg->getBool(
"removeHGLOOTF",
true));
597 spnNits->setValue(cfg->getDouble(
"HLGnominalPeak", 1000.0));
598 spnGamma->setValue(cfg->getDouble(
"HLGgamma", 1.2));
600 lossySettings->setEnabled(!chkLossless->isChecked());