213#if LIBHEIF_HAVE_VERSION(1, 13, 0)
217#if LIBHEIF_HAVE_VERSION(1, 20, 2)
218 using HeifStrideType = size_t;
219 auto heifGetPlaneMethod = std::mem_fn(qNonConstOverload<heif_channel, HeifStrideType*>(&heif::Image::get_plane2));
220#elif LIBHEIF_HAVE_VERSION(1, 20, 0)
221 using HeifStrideType = size_t;
222 auto heifGetPlaneMethod = std::mem_fn(qNonConstOverload<heif_channel, HeifStrideType*>(&heif::Image::get_plane));
224 using HeifStrideType = int;
225 auto heifGetPlaneMethod = std::mem_fn(qNonConstOverload<heif_channel, HeifStrideType*>(&heif::Image::get_plane));
233 ctx.read_from_reader(reader);
237 heif::ImageHandle handle = ctx.get_primary_image_handle();
239 heif_color_profile_type profileType = heif_image_handle_get_color_profile_type(handle.get_raw_image_handle());
242 heif::Image heifimage = handle.decode_image(heif_colorspace_undefined, heif_chroma_undefined);
243 heif_colorspace heifModel = heifimage.get_colorspace();
244 heif_chroma heifChroma = heifimage.get_chroma_format();
245 int luma = handle.get_luma_bits_per_pixel();
246 bool hasAlpha = handle.has_alpha_channel();
248 dbgFile <<
"loading heif" << heifModel << heifChroma << luma;
251 bool applyOOTF =
true;
252 float displayGamma = 1.2f;
253 float displayNits = 1000.0;
255 struct heif_error err {
266 if (profileType == heif_color_profile_type_prof || profileType == heif_color_profile_type_rICC) {
267 dbgFile <<
"profile type is icc profile";
272 int rawProfileSize = (int) heif_image_handle_get_raw_color_profile_size(handle.get_raw_image_handle());
273 if (rawProfileSize > 0) {
274 QByteArray ba(rawProfileSize, 0);
275 err = heif_image_handle_get_raw_color_profile(handle.get_raw_image_handle(), ba.data());
277 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) {
327 query.
whitePoint = {
static_cast<double>(nclx->color_primary_white_x),
328 static_cast<double>(nclx->color_primary_white_y)};
333 return {{
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)}};
348 heif_nclx_color_profile_free(nclx);
349 dbgFile <<
"nclx profile found" << profile->
name();
359 heifimage = handle.decode_image(heif_colorspace_YCbCr, heif_chroma_monochrome);
362 heifChroma = heif_chroma_monochrome;
363 }
else if (heifModel == heif_colorspace_YCbCr) {
365 heifimage = handle.decode_image(heif_colorspace_RGB, heif_chroma_444);
367 heifModel = heifimage.get_colorspace();
368 heifChroma = heifimage.get_chroma_format();
385 int width = handle.get_width();
387 int height = handle.get_height();
391 KisImageSP image =
new KisImage(document->createUndoStore(), width, height, colorSpace,
396 if (luma != 8 && luma != 10 && luma != 12) {
397 dbgFile <<
"unknown bitdepth" << luma;
400 if (heifChroma == heif_chroma_monochrome) {
401 dbgFile <<
"monochrome heif file, bits:" << luma;
402 HeifStrideType strideG = 0;
403 HeifStrideType strideA = 0;
404 const uint8_t *imgG = heifGetPlaneMethod(heifimage, heif_channel_Y, &strideG);
405 const uint8_t *imgA =
406 heifGetPlaneMethod(heifimage, heif_channel_Alpha, &strideA);
407 const int width = heifimage.get_width(heif_channel_Y);
408 const int height = heifimage.get_height(heif_channel_Y);
421 }
else if (heifChroma == heif_chroma_444) {
422 dbgFile <<
"planar heif file, bits:" << luma;
424 HeifStrideType strideR = 0;
425 HeifStrideType strideG = 0;
426 HeifStrideType strideB = 0;
427 HeifStrideType strideA = 0;
428 const uint8_t* imgR = heifGetPlaneMethod(heifimage, heif_channel_R, &strideR);
429 const uint8_t* imgG = heifGetPlaneMethod(heifimage, heif_channel_G, &strideG);
430 const uint8_t* imgB = heifGetPlaneMethod(heifimage, heif_channel_B, &strideB);
431 const uint8_t *imgA =
432 heifGetPlaneMethod(heifimage, heif_channel_Alpha, &strideA);
453 }
else if (heifChroma == heif_chroma_interleaved_RGB || heifChroma == heif_chroma_interleaved_RGBA) {
454 HeifStrideType stride = 0;
455 dbgFile <<
"interleaved SDR heif file, bits:" << luma;
457 const uint8_t *img = heifGetPlaneMethod(heifimage, heif_channel_interleaved, &stride);
458 width = heifimage.get_width(heif_channel_interleaved);
459 height = heifimage.get_height(heif_channel_interleaved);
475 }
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) {
476 HeifStrideType stride = 0;
477 dbgFile <<
"interleaved HDR heif file, bits:" << luma;
480 heifGetPlaneMethod(heifimage, heif_channel_interleaved, &stride);
499 image->
cropImage(QRect(0, 0, width, height));
503 std::vector<heif_item_id> metadata_IDs = handle.get_list_of_metadata_block_IDs();
505 for (heif_item_id
id : metadata_IDs) {
507 if (handle.get_metadata_type(
id) ==
"Exif") {
510 std::vector<uint8_t> exif_data = handle.get_metadata(
id);
512 if (exif_data.size()>4) {
513 size_t skip = ((quint32(exif_data[0]) << 24U)
514 | (quint32(exif_data[1])) << 16U
515 | (quint32(exif_data[2]) << 8U) | exif_data[3])
518 if (exif_data.size() > skip) {
524 reinterpret_cast<char *
>(exif_data.data() + skip),
525 static_cast<int>(exif_data.size() - skip));
532 if (handle.get_metadata_type(
id) ==
"mime" &&
533 handle.get_metadata_content_type(
id) ==
"application/rdf+xml") {
536 std::vector<uint8_t> xmp_data = handle.get_metadata(
id);
540 QByteArray ba(
reinterpret_cast<char *
>(xmp_data.data()),
static_cast<int>(xmp_data.size()));
546 document->setCurrentImage(image);
548 }
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)