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 45 of file HeifImport.cpp.

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

◆ ~HeifImport()

HeifImport::~HeifImport ( )
override

Definition at line 49 of file HeifImport.cpp.

50{
51}

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 210 of file HeifImport.cpp.

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 // Wrap input stream into heif Reader object
228 Reader_QIODevice reader(io);
229
230 try {
231 heif::Context ctx;
232 ctx.read_from_reader(reader);
233
234 // decode primary image
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 };
256 const KoColorProfile *profile = nullptr;
257 KoID colorDepth = Integer8BitsColorDepthID;
258 QString colorModel = RGBAColorModelID.id();
259
260 if (luma > 8) {
261 colorDepth = Integer16BitsColorDepthID;
262 }
263 // First, get the profile, because sometimes the image may be encoded in YCbCr and the embedded icc profile is graya.
264
265 if (profileType == heif_color_profile_type_prof || profileType == heif_color_profile_type_rICC) {
266 dbgFile << "profile type is icc profile";
267 // rICC are 'restricted' icc profiles, and are matrix shaper profiles
268 // that are either RGB or Grayscale, and are of the input or display types.
269 // They are from the JPEG2000 spec.
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 {
278 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 const QVector<double> colorants = [&]() -> QVector<double> {
327 if (primaries == PRIMARIES_UNSPECIFIED) {
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
342 profile = KoColorSpaceRegistry::instance()->profileFor(colorants,
343 primaries,
344 transferCharacteristic);
345
346 if (linearizePolicy != LinearizePolicy::KeepTheSame) {
347 colorDepth = Float32BitsColorDepthID;
348 }
349
350 heif_nclx_color_profile_free(nclx);
351 dbgFile << "nclx profile found" << profile->name();
352 }
353 } else {
354 dbgFile << "no profile found";
355 }
356
357 // Now, to figure out the correct chroma and color model.
358 if (heifModel == heif_colorspace_monochrome || colorModel == GrayAColorModelID.id()) {
359 // Grayscale image.
360 if (heifChroma != heif_chroma_monochrome && colorModel == GrayAColorModelID.id()) {
361 heifimage = handle.decode_image(heif_colorspace_YCbCr, heif_chroma_monochrome);
362 }
363 colorModel = GrayAColorModelID.id();
364 heifChroma = heif_chroma_monochrome;
365
366 }
367
368 // Get the default profile if we haven't found one up till now.
369 if (!profile) {
370 if (colorModel == RGBAColorModelID.id()) {
374 } else {
375 const QString colorSpaceId = KoColorSpaceRegistry::instance()->colorSpaceId(colorModel, colorDepth.id());
376 QString profileName = KoColorSpaceRegistry::instance()->defaultProfileForColorSpace(colorSpaceId);
377 profile = KoColorSpaceRegistry::instance()->profileByName(profileName);
378 }
379 }
380
381 const KoColorSpace *colorSpace = KoColorSpaceRegistry::instance()->colorSpace(colorModel, colorDepth.id(), profile);
382
383 int width = handle.get_width();
384
385 int height = handle.get_height();
386
387 // convert HEIF image to Krita KisDocument
388
389 KisImageSP image = new KisImage(document->createUndoStore(), width, height, colorSpace,
390 "HEIF image");
391
392 KisPaintLayerSP layer = new KisPaintLayer(image, image->nextLayerName(), OPACITY_OPAQUE_U8);
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);
408 layer->paintDevice()->createHLineIteratorNG(0, 0, width);
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);
431 KisHLineIteratorSP it = layer->paintDevice()->createHLineIteratorNG(0, 0, width);
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);
459 layer->paintDevice()->createHLineIteratorNG(0, 0, width);
460
461 SDR::readInterleavedLayer(linearizePolicy,
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);
480 layer->paintDevice()->createHLineIteratorNG(0, 0, width);
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
496 image->addNode(layer.data(), image->rootLayer().data());
497 image->cropImage(QRect(0, 0, width, height));
498
499 // --- Iterate through all metadata blocks and extract Exif and XMP metadata ---
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 // Read exif information
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) {
517 KisMetaData::IOBackend *exifIO =
519
520 // Copy the exif data into the byte array
521 QByteArray ba(
522 reinterpret_cast<char *>(exif_data.data() + skip),
523 static_cast<int>(exif_data.size() - skip));
524 QBuffer buf(&ba);
525 exifIO->loadFrom(layer->metaData(), &buf);
526 }
527 }
528 }
529
530 if (handle.get_metadata_type(id) == "mime" &&
531 handle.get_metadata_content_type(id) == "application/rdf+xml") {
532 // Read XMP information
533
534 std::vector<uint8_t> xmp_data = handle.get_metadata(id);
536
537 // Copy the xmp data into the byte array
538 QByteArray ba(reinterpret_cast<char *>(xmp_data.data()), static_cast<int>(xmp_data.size()));
539 QBuffer buf(&ba);
540 xmpIO->loadFrom(layer->metaData(), &buf);
541 }
542 }
543
544 document->setCurrentImage(image);
546 } catch (Error &err) {
547 return setHeifError(document, err);
548 }
549}
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:715
void cropImage(const QRect &newRect)
start asynchronous operation on cropping the image
Definition kis_image.cc:870
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
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)

References KisNodeFacade::addNode(), KoColorSpaceRegistry::addProfile(), 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, KisImage::rootLayer(), setHeifError(), TRC_IEC_61966_2_1, TRC_ITU_R_BT_709_5, TRC_LINEAR, and KoGenericRegistry< T >::value().

◆ 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: