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;
383 int width = handle.get_width();
385 int height = handle.get_height();
389 KisImageSP image =
new KisImage(document->createUndoStore(), width, height, colorSpace,
394 if (luma != 8 && luma != 10 && luma != 12) {
395 dbgFile <<
"unknown bitdepth" << luma;
398 if (heifChroma == heif_chroma_monochrome) {
399 dbgFile <<
"monochrome heif file, bits:" << luma;
400 HeifStrideType strideG = 0;
401 HeifStrideType strideA = 0;
402 const uint8_t *imgG = heifGetPlaneMethod(heifimage, heif_channel_Y, &strideG);
403 const uint8_t *imgA =
404 heifGetPlaneMethod(heifimage, heif_channel_Alpha, &strideA);
405 const int width = heifimage.get_width(heif_channel_Y);
406 const int height = heifimage.get_height(heif_channel_Y);
419 }
else if (heifChroma == heif_chroma_444) {
420 dbgFile <<
"planar heif file, bits:" << luma;
422 HeifStrideType strideR = 0;
423 HeifStrideType strideG = 0;
424 HeifStrideType strideB = 0;
425 HeifStrideType strideA = 0;
426 const uint8_t* imgR = heifGetPlaneMethod(heifimage, heif_channel_R, &strideR);
427 const uint8_t* imgG = heifGetPlaneMethod(heifimage, heif_channel_G, &strideG);
428 const uint8_t* imgB = heifGetPlaneMethod(heifimage, heif_channel_B, &strideB);
429 const uint8_t *imgA =
430 heifGetPlaneMethod(heifimage, heif_channel_Alpha, &strideA);
451 }
else if (heifChroma == heif_chroma_interleaved_RGB || heifChroma == heif_chroma_interleaved_RGBA) {
452 HeifStrideType stride = 0;
453 dbgFile <<
"interleaved SDR heif file, bits:" << luma;
455 const uint8_t *img = heifGetPlaneMethod(heifimage, heif_channel_interleaved, &stride);
456 width = heifimage.get_width(heif_channel_interleaved);
457 height = heifimage.get_height(heif_channel_interleaved);
473 }
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) {
474 HeifStrideType stride = 0;
475 dbgFile <<
"interleaved HDR heif file, bits:" << luma;
478 heifGetPlaneMethod(heifimage, heif_channel_interleaved, &stride);
497 image->
cropImage(QRect(0, 0, width, height));
501 std::vector<heif_item_id> metadata_IDs = handle.get_list_of_metadata_block_IDs();
503 for (heif_item_id
id : metadata_IDs) {
505 if (handle.get_metadata_type(
id) ==
"Exif") {
508 std::vector<uint8_t> exif_data = handle.get_metadata(
id);
510 if (exif_data.size()>4) {
511 size_t skip = ((quint32(exif_data[0]) << 24U)
512 | (quint32(exif_data[1])) << 16U
513 | (quint32(exif_data[2]) << 8U) | exif_data[3])
516 if (exif_data.size() > skip) {
522 reinterpret_cast<char *
>(exif_data.data() + skip),
523 static_cast<int>(exif_data.size() - skip));
530 if (handle.get_metadata_type(
id) ==
"mime" &&
531 handle.get_metadata_content_type(
id) ==
"application/rdf+xml") {
534 std::vector<uint8_t> xmp_data = handle.get_metadata(
id);
538 QByteArray ba(
reinterpret_cast<char *
>(xmp_data.data()),
static_cast<int>(xmp_data.size()));
544 document->setCurrentImage(image);
546 }
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)