The filter chain calls this method to perform the actual conversion. The passed mimetypes should be a pair of those you specified in your .desktop file. You have to implement this method to make the filter work.
212{
213#if LIBHEIF_HAVE_VERSION(1, 13, 0)
214 HeifLock lock;
215#endif
216
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));
223#else
224 using HeifStrideType = int;
225 auto heifGetPlaneMethod = std::mem_fn(qNonConstOverload<heif_channel, HeifStrideType*>(&heif::Image::get_plane));
226#endif
227
228
230
231 try {
232 heif::Context ctx;
233 ctx.read_from_reader(reader);
234
235
236
237 heif::ImageHandle handle = ctx.get_primary_image_handle();
238
239 heif_color_profile_type profileType = heif_image_handle_get_color_profile_type(handle.get_raw_image_handle());
240
241
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();
247
248 dbgFile <<
"loading heif" << heifModel << heifChroma << luma;
249
251 bool applyOOTF = true;
252 float displayGamma = 1.2f;
253 float displayNits = 1000.0;
254
255 struct heif_error err {
256 };
260
261 if (luma > 8) {
263 }
264
265
266 if (profileType == heif_color_profile_type_prof || profileType == heif_color_profile_type_rICC) {
267 dbgFile <<
"profile type is icc profile";
268
269
270
271
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());
276 if (err.code) {
277 dbgFile <<
"icc profile loading failed:" << err.message;
278 } else {
281 }
282 } else {
283 dbgFile <<
"icc profile is empty";
284 }
285 } else if (profileType == heif_color_profile_type_nclx) {
286 dbgFile <<
"profile type is nclx coding independent code points";
287
288
289
290
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;
295 } else {
298 if (nclx->transfer_characteristics == heif_transfer_characteristic_ITU_R_BT_2100_0_PQ) {
299 dbgFile <<
"linearizing from PQ";
302 }
303 if (nclx->transfer_characteristics == heif_transfer_characteristic_ITU_R_BT_2100_0_HLG) {
304 dbgFile <<
"linearizing from HLG";
305 if (!document->fileBatchMode()) {
307 dlg.exec();
308 applyOOTF = dlg.applyOOTF();
309 displayGamma = dlg.gamma();
310 displayNits = dlg.nominalPeakBrightness();
311 }
314 }
315 if (nclx->transfer_characteristics == heif_transfer_characteristic_SMPTE_ST_428_1) {
316 dbgFile <<
"linearizing from SMPTE 428";
319 }
320
321 if (nclx->transfer_characteristics == heif_transfer_characteristic_IEC_61966_2_4 ||
322 nclx->transfer_characteristics == heif_transfer_characteristic_ITU_R_BT_1361) {
324 }
325
327 query.whitePoint = {static_cast<double>(nclx->color_primary_white_x),
328 static_cast<double>(nclx->color_primary_white_y)};
331 return {};
332 } else {
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)}};
339 }
340 }();
341
343
346 }
347
348 heif_nclx_color_profile_free(nclx);
349 dbgFile <<
"nclx profile found" << profile->
name();
350 }
351 } else {
353 }
354
355
357
359 heifimage = handle.decode_image(heif_colorspace_YCbCr, heif_chroma_monochrome);
360 }
362 heifChroma = heif_chroma_monochrome;
363 } else if (heifModel == heif_colorspace_YCbCr) {
364
365 heifimage = handle.decode_image(heif_colorspace_RGB, heif_chroma_444);
367 heifModel = heifimage.get_colorspace();
368 heifChroma = heifimage.get_chroma_format();
369 }
370
371
372 if (!profile) {
376 } else {
380 }
381 }
382
384
385 int width = handle.get_width();
386
387 int height = handle.get_height();
388
389
390
391 KisImageSP image =
new KisImage(document->createUndoStore(), width, height, colorSpace,
392 "HEIF image");
393
395
396 if (luma != 8 && luma != 10 && luma != 12) {
397 dbgFile <<
"unknown bitdepth" << luma;
398 }
399
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);
411
413 hasAlpha,
414 width,
415 height,
416 it,
417 imgG,
418 imgA,
419 strideG,
420 strideA);
421 } else if (heifChroma == heif_chroma_444) {
422 dbgFile <<
"planar heif file, bits:" << luma;
423
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);
434
436 linearizePolicy,
437 applyOOTF,
438 hasAlpha,
439 width,
440 height,
441 imgR,
442 strideR,
443 imgG,
444 strideG,
445 imgB,
446 strideB,
447 imgA,
448 strideA,
449 it,
450 displayGamma,
451 displayNits,
452 colorSpace);
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;
456
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);
462
464 applyOOTF,
465 hasAlpha,
466 width,
467 height,
468 img,
469 stride,
470 it,
471 displayGamma,
472 displayNits,
473 colorSpace);
474
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;
478
479 const uint8_t *img =
480 heifGetPlaneMethod(heifimage, heif_channel_interleaved, &stride);
483
485 linearizePolicy,
486 applyOOTF,
487 hasAlpha,
488 width,
489 height,
490 img,
491 stride,
492 it,
493 displayGamma,
494 displayNits,
495 colorSpace);
496 }
497
499 image->
cropImage(QRect(0, 0, width, height));
500
501
502
503 std::vector<heif_item_id> metadata_IDs = handle.get_list_of_metadata_block_IDs();
504
505 for (heif_item_id id : metadata_IDs) {
506
507 if (handle.get_metadata_type(id) == "Exif") {
508
509
510 std::vector<uint8_t> exif_data = handle.get_metadata(id);
511
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])
516 + 4u;
517
518 if (exif_data.size() > skip) {
521
522
523 QByteArray ba(
524 reinterpret_cast<char *>(exif_data.data() + skip),
525 static_cast<int>(exif_data.size() - skip));
526 QBuffer buf(&ba);
528 }
529 }
530 }
531
532 if (handle.get_metadata_type(id) == "mime" &&
533 handle.get_metadata_content_type(id) == "application/rdf+xml") {
534
535
536 std::vector<uint8_t> xmp_data = handle.get_metadata(id);
538
539
540 QByteArray ba(reinterpret_cast<char *>(xmp_data.data()), static_cast<int>(xmp_data.size()));
541 QBuffer buf(&ba);
543 }
544 }
545
546 document->setCurrentImage(image);
548 } catch (Error &err) {
550 }
551}
KisImportExportErrorCode setHeifError(KisDocument *document, heif::Error error)
const KoID Float32BitsColorDepthID("F32", ki18n("32-bit float/channel"))
const KoID GrayAColorModelID("GRAYA", ki18n("Grayscale/Alpha"))
const KoID Integer8BitsColorDepthID("U8", ki18n("8-bit integer/channel"))
const KoID Integer16BitsColorDepthID("U16", ki18n("16-bit integer/channel"))
const KoID RGBAColorModelID("RGBA", ki18n("RGB/Alpha"))
ColorPrimaries
The colorPrimaries enum Enum of colorants, follows ITU H.273 for values 0 to 255, and has extra known...
@ PRIMARIES_ITU_R_BT_709_5
TransferCharacteristics
The transferCharacteristics enum Enum of transfer characteristics, follows ITU H.273 for values 0 to ...
const quint8 OPACITY_OPAQUE_U8
LinearizePolicy
The KoColorTransferFunctions class.
KisGroupLayerSP rootLayer() const
QString nextLayerName(const QString &baseName="") const
void cropImage(const QRect &newRect)
start asynchronous operation on cropping the image
KisHLineIteratorSP createHLineIteratorNG(qint32 x, qint32 y, qint32 w)
const T value(const QString &id) const
auto readPlanarLayer(const int luma, Args &&...args)
auto readInterleavedLayer(const int luma, LinearizePolicy linearizePolicy, bool applyOOTF, const int channels, const int width, const int height, const uint8_t *img, const int stride, KisHLineIteratorSP it, float displayGamma, float displayNits, const KoColorSpace *colorSpace)
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)
auto readInterleavedLayer(LinearizePolicy linearizePolicy, bool applyOOTF, const int channels, const int width, const int height, const uint8_t *img, const int stride, KisHLineIteratorSP it, float displayGamma, float displayNits, const KoColorSpace *colorSpace)
KisMetaData::Store * metaData()
bool addNode(KisNodeSP node, KisNodeSP parent=KisNodeSP(), KisNodeAdditionFlags flags=KisNodeAdditionFlag::None)
KisPaintDeviceSP paintDevice
The KoColorProfileQuery struct.
virtual QString colorModelID() const
const KoColorProfile * profileByName(const QString &name) const
QString colorSpaceId(const QString &colorModelId, const QString &colorDepthId) const
const KoColorSpace * colorSpace(const QString &colorModelId, const QString &colorDepthId, const KoColorProfile *profile)
static KoColorSpaceRegistry * instance()
const KoColorProfile * profileFor(const KoColorProfileQuery &query, const bool generate=true) const
profileFor tries to find the profile that matches these characteristics, if no such profile is found,...
QString defaultProfileForColorSpace(const QString &colorSpaceId) const
const KoColorProfile * createColorProfile(const QString &colorModelId, const QString &colorDepthId, const QByteArray &rawData)