212#if LIBHEIF_HAVE_VERSION(1, 13, 0)
216#if LIBHEIF_HAVE_VERSION(1, 20, 2)
217 using HeifStrideType = size_t;
218 auto heifGetPlaneMethod = std::mem_fn(qNonConstOverload<heif_channel, HeifStrideType*>(&heif::Image::get_plane2));
219#elif LIBHEIF_HAVE_VERSION(1, 20, 0)
220 using HeifStrideType = size_t;
221 auto heifGetPlaneMethod = std::mem_fn(qNonConstOverload<heif_channel, HeifStrideType*>(&heif::Image::get_plane));
223 using HeifStrideType = int;
224 auto heifGetPlaneMethod = std::mem_fn(qNonConstOverload<heif_channel, HeifStrideType*>(&heif::Image::get_plane));
232 ctx.read_from_reader(reader);
236 heif::ImageHandle handle = ctx.get_primary_image_handle();
238 heif_color_profile_type profileType = heif_image_handle_get_color_profile_type(handle.get_raw_image_handle());
241 heif::Image heifimage = handle.decode_image(heif_colorspace_undefined, heif_chroma_undefined);
242 heif_colorspace heifModel = heifimage.get_colorspace();
243 heif_chroma heifChroma = heifimage.get_chroma_format();
244 int luma = handle.get_luma_bits_per_pixel();
245 bool hasAlpha = handle.has_alpha_channel();
247 dbgFile <<
"loading heif" << heifModel << heifChroma << luma;
250 bool applyOOTF =
true;
251 float displayGamma = 1.2f;
252 float displayNits = 1000.0;
254 struct heif_error err {
265 if (profileType == heif_color_profile_type_prof || profileType == heif_color_profile_type_rICC) {
266 dbgFile <<
"profile type is icc profile";
271 int rawProfileSize = (int) heif_image_handle_get_raw_color_profile_size(handle.get_raw_image_handle());
272 if (rawProfileSize > 0) {
273 QByteArray ba(rawProfileSize, 0);
274 err = heif_image_handle_get_raw_color_profile(handle.get_raw_image_handle(), ba.data());
276 dbgFile <<
"icc profile loading failed:" << err.message;
283 dbgFile <<
"icc profile is empty";
285 }
else if (profileType == heif_color_profile_type_nclx) {
286 dbgFile <<
"profile type is nclx coding independent code points";
291 struct heif_color_profile_nclx *nclx =
nullptr;
292 err = heif_image_handle_get_nclx_color_profile(handle.get_raw_image_handle(), &nclx);
293 if (err.code || !nclx) {
294 dbgFile <<
"nclx profile loading failed" << err.message;
298 if (nclx->transfer_characteristics == heif_transfer_characteristic_ITU_R_BT_2100_0_PQ) {
299 dbgFile <<
"linearizing from PQ";
303 if (nclx->transfer_characteristics == heif_transfer_characteristic_ITU_R_BT_2100_0_HLG) {
304 dbgFile <<
"linearizing from HLG";
305 if (!document->fileBatchMode()) {
309 displayGamma = dlg.
gamma();
315 if (nclx->transfer_characteristics == heif_transfer_characteristic_SMPTE_ST_428_1) {
316 dbgFile <<
"linearizing from SMPTE 428";
321 if (nclx->transfer_characteristics == heif_transfer_characteristic_IEC_61966_2_4 ||
322 nclx->transfer_characteristics == heif_transfer_characteristic_ITU_R_BT_1361) {
331 static_cast<double>(nclx->color_primary_white_x),
332 static_cast<double>(nclx->color_primary_white_y),
333 static_cast<double>(nclx->color_primary_red_x),
334 static_cast<double>(nclx->color_primary_red_y),
335 static_cast<double>(nclx->color_primary_green_x),
336 static_cast<double>(nclx->color_primary_green_y),
337 static_cast<double>(nclx->color_primary_blue_x),
338 static_cast<double>(nclx->color_primary_blue_y)};
344 transferCharacteristic);
350 heif_nclx_color_profile_free(nclx);
351 dbgFile <<
"nclx profile found" << profile->
name();
361 heifimage = handle.decode_image(heif_colorspace_YCbCr, heif_chroma_monochrome);
364 heifChroma = heif_chroma_monochrome;
365 }
else if (heifModel == heif_colorspace_YCbCr) {
367 heifimage = handle.decode_image(heif_colorspace_RGB, heif_chroma_undefined);
369 heifModel = heifimage.get_colorspace();
370 heifChroma = heifimage.get_chroma_format();
388 int width = handle.get_width();
390 int height = handle.get_height();
394 KisImageSP image =
new KisImage(document->createUndoStore(), width, height, colorSpace,
399 if (luma != 8 && luma != 10 && luma != 12) {
400 dbgFile <<
"unknown bitdepth" << luma;
403 if (heifChroma == heif_chroma_monochrome) {
404 dbgFile <<
"monochrome heif file, bits:" << luma;
405 HeifStrideType strideG = 0;
406 HeifStrideType strideA = 0;
407 const uint8_t *imgG = heifGetPlaneMethod(heifimage, heif_channel_Y, &strideG);
408 const uint8_t *imgA =
409 heifGetPlaneMethod(heifimage, heif_channel_Alpha, &strideA);
410 const int width = heifimage.get_width(heif_channel_Y);
411 const int height = heifimage.get_height(heif_channel_Y);
424 }
else if (heifChroma == heif_chroma_444) {
425 dbgFile <<
"planar heif file, bits:" << luma;
427 HeifStrideType strideR = 0;
428 HeifStrideType strideG = 0;
429 HeifStrideType strideB = 0;
430 HeifStrideType strideA = 0;
431 const uint8_t* imgR = heifGetPlaneMethod(heifimage, heif_channel_R, &strideR);
432 const uint8_t* imgG = heifGetPlaneMethod(heifimage, heif_channel_G, &strideG);
433 const uint8_t* imgB = heifGetPlaneMethod(heifimage, heif_channel_B, &strideB);
434 const uint8_t *imgA =
435 heifGetPlaneMethod(heifimage, heif_channel_Alpha, &strideA);
456 }
else if (heifChroma == heif_chroma_interleaved_RGB || heifChroma == heif_chroma_interleaved_RGBA) {
457 HeifStrideType stride = 0;
458 dbgFile <<
"interleaved SDR heif file, bits:" << luma;
460 const uint8_t *img = heifGetPlaneMethod(heifimage, heif_channel_interleaved, &stride);
461 width = heifimage.get_width(heif_channel_interleaved);
462 height = heifimage.get_height(heif_channel_interleaved);
478 }
else if (heifChroma == heif_chroma_interleaved_RRGGBB_LE || heifChroma == heif_chroma_interleaved_RRGGBBAA_LE || heifChroma == heif_chroma_interleaved_RRGGBB_BE || heifChroma == heif_chroma_interleaved_RRGGBB_BE) {
479 HeifStrideType stride = 0;
480 dbgFile <<
"interleaved HDR heif file, bits:" << luma;
483 heifGetPlaneMethod(heifimage, heif_channel_interleaved, &stride);
502 image->
cropImage(QRect(0, 0, width, height));
506 std::vector<heif_item_id> metadata_IDs = handle.get_list_of_metadata_block_IDs();
508 for (heif_item_id
id : metadata_IDs) {
510 if (handle.get_metadata_type(
id) ==
"Exif") {
513 std::vector<uint8_t> exif_data = handle.get_metadata(
id);
515 if (exif_data.size()>4) {
516 size_t skip = ((quint32(exif_data[0]) << 24U)
517 | (quint32(exif_data[1])) << 16U
518 | (quint32(exif_data[2]) << 8U) | exif_data[3])
521 if (exif_data.size() > skip) {
527 reinterpret_cast<char *
>(exif_data.data() + skip),
528 static_cast<int>(exif_data.size() - skip));
535 if (handle.get_metadata_type(
id) ==
"mime" &&
536 handle.get_metadata_content_type(
id) ==
"application/rdf+xml") {
539 std::vector<uint8_t> xmp_data = handle.get_metadata(
id);
543 QByteArray ba(
reinterpret_cast<char *
>(xmp_data.data()),
static_cast<int>(xmp_data.size()));
549 document->setCurrentImage(image);
551 }
catch (Error &err) {
auto readPlanarLayer(const int luma, LinearizePolicy policy, bool applyOOTF, bool hasAlpha, const int width, const int height, const uint8_t *imgR, const int strideR, const uint8_t *imgG, const int strideG, const uint8_t *imgB, const int strideB, const uint8_t *imgA, const int strideA, KisHLineIteratorSP it, float displayGamma, float displayNits, const KoColorSpace *colorSpace)