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
366 }
367
368
369 if (!profile) {
374 } else {
378 }
379 }
380
382
383 int width = handle.get_width();
384
385 int height = handle.get_height();
386
387
388
389 KisImageSP image =
new KisImage(document->createUndoStore(), width, height, colorSpace,
390 "HEIF image");
391
393
394 if (luma != 8 && luma != 10 && luma != 12) {
395 dbgFile <<
"unknown bitdepth" << luma;
396 }
397
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);
409
411 hasAlpha,
412 width,
413 height,
414 it,
415 imgG,
416 imgA,
417 strideG,
418 strideA);
419 } else if (heifChroma == heif_chroma_444) {
420 dbgFile <<
"planar heif file, bits:" << luma;
421
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);
432
434 linearizePolicy,
435 applyOOTF,
436 hasAlpha,
437 width,
438 height,
439 imgR,
440 strideR,
441 imgG,
442 strideG,
443 imgB,
444 strideB,
445 imgA,
446 strideA,
447 it,
448 displayGamma,
449 displayNits,
450 colorSpace);
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;
454
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);
460
462 applyOOTF,
463 hasAlpha,
464 width,
465 height,
466 img,
467 stride,
468 it,
469 displayGamma,
470 displayNits,
471 colorSpace);
472
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;
476
477 const uint8_t *img =
478 heifGetPlaneMethod(heifimage, heif_channel_interleaved, &stride);
481
483 linearizePolicy,
484 applyOOTF,
485 hasAlpha,
486 width,
487 height,
488 img,
489 stride,
490 it,
491 displayGamma,
492 displayNits,
493 colorSpace);
494 }
495
497 image->
cropImage(QRect(0, 0, width, height));
498
499
500
501 std::vector<heif_item_id> metadata_IDs = handle.get_list_of_metadata_block_IDs();
502
503 for (heif_item_id id : metadata_IDs) {
504
505 if (handle.get_metadata_type(id) == "Exif") {
506
507
508 std::vector<uint8_t> exif_data = handle.get_metadata(id);
509
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])
514 + 4u;
515
516 if (exif_data.size() > skip) {
519
520
521 QByteArray ba(
522 reinterpret_cast<char *>(exif_data.data() + skip),
523 static_cast<int>(exif_data.size() - skip));
524 QBuffer buf(&ba);
526 }
527 }
528 }
529
530 if (handle.get_metadata_type(id) == "mime" &&
531 handle.get_metadata_content_type(id) == "application/rdf+xml") {
532
533
534 std::vector<uint8_t> xmp_data = handle.get_metadata(id);
536
537
538 QByteArray ba(reinterpret_cast<char *>(xmp_data.data()), static_cast<int>(xmp_data.size()));
539 QBuffer buf(&ba);
541 }
542 }
543
544 document->setCurrentImage(image);
546 } catch (Error &err) {
548 }
549}
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)