Krita Source Code Documentation
Loading...
Searching...
No Matches
HeifImport Class Reference

#include <HeifImport.h>

+ Inheritance diagram for HeifImport:

Public Member Functions

KisImportExportErrorCode convert (KisDocument *document, QIODevice *io, KisPropertiesConfigurationSP configuration=0) override
 
 HeifImport (QObject *parent, const QVariantList &)
 
bool supportsIO () const override
 Override and return false for the filters that use a library that cannot handle file handles, only file names.
 
 ~HeifImport () override
 
- Public Member Functions inherited from KisImportExportFilter
virtual KisConfigWidgetcreateConfigurationWidget (QWidget *parent, const QByteArray &from="", const QByteArray &to="") const
 createConfigurationWidget creates a widget that can be used to define the settings for a given import/export filter
 
virtual KisPropertiesConfigurationSP defaultConfiguration (const QByteArray &from="", const QByteArray &to="") const
 defaultConfiguration defines the default settings for the given import export filter
 
virtual QMap< QString, KisExportCheckBase * > exportChecks ()
 generate and return the list of capabilities of this export filter. The list
 
virtual bool exportSupportsGuides () const
 exportSupportsGuides Because guides are in the document and not the image, checking for guides cannot be made an exportCheck.
 
KisPropertiesConfigurationSP lastSavedConfiguration (const QByteArray &from="", const QByteArray &to="") const
 lastSavedConfiguration return the last saved configuration for this filter
 
 Private ()
 
void setBatchMode (bool batchmode)
 
void setFilename (const QString &filename)
 
void setImportUserFeedBackInterface (KisImportUserFeedbackInterface *interface)
 
void setMimeType (const QString &mime)
 
void setRealFilename (const QString &filename)
 
void setUpdater (QPointer< KoUpdater > updater)
 
QPointer< KoUpdaterupdater ()
 
virtual QString verify (const QString &fileName) const
 Verify whether the given file is correct and readable.
 
 ~KisImportExportFilter () override
 
 ~Private ()
 

Additional Inherited Members

- Public Attributes inherited from KisImportExportFilter
bool batchmode
 
QMap< QString, KisExportCheckBase * > capabilities
 
QString filename
 
KisImportUserFeedbackInterfaceimportUserFeedBackInterface {nullptr}
 
QByteArray mime
 
QString realFilename
 
QPointer< KoUpdaterupdater
 
- Static Public Attributes inherited from KisImportExportFilter
static const QString CICPPrimariesTag = "CICPCompatiblePrimaries"
 
static const QString CICPTransferCharacteristicsTag = "CICPCompatibleTransferFunction"
 
static const QString ColorDepthIDTag = "ColorDepthID"
 
static const QString ColorModelIDTag = "ColorModelID"
 
static const QString HDRTag = "HDRSupported"
 
static const QString ImageContainsTransparencyTag = "ImageContainsTransparency"
 
static const QString sRGBTag = "sRGB"
 
- Protected Member Functions inherited from KisImportExportFilter
void addCapability (KisExportCheckBase *capability)
 
void addSupportedColorModels (QList< QPair< KoID, KoID > > supportedColorModels, const QString &name, KisExportCheckBase::Level level=KisExportCheckBase::PARTIALLY)
 
bool batchMode () const
 
QString filename () const
 
KisImportUserFeedbackInterfaceimportUserFeedBackInterface () const
 
virtual void initializeCapabilities ()
 
 KisImportExportFilter (QObject *parent=0)
 
QByteArray mimeType () const
 
QString realFilename () const
 
void setProgress (int value)
 
QString verifyZiPBasedFiles (const QString &fileName, const QStringList &filesToCheck) const
 

Detailed Description

Definition at line 17 of file HeifImport.h.

Constructor & Destructor Documentation

◆ HeifImport()

HeifImport::HeifImport ( QObject * parent,
const QVariantList &  )

Definition at line 46 of file HeifImport.cpp.

46 : KisImportExportFilter(parent)
47{
48}
KisImportExportFilter(QObject *parent=0)

◆ ~HeifImport()

HeifImport::~HeifImport ( )
override

Definition at line 50 of file HeifImport.cpp.

51{
52}

Member Function Documentation

◆ convert()

KisImportExportErrorCode HeifImport::convert ( KisDocument * document,
QIODevice * io,
KisPropertiesConfigurationSP configuration = 0 )
overridevirtual

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.

Returns
The error status, see the #ConversionStatus enum. KisImportExportFilter::OK means that everything is alright.

Implements KisImportExportFilter.

Definition at line 211 of file HeifImport.cpp.

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 // Wrap input stream into heif Reader object
229 Reader_QIODevice reader(io);
230
231 try {
232 heif::Context ctx;
233 ctx.read_from_reader(reader);
234
235 // decode primary image
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 };
257 const KoColorProfile *profile = nullptr;
258 KoID colorDepth = Integer8BitsColorDepthID;
259 QString colorModel = RGBAColorModelID.id();
260
261 if (luma > 8) {
262 colorDepth = Integer16BitsColorDepthID;
263 }
264 // First, get the profile, because sometimes the image may be encoded in YCbCr and the embedded icc profile is graya.
265
266 if (profileType == heif_color_profile_type_prof || profileType == heif_color_profile_type_rICC) {
267 dbgFile << "profile type is icc profile";
268 // rICC are 'restricted' icc profiles, and are matrix shaper profiles
269 // that are either RGB or Grayscale, and are of the input or display types.
270 // They are from the JPEG2000 spec.
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 {
279 profile = KoColorSpaceRegistry::instance()->createColorProfile(colorModel, colorDepth.id(), ba);
280 colorModel = profile->colorModelID();
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 // NCLX parameters is a colorspace description used for videofiles.
288 // We generate a color profile for most entries, except that we cannot handle
289 // PQ, HLG or 428 in an icc profile, so we convert those on the fly to linear.
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 {
296 TransferCharacteristics transferCharacteristic = TransferCharacteristics(nclx->transfer_characteristics);
297 ColorPrimaries primaries = ColorPrimaries(nclx->color_primaries);
298 if (nclx->transfer_characteristics == heif_transfer_characteristic_ITU_R_BT_2100_0_PQ) {
299 dbgFile << "linearizing from PQ";
300 linearizePolicy = LinearizePolicy::LinearFromPQ;
301 transferCharacteristic = TRC_LINEAR;
302 }
303 if (nclx->transfer_characteristics == heif_transfer_characteristic_ITU_R_BT_2100_0_HLG) {
304 dbgFile << "linearizing from HLG";
305 if (!document->fileBatchMode()) {
306 KisDlgHLGImport dlg(applyOOTF, displayGamma, displayNits);
307 dlg.exec();
308 applyOOTF = dlg.applyOOTF();
309 displayGamma = dlg.gamma();
310 displayNits = dlg.nominalPeakBrightness();
311 }
312 linearizePolicy = LinearizePolicy::LinearFromHLG;
313 transferCharacteristic = TRC_LINEAR;
314 }
315 if (nclx->transfer_characteristics == heif_transfer_characteristic_SMPTE_ST_428_1) {
316 dbgFile << "linearizing from SMPTE 428";
317 linearizePolicy = LinearizePolicy::LinearFromSMPTE428;
318 transferCharacteristic = TRC_LINEAR;
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) {
323 transferCharacteristic = TRC_ITU_R_BT_709_5;
324 }
325
326 KoColorProfileQuery query(primaries, transferCharacteristic);
327 query.whitePoint = {static_cast<double>(nclx->color_primary_white_x),
328 static_cast<double>(nclx->color_primary_white_y)};
329 query.rgbColorants = [&]() -> QList<KoColorimetryUtils::xy> {
330 if (primaries == PRIMARIES_UNSPECIFIED) {
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
342 profile = KoColorSpaceRegistry::instance()->profileFor(query);
343
344 if (linearizePolicy != LinearizePolicy::KeepTheSame) {
345 colorDepth = Float32BitsColorDepthID;
346 }
347
348 heif_nclx_color_profile_free(nclx);
349 dbgFile << "nclx profile found" << profile->name();
350 }
351 } else {
352 dbgFile << "no profile found";
353 }
354
355 // Now, to figure out the correct chroma and color model.
356 if (heifModel == heif_colorspace_monochrome || colorModel == GrayAColorModelID.id()) {
357 // Grayscale image.
358 if (heifChroma != heif_chroma_monochrome && colorModel == GrayAColorModelID.id()) {
359 heifimage = handle.decode_image(heif_colorspace_YCbCr, heif_chroma_monochrome);
360 }
361 colorModel = GrayAColorModelID.id();
362 heifChroma = heif_chroma_monochrome;
363 } else if (heifModel == heif_colorspace_YCbCr) {
364 // we do not support importing YCrBr spaces directly
365 heifimage = handle.decode_image(heif_colorspace_RGB, heif_chroma_444);
366 colorModel = RGBAColorModelID.id();
367 heifModel = heifimage.get_colorspace();
368 heifChroma = heifimage.get_chroma_format();
369 }
370
371 // Get the default profile if we haven't found one up till now.
372 if (!profile) {
373 if (colorModel == RGBAColorModelID.id()) {
376 } else {
377 const QString colorSpaceId = KoColorSpaceRegistry::instance()->colorSpaceId(colorModel, colorDepth.id());
378 QString profileName = KoColorSpaceRegistry::instance()->defaultProfileForColorSpace(colorSpaceId);
379 profile = KoColorSpaceRegistry::instance()->profileByName(profileName);
380 }
381 }
382
383 const KoColorSpace *colorSpace = KoColorSpaceRegistry::instance()->colorSpace(colorModel, colorDepth.id(), profile);
384
385 int width = handle.get_width();
386
387 int height = handle.get_height();
388
389 // convert HEIF image to Krita KisDocument
390
391 KisImageSP image = new KisImage(document->createUndoStore(), width, height, colorSpace,
392 "HEIF image");
393
394 KisPaintLayerSP layer = new KisPaintLayer(image, image->nextLayerName(), OPACITY_OPAQUE_U8);
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);
410 layer->paintDevice()->createHLineIteratorNG(0, 0, width);
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);
433 KisHLineIteratorSP it = layer->paintDevice()->createHLineIteratorNG(0, 0, width);
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);
461 layer->paintDevice()->createHLineIteratorNG(0, 0, width);
462
463 SDR::readInterleavedLayer(linearizePolicy,
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);
482 layer->paintDevice()->createHLineIteratorNG(0, 0, width);
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
498 image->addNode(layer.data(), image->rootLayer().data());
499 image->cropImage(QRect(0, 0, width, height));
500
501 // --- Iterate through all metadata blocks and extract Exif and XMP metadata ---
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 // Read exif information
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) {
519 KisMetaData::IOBackend *exifIO =
521
522 // Copy the exif data into the byte array
523 QByteArray ba(
524 reinterpret_cast<char *>(exif_data.data() + skip),
525 static_cast<int>(exif_data.size() - skip));
526 QBuffer buf(&ba);
527 exifIO->loadFrom(layer->metaData(), &buf);
528 }
529 }
530 }
531
532 if (handle.get_metadata_type(id) == "mime" &&
533 handle.get_metadata_content_type(id) == "application/rdf+xml") {
534 // Read XMP information
535
536 std::vector<uint8_t> xmp_data = handle.get_metadata(id);
538
539 // Copy the xmp data into the byte array
540 QByteArray ba(reinterpret_cast<char *>(xmp_data.data()), static_cast<int>(xmp_data.size()));
541 QBuffer buf(&ba);
542 xmpIO->loadFrom(layer->metaData(), &buf);
543 }
544 }
545
546 document->setCurrentImage(image);
548 } catch (Error &err) {
549 return setHeifError(document, err);
550 }
551}
KisImportExportErrorCode setHeifError(KisDocument *document, heif::Error error)
Definition HeifError.cpp:10
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_UNSPECIFIED
@ PRIMARIES_ITU_R_BT_709_5
TransferCharacteristics
The transferCharacteristics enum Enum of transfer characteristics, follows ITU H.273 for values 0 to ...
@ TRC_IEC_61966_2_1
@ TRC_ITU_R_BT_709_5
const quint8 OPACITY_OPAQUE_U8
LinearizePolicy
The KoColorTransferFunctions class.
KisGroupLayerSP rootLayer() const
QString nextLayerName(const QString &baseName="") const
Definition kis_image.cc:716
void cropImage(const QRect &newRect)
start asynchronous operation on cropping the image
Definition kis_image.cc:871
virtual bool loadFrom(Store *store, QIODevice *ioDevice) const =0
static KisMetadataBackendRegistry * instance()
KisHLineIteratorSP createHLineIteratorNG(qint32 x, qint32 y, qint32 w)
const T value(const QString &id) const
Definition KoID.h:30
QString id() const
Definition KoID.cpp:63
#define dbgFile
Definition kis_debug.h:53
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)

References KisNodeFacade::addNode(), KisDlgHLGImport::applyOOTF(), KoColorProfile::colorModelID(), KoColorSpaceRegistry::colorSpace(), KoColorSpaceRegistry::colorSpaceId(), KoColorSpaceRegistry::createColorProfile(), KisPaintDevice::createHLineIteratorNG(), KisImage::cropImage(), KisSharedPtr< T >::data(), dbgFile, KoColorSpaceRegistry::defaultProfileForColorSpace(), Float32BitsColorDepthID, KisDlgHLGImport::gamma(), GrayAColorModelID, KoID::id(), KisMetadataBackendRegistry::instance(), KoColorSpaceRegistry::instance(), Integer16BitsColorDepthID, Integer8BitsColorDepthID, KeepTheSame, LinearFromHLG, LinearFromPQ, LinearFromSMPTE428, KisMetaData::IOBackend::loadFrom(), KisLayer::metaData(), KoColorProfile::name, KisImage::nextLayerName(), KisDlgHLGImport::nominalPeakBrightness(), ImportExportCodes::OK, OPACITY_OPAQUE_U8, KisPaintLayer::paintDevice, PRIMARIES_ITU_R_BT_709_5, PRIMARIES_UNSPECIFIED, KoColorSpaceRegistry::profileByName(), KoColorSpaceRegistry::profileFor(), HDR::readInterleavedLayer(), SDR::readInterleavedLayer(), Gray::readPlanarLayer(), Planar::readPlanarLayer(), RGBAColorModelID, KoColorProfileQuery::rgbColorants, KisImage::rootLayer(), setHeifError(), TRC_IEC_61966_2_1, TRC_ITU_R_BT_709_5, TRC_LINEAR, KoGenericRegistry< T >::value(), and KoColorProfileQuery::whitePoint.

◆ supportsIO()

bool HeifImport::supportsIO ( ) const
inlineoverridevirtual

Override and return false for the filters that use a library that cannot handle file handles, only file names.

Reimplemented from KisImportExportFilter.

Definition at line 23 of file HeifImport.h.

23{ return true; }

The documentation for this class was generated from the following files: