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.
211{
212#if LIBHEIF_HAVE_VERSION(1, 13, 0)
213 HeifLock lock;
214#endif
215
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));
222#else
223 using HeifStrideType = int;
224 auto heifGetPlaneMethod = std::mem_fn(qNonConstOverload<heif_channel, HeifStrideType*>(&heif::Image::get_plane));
225#endif
226
227
229
230 try {
231 heif::Context ctx;
232 ctx.read_from_reader(reader);
233
234
235
236 heif::ImageHandle handle = ctx.get_primary_image_handle();
237
238 heif_color_profile_type profileType = heif_image_handle_get_color_profile_type(handle.get_raw_image_handle());
239
240
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();
246
247 dbgFile <<
"loading heif" << heifModel << heifChroma << luma;
248
250 bool applyOOTF = true;
251 float displayGamma = 1.2f;
252 float displayNits = 1000.0;
253
254 struct heif_error err {
255 };
259
260 if (luma > 8) {
262 }
263
264
265 if (profileType == heif_color_profile_type_prof || profileType == heif_color_profile_type_rICC) {
266 dbgFile <<
"profile type is icc profile";
267
268
269
270
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());
275 if (err.code) {
276 dbgFile <<
"icc profile loading failed:" << err.message;
277 } 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
328 return {};
329 } else {
330 return {
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)};
339 }
340 }();
341
343 primaries,
344 transferCharacteristic);
345
348 }
349
350 heif_nclx_color_profile_free(nclx);
351 dbgFile <<
"nclx profile found" << profile->
name();
352 }
353 } else {
355 }
356
357
359
361 heifimage = handle.decode_image(heif_colorspace_YCbCr, heif_chroma_monochrome);
362 }
364 heifChroma = heif_chroma_monochrome;
365 } else if (heifModel == heif_colorspace_YCbCr) {
366
367 heifimage = handle.decode_image(heif_colorspace_RGB, heif_chroma_undefined);
369 heifModel = heifimage.get_colorspace();
370 heifChroma = heifimage.get_chroma_format();
371 }
372
373
374 if (!profile) {
379 } else {
383 }
384 }
385
387
388 int width = handle.get_width();
389
390 int height = handle.get_height();
391
392
393
394 KisImageSP image =
new KisImage(document->createUndoStore(), width, height, colorSpace,
395 "HEIF image");
396
398
399 if (luma != 8 && luma != 10 && luma != 12) {
400 dbgFile <<
"unknown bitdepth" << luma;
401 }
402
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);
414
416 hasAlpha,
417 width,
418 height,
419 it,
420 imgG,
421 imgA,
422 strideG,
423 strideA);
424 } else if (heifChroma == heif_chroma_444) {
425 dbgFile <<
"planar heif file, bits:" << luma;
426
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);
437
439 linearizePolicy,
440 applyOOTF,
441 hasAlpha,
442 width,
443 height,
444 imgR,
445 strideR,
446 imgG,
447 strideG,
448 imgB,
449 strideB,
450 imgA,
451 strideA,
452 it,
453 displayGamma,
454 displayNits,
455 colorSpace);
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;
459
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);
465
467 applyOOTF,
468 hasAlpha,
469 width,
470 height,
471 img,
472 stride,
473 it,
474 displayGamma,
475 displayNits,
476 colorSpace);
477
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;
481
482 const uint8_t *img =
483 heifGetPlaneMethod(heifimage, heif_channel_interleaved, &stride);
486
488 linearizePolicy,
489 applyOOTF,
490 hasAlpha,
491 width,
492 height,
493 img,
494 stride,
495 it,
496 displayGamma,
497 displayNits,
498 colorSpace);
499 }
500
502 image->
cropImage(QRect(0, 0, width, height));
503
504
505
506 std::vector<heif_item_id> metadata_IDs = handle.get_list_of_metadata_block_IDs();
507
508 for (heif_item_id id : metadata_IDs) {
509
510 if (handle.get_metadata_type(id) == "Exif") {
511
512
513 std::vector<uint8_t> exif_data = handle.get_metadata(id);
514
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])
519 + 4u;
520
521 if (exif_data.size() > skip) {
524
525
526 QByteArray ba(
527 reinterpret_cast<char *>(exif_data.data() + skip),
528 static_cast<int>(exif_data.size() - skip));
529 QBuffer buf(&ba);
531 }
532 }
533 }
534
535 if (handle.get_metadata_type(id) == "mime" &&
536 handle.get_metadata_content_type(id) == "application/rdf+xml") {
537
538
539 std::vector<uint8_t> xmp_data = handle.get_metadata(id);
541
542
543 QByteArray ba(reinterpret_cast<char *>(xmp_data.data()), static_cast<int>(xmp_data.size()));
544 QBuffer buf(&ba);
546 }
547 }
548
549 document->setCurrentImage(image);
551 } catch (Error &err) {
553 }
554}
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
virtual QString colorModelID() const
const KoColorProfile * profileByName(const QString &name) const
QString colorSpaceId(const QString &colorModelId, const QString &colorDepthId) const
const KoColorProfile * profileFor(const QVector< double > &colorants, ColorPrimaries colorPrimaries, TransferCharacteristics transferFunction) const
profileFor tries to find the profile that matches these characteristics, if no such profile is found,...
const KoColorSpace * colorSpace(const QString &colorModelId, const QString &colorDepthId, const KoColorProfile *profile)
static KoColorSpaceRegistry * instance()
QString defaultProfileForColorSpace(const QString &colorSpaceId) const
const KoColorProfile * createColorProfile(const QString &colorModelId, const QString &colorDepthId, const QByteArray &rawData)
void addProfile(KoColorProfile *profile)