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

#include <kis_tiff_import.h>

+ Inheritance diagram for KisTIFFImport:

Public Member Functions

KisImportExportErrorCode convert (KisDocument *document, QIODevice *io, KisPropertiesConfigurationSP configuration=nullptr) override
 
 KisTIFFImport (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.
 
 ~KisTIFFImport () 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 ()
 

Private Member Functions

KisImportExportErrorCode readImageFromPsd (KisDocument *m_doc, TIFF *image, KisTiffBasicInfo &basicInfo)
 
KisImportExportErrorCode readImageFromTiff (KisDocument *m_doc, TIFF *image, KisTiffBasicInfo &basicInfo)
 
KisImportExportErrorCode readTIFFDirectory (KisDocument *m_doc, TIFF *image)
 

Private Attributes

KisImageSP m_image
 
bool m_photoshopBlockParsed = false
 
TIFFErrorHandler oldErrHandler = nullptr
 
TIFFErrorHandler oldWarnHandler = nullptr
 

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 23 of file kis_tiff_import.h.

Constructor & Destructor Documentation

◆ KisTIFFImport()

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

Definition at line 315 of file kis_tiff_import.cc.

316 : KisImportExportFilter(parent)
317 , m_image(nullptr)
318 , oldErrHandler(TIFFSetErrorHandler(&KisTiffErrorHandler))
319 , oldWarnHandler(TIFFSetWarningHandler(&KisTiffWarningHandler))
320{
321}
KisImportExportFilter(QObject *parent=0)
TIFFErrorHandler oldErrHandler
KisImageSP m_image
TIFFErrorHandler oldWarnHandler
void KisTiffWarningHandler(const char *module, const char *fmt, va_list args)
void KisTiffErrorHandler(const char *module, const char *fmt, va_list args)

◆ ~KisTIFFImport()

KisTIFFImport::~KisTIFFImport ( )
override

Definition at line 323 of file kis_tiff_import.cc.

324{
325 TIFFSetErrorHandler(oldErrHandler);
326 TIFFSetWarningHandler(oldWarnHandler);
327}

References oldErrHandler, and oldWarnHandler.

Member Function Documentation

◆ convert()

KisImportExportErrorCode KisTIFFImport::convert ( KisDocument * document,
QIODevice * io,
KisPropertiesConfigurationSP configuration = nullptr )
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 1815 of file kis_tiff_import.cc.

1818{
1819 dbgFile << "Start decoding TIFF File";
1820
1823 }
1826 }
1827
1828 QFile file(filename());
1829 if (!file.open(QFile::ReadOnly)) {
1831 }
1832
1833 // Open the TIFF file
1834 const QByteArray encodedFilename = QFile::encodeName(filename());
1835
1836 // https://gitlab.com/libtiff/libtiff/-/issues/173
1837#ifdef Q_OS_WIN
1838 const intptr_t handle = _get_osfhandle(file.handle());
1839#else
1840 const int handle = file.handle();
1841#endif
1842
1843 std::unique_ptr<TIFF, decltype(&TIFFCleanup)> image(TIFFFdOpen(handle, encodedFilename.data(), "r"), &TIFFCleanup);
1844
1845 if (!image) {
1846 dbgFile << "Could not open the file, either it does not exist, either "
1847 "it is not a TIFF :"
1848 << filename();
1850 }
1851 dbgFile << "Reading first image descriptor";
1852 KisImportExportErrorCode result = readTIFFDirectory(document, image.get());
1853 if (!result.isOk()) {
1854 return result;
1855 }
1856
1858 // Photoshop images only have one IFD plus the layer blob
1859 // Ward off inconsistencies by blocking future attempts to parse them
1861 while (TIFFReadDirectory(image.get())) {
1862 result = readTIFFDirectory(document, image.get());
1863 if (!result.isOk()) {
1864 return result;
1865 }
1866 }
1867 }
1868 // Freeing memory
1869 image.reset();
1870 file.close();
1871
1872 {
1873 // HACK!! Externally parse the Exif metadata
1874 // libtiff has no way to access the fields wholesale
1875 try {
1877
1878#if EXIV2_TEST_VERSION(0,28,0)
1879 const std::unique_ptr<Exiv2::Image> readImg = Exiv2::ImageFactory::open(std::move(basicIoDevice));
1880#else
1881 const std::unique_ptr<Exiv2::Image> readImg(Exiv2::ImageFactory::open(basicIoDevice).release());
1882#endif
1883
1884 readImg->readMetadata();
1885
1886 const KisMetaData::IOBackend *io =
1888
1889 // All IFDs are paint layer children of root
1891
1892 QBuffer ioDevice;
1893
1894 {
1895 // Synthesize the Exif blob
1896 Exiv2::ExifData tempData;
1897 Exiv2::Blob tempBlob;
1898
1899 // NOTE: do not use std::copy_if, auto_ptrs beware
1900 for (const Exiv2::Exifdatum &i : readImg->exifData()) {
1901 const uint16_t tag = i.tag();
1902
1903 if (tag == Exif::Image::ImageWidth
1904 || tag == Exif::Image::ImageLength
1906 || tag == Exif::Image::Compression
1908 || tag == Exif::Image::Orientation
1913 || tag == Exif::Image::XResolution
1914 || tag == Exif::Image::YResolution
1917 || tag == Exif::Image::WhitePoint
1922 dbgMetaData << "Ignoring TIFF-specific"
1923 << i.key().c_str();
1924 continue;
1925 }
1926
1927 tempData.add(i);
1928 }
1929
1930 // Encode into temporary blob
1931 Exiv2::ExifParser::encode(tempBlob,
1932 Exiv2::littleEndian,
1933 tempData);
1934
1935 // Reencode into Qt land
1936 ioDevice.setData(reinterpret_cast<char *>(tempBlob.data()),
1937 static_cast<int>(tempBlob.size()));
1938 }
1939
1940 // Get layer
1941 KisLayer *layer = qobject_cast<KisLayer *>(node.data());
1942 KIS_ASSERT_RECOVER(layer)
1943 {
1944 errFile << "Attempted to import metadata on an empty document";
1946 }
1947
1948 // Inject the data as any other IOBackend
1949 io->loadFrom(layer->metaData(), &ioDevice);
1950#if EXIV2_TEST_VERSION(0,28,0)
1951 } catch (Exiv2::Error &e) {
1952 errFile << "Failed metadata import:" << Exiv2::Error(e.code()).what();
1953#else
1954 } catch (Exiv2::AnyError &e) {
1955 errFile << "Failed metadata import:" << e.code() << e.what();
1956#endif
1957 }
1958 }
1959
1960 document->setCurrentImage(m_image);
1961
1962 m_image = nullptr;
1963 m_photoshopBlockParsed = false;
1964
1965 return ImportExportCodes::OK;
1966}
Exiv2::BasicIo::AutoPtr ptr_type
KisGroupLayerSP rootLayer() const
virtual bool loadFrom(Store *store, QIODevice *ioDevice) const =0
static KisMetadataBackendRegistry * instance()
KisImportExportErrorCode readTIFFDirectory(KisDocument *m_doc, TIFF *image)
bool m_photoshopBlockParsed
const T value(const QString &id) const
#define KIS_ASSERT_RECOVER(cond)
Definition kis_assert.h:55
#define errFile
Definition kis_debug.h:115
#define dbgMetaData
Definition kis_debug.h:61
#define dbgFile
Definition kis_debug.h:53
const uint16_t ImageLength
const uint16_t PrimaryChromaticities
const uint16_t ReferenceBlackWhite
const uint16_t ImageWidth
const uint16_t PlanarConfiguration
const uint16_t YResolution
const uint16_t XResolution
const uint16_t TransferFunction
const uint16_t Orientation
const uint16_t ResolutionUnit
const uint16_t YCbCrSubSampling
const uint16_t SamplesPerPixel
const uint16_t BitsPerSample
const uint16_t Compression
const uint16_t InterColorProfile
const uint16_t YCbCrCoefficients
const uint16_t YCbCrPositioning
const uint16_t WhitePoint
const uint16_t PhotometricInterpretation
KisMetaData::Store * metaData()
KisNodeSP firstChild() const
Definition kis_node.cpp:361

References Exif::Image::BitsPerSample, Exif::Image::Compression, KisSharedPtr< T >::data(), dbgFile, dbgMetaData, KisImportExportAdditionalChecks::doesFileExist(), errFile, ImportExportCodes::FileFormatIncorrect, KisImportExportFilter::filename, ImportExportCodes::FileNotExist, KisNode::firstChild(), Exif::Image::ImageLength, Exif::Image::ImageWidth, KisMetadataBackendRegistry::instance(), Exif::Image::InterColorProfile, ImportExportCodes::InternalError, KisImportExportAdditionalChecks::isFileReadable(), KisImportExportErrorCode::isOk(), KIS_ASSERT_RECOVER, KisMetaData::IOBackend::loadFrom(), m_image, m_photoshopBlockParsed, KisLayer::metaData(), ImportExportCodes::NoAccessToRead, ImportExportCodes::OK, Exif::Image::Orientation, Exif::Image::PhotometricInterpretation, Exif::Image::PlanarConfiguration, Exif::Image::PrimaryChromaticities, readTIFFDirectory(), Exif::Image::ReferenceBlackWhite, Exif::Image::ResolutionUnit, KisImage::rootLayer(), Exif::Image::SamplesPerPixel, Exif::Image::TransferFunction, KoGenericRegistry< T >::value(), Exif::Image::WhitePoint, Exif::Image::XResolution, Exif::Image::YCbCrCoefficients, Exif::Image::YCbCrPositioning, Exif::Image::YCbCrSubSampling, and Exif::Image::YResolution.

◆ readImageFromPsd()

KisImportExportErrorCode KisTIFFImport::readImageFromPsd ( KisDocument * m_doc,
TIFF * image,
KisTiffBasicInfo & basicInfo )
private

Imports the image from the PSD descriptor.

Definition at line 1505 of file kis_tiff_import.cc.

1506{
1507#ifdef TIFF_HAS_PSD_TAGS
1508 // Attempt to parse Photoshop metadata
1509 // if it succeeds, divert and load as PSD
1510
1512 QBuffer photoshopLayerData;
1513
1514 KisTiffPsdLayerRecord photoshopLayerRecord(TIFFIsBigEndian(image),
1515 basicInfo.width,
1516 basicInfo.height,
1517 basicInfo.depth,
1518 basicInfo.nbchannels,
1519 basicInfo.color_type);
1520
1521 KisTiffPsdResourceRecord photoshopImageResourceRecord;
1522
1523 {
1524 // Determine if we have Photoshop metadata
1525 uint32_t length{0};
1526 uint8_t *data{nullptr};
1527
1528 if (TIFFGetField(image, TIFFTAG_IMAGESOURCEDATA, &length, &data)
1529 == 1) {
1530 dbgFile << "There are Photoshop layers, processing them now. "
1531 "Section size: "
1532 << length;
1533
1534 QByteArray buf(reinterpret_cast<char *>(data),
1535 static_cast<int>(length));
1536 photoshopLayerData.setData(buf);
1537 photoshopLayerData.open(QIODevice::ReadOnly);
1538
1539 if (!photoshopLayerRecord.read(photoshopLayerData)) {
1540 dbgFile << "TIFF: failed reading Photoshop layer metadata: "
1541 << photoshopLayerRecord.record()->error;
1542 }
1543 }
1544 }
1545
1546 {
1547 // Determine if we have Photoshop metadata
1548 uint32_t length{0};
1549 uint8_t *data{nullptr};
1550
1551 if (TIFFGetField(image, TIFFTAG_PHOTOSHOP, &length, &data) == 1
1552 && data != nullptr) {
1553 dbgFile << "There is Photoshop metadata, processing it now. "
1554 "Section size: "
1555 << length;
1556
1557 QByteArray photoshopImageResourceData(
1558 reinterpret_cast<char *>(data),
1559 static_cast<int>(length));
1560
1561 QBuffer buf(&photoshopImageResourceData);
1562 buf.open(QIODevice::ReadOnly);
1563
1564 if (!photoshopImageResourceRecord.read(buf)) {
1565 dbgFile << "TIFF: failed reading Photoshop image metadata: "
1566 << photoshopImageResourceRecord.error;
1567 }
1568 }
1569 }
1570
1571 if (photoshopLayerRecord.valid()
1572 && photoshopImageResourceRecord.valid()) {
1573
1575
1576 bool usePsd = true;
1577 importUserFeedBackInterface()->askUser([&] (QWidget *parent) {
1578 usePsd = QMessageBox::question(parent, i18nc("@title:window", "TIFF image with PSD data"),
1579 i18nc("the choice for the user on loading a TIFF file",
1580 "The TIFF image contains valid PSD data embedded. "
1581 "Would you like to use PSD data instead of normal TIFF data?"))
1582 == QMessageBox::Yes;
1583
1584 return true;
1585 });
1586
1587 if (!usePsd) {
1589 }
1590 }
1591
1593 readImageFromPsdRecords(m_doc,
1594 photoshopLayerRecord,
1595 photoshopImageResourceRecord,
1596 photoshopLayerData,
1597 basicInfo);
1598
1599 if (!result.isOk()) {
1600 dbgFile << "Photoshop import failed";
1601 }
1602 return result;
1603 }
1604 }
1605
1607
1608#else
1610#endif
1611}
qreal length(const QPointF &vec)
Definition Ellipse.cc:82
KisImportUserFeedbackInterface * importUserFeedBackInterface
virtual Result askUser(AskCallback callback)=0
ask the user a question about the loading process

References KisImportUserFeedbackInterface::askUser(), ImportExportCodes::Cancelled, KisTiffBasicInfo::color_type, dbgFile, KisTiffBasicInfo::depth, KisTiffPsdResourceRecord::error, ImportExportCodes::FormatFeaturesUnsupported, KisTiffBasicInfo::height, KisImportExportFilter::importUserFeedBackInterface, KisImportExportErrorCode::isOk(), length(), m_photoshopBlockParsed, KisTiffBasicInfo::nbchannels, KisTiffPsdLayerRecord::read(), KisTiffPsdResourceRecord::read(), KisTiffPsdLayerRecord::record(), KisTiffPsdResourceRecord::valid(), KisTiffPsdLayerRecord::valid(), and KisTiffBasicInfo::width.

◆ readImageFromTiff()

KisImportExportErrorCode KisTIFFImport::readImageFromTiff ( KisDocument * m_doc,
TIFF * image,
KisTiffBasicInfo & basicInfo )
private

Imports the image from the TIFF descriptor.

Definition at line 592 of file kis_tiff_import.cc.

595{
596 uint32_t &width = basicInfo.width;
597 uint32_t &height = basicInfo.height;
598 float &xres = basicInfo.xres;
599 float &yres = basicInfo.yres;
600 uint16_t &depth = basicInfo.depth;
601 uint16_t &sampletype = basicInfo.sampletype;
602 uint16_t &nbchannels = basicInfo.nbchannels;
603 uint16_t &color_type = basicInfo.color_type;
604 uint16_t *&sampleinfo = basicInfo.sampleinfo;
605 uint16_t &extrasamplescount = basicInfo.extrasamplescount;
606 const KoColorSpace *&cs = basicInfo.cs;
607 QPair<QString, QString> &colorSpaceIdTag = basicInfo.colorSpaceIdTag;
608 KoColorTransformation *&transform = basicInfo.transform;
609 uint8_t &dstDepth = basicInfo.dstDepth;
610
611 // Check if there is an alpha channel
612 int32_t alphapos = -1; // <- no alpha
613 bool hasPremultipliedAlpha = false;
614 // Check which extra is alpha if any
615 dbgFile << "There are" << nbchannels << " channels and" << extrasamplescount
616 << " extra channels";
617 if (sampleinfo) { // index images don't have any sampleinfo, and therefore
618 // sampleinfo == 0
619 for (uint16_t i = 0; i < extrasamplescount; i++) {
620 dbgFile << "sample" << i << "extra sample count"
621 << extrasamplescount << "color channel count"
622 << (cs->colorChannelCount()) << "Number of channels"
623 << nbchannels << "sample info" << sampleinfo[i];
624 switch (sampleinfo[i]) {
625 case EXTRASAMPLE_ASSOCALPHA:
626 // The color values are already multiplied with the alpha value.
627 // This is reversed in the postprocessor.
628 dbgPlugins << "Detected associated alpha @ " << i;
629 hasPremultipliedAlpha = true;
630 alphapos = static_cast<int32_t>(extrasamplescount
631 - 1U); // nbsamples - 1
632 break;
633 case EXTRASAMPLE_UNASSALPHA:
634 // color values are not premultiplied with alpha, and can be
635 // used as they are.
636 alphapos = i;
637 break;
638 case EXTRASAMPLE_UNSPECIFIED:
639 default:
640 qWarning() << "Extra sample type not defined for this file, "
641 "assuming unassociated alpha.";
642 alphapos = i;
643 break;
644 }
645
646 if (sampleinfo[i] == EXTRASAMPLE_UNASSALPHA) {
647 // color values are not premultiplied with alpha, and can be
648 // used as they are.
649 alphapos = i;
650 }
651 }
652 }
653
654 dbgFile << "Alpha pos:" << alphapos;
655
656 // Read META Information
657 KoDocumentInfo *info = m_doc->documentInfo();
658 char *text = nullptr;
659 if (TIFFGetField(image, TIFFTAG_ARTIST, &text) == 1) {
660 info->setAuthorInfo("creator", text);
661 }
662 if (TIFFGetField(image, TIFFTAG_DOCUMENTNAME, &text) == 1) {
663 info->setAboutInfo("title", text);
664 }
665 if (TIFFGetField(image, TIFFTAG_IMAGEDESCRIPTION, &text) == 1) {
666 info->setAboutInfo("description", text);
667 }
668
669 uint16_t orientation = ORIENTATION_TOPLEFT;
670 if (TIFFGetField(image, TIFFTAG_ORIENTATION, &orientation) == 0) {
671 dbgFile << "Orientation not defined, assuming top left";
672 }
673
674 dbgFile << "Orientation:" << orientation;
675
676 // Try to get IPTC metadata
677 uint32_t iptc_profile_size = 0;
678 uint32_t *iptc_profile_data = nullptr;
679 if (TIFFGetField(image,
680 TIFFTAG_RICHTIFFIPTC,
681 &iptc_profile_size,
682 &iptc_profile_data)
683 == 0) {
684 dbgFile << "IPTC metadata not found!";
685 }
686
687 // Try to get XMP metadata
688 uint32_t xmp_size = 0;
689 uint8_t *xmp_data = nullptr;
690 if (TIFFGetField(image, TIFFTAG_XMLPACKET, &xmp_size, &xmp_data) == 0) {
691 dbgFile << "XML metadata not found!";
692 }
693
694 // Get the planar configuration
695 uint16_t planarconfig = PLANARCONFIG_CONTIG;
696 if (TIFFGetField(image, TIFFTAG_PLANARCONFIG, &planarconfig) == 0) {
697 dbgFile << "Planar configuration is not defined";
699 }
700 // Creating the KisImageSP
701 if (!m_image) {
702 m_image = new KisImage(m_doc->createUndoStore(),
703 static_cast<qint32>(width),
704 static_cast<qint32>(height),
705 cs,
706 "built image");
708 m_image,
710 // It is the "invert" macro because we
711 // convert from pointer-per-unit to points
712 if (basicInfo.resolution == TiffResolution::INCH) {
713 m_image->setResolution(POINT_TO_INCH(static_cast<qreal>(xres)), POINT_TO_INCH(static_cast<qreal>(yres)));
714 } else {
715 m_image->setResolution(POINT_TO_CM(static_cast<qreal>(xres)), POINT_TO_CM(static_cast<qreal>(yres)));
716 }
717 } else {
718 if (m_image->width() < static_cast<qint32>(width)
719 || m_image->height() < static_cast<qint32>(height)) {
720 qint32 newwidth = (m_image->width() < static_cast<qint32>(width))
721 ? static_cast<qint32>(width)
722 : m_image->width();
723 qint32 newheight = (m_image->height() < static_cast<qint32>(height))
724 ? static_cast<qint32>(height)
725 : m_image->height();
726 m_image->resizeImage(QRect(0, 0, newwidth, newheight));
727 }
728 }
729 KisPaintLayer *layer =
731 std::unique_ptr<std::remove_pointer_t<tdata_t>, decltype(&_TIFFfree)> buf(
732 nullptr,
733 &_TIFFfree);
734 // used only for planar configuration separated
736 [](QVector<uint8_t *> *buf) {
737 for (uint8_t *p : *buf)
738 _TIFFfree(p);
739 delete buf;
740 });
741
742 QSharedPointer<KisBufferStreamBase> tiffstream = nullptr;
743 QSharedPointer<KisTIFFReaderBase> tiffReader = nullptr;
744
745 // Configure poses
746 uint16_t nbcolorsamples = nbchannels - extrasamplescount;
747 const auto poses = [&]() -> std::array<quint8, 5> {
748 switch (color_type) {
749 case PHOTOMETRIC_MINISWHITE:
750 case PHOTOMETRIC_MINISBLACK:
751 return {0, 1};
752 case PHOTOMETRIC_CIELAB:
753 case PHOTOMETRIC_ICCLAB:
754 return {0, 1, 2, 3};
755 case PHOTOMETRIC_RGB:
756 if (sampletype == SAMPLEFORMAT_IEEEFP) {
757 return {0, 1, 2, 3};
758 } else {
759 return {2, 1, 0, 3};
760 }
761 case PHOTOMETRIC_SEPARATED:
762 return {0, 1, 2, 3, 4};
763 default:
764 return {};
765 }
766 }();
767
768 auto postprocessor = [&]() -> QSharedPointer<KisTIFFPostProcessor> {
769 switch (color_type) {
770 case PHOTOMETRIC_MINISWHITE:
771 return makePostProcessor<KisTIFFPostProcessorInvert>(
772 nbcolorsamples,
773 colorSpaceIdTag);
774 case PHOTOMETRIC_MINISBLACK:
775 return makePostProcessor<KisTIFFPostProcessorDummy>(
776 nbcolorsamples,
777 colorSpaceIdTag);
778 case PHOTOMETRIC_CIELAB:
779 return makePostProcessor<KisTIFFPostProcessorCIELABtoICCLAB>(
780 nbcolorsamples,
781 colorSpaceIdTag);
782 case PHOTOMETRIC_ICCLAB:
783 case PHOTOMETRIC_RGB:
784 case PHOTOMETRIC_SEPARATED:
785 return makePostProcessor<KisTIFFPostProcessorDummy>(
786 nbcolorsamples,
787 colorSpaceIdTag);
788 default:
789 return {};
790 }
791 }();
792
793 // Initialize tiffReader
794 QVector<uint16_t> lineSizeCoeffs(nbchannels, 1);
795 uint16_t vsubsampling = 1;
796 uint16_t hsubsampling = 1;
797 if (color_type == PHOTOMETRIC_PALETTE) {
798 uint16_t *red =
799 nullptr; // No need to free them they are free by libtiff
800 uint16_t *green = nullptr;
801 uint16_t *blue = nullptr;
802 if ((TIFFGetField(image, TIFFTAG_COLORMAP, &red, &green, &blue)) == 0) {
803 dbgFile << "Indexed image does not define a palette";
805 }
806
807 tiffReader =
809 red,
810 green,
811 blue,
812 poses,
813 alphapos,
814 depth,
815 sampletype,
816 nbcolorsamples,
817 extrasamplescount,
818 hasPremultipliedAlpha,
819 transform,
820 postprocessor);
821 } else if (color_type == PHOTOMETRIC_YCBCR) {
822 TIFFGetFieldDefaulted(image,
823 TIFFTAG_YCBCRSUBSAMPLING,
824 &hsubsampling,
825 &vsubsampling);
826 lineSizeCoeffs[1] = hsubsampling;
827 lineSizeCoeffs[2] = hsubsampling;
828 dbgFile << "Subsampling" << 4 << hsubsampling << vsubsampling;
829 if (dstDepth == 8) {
830 tiffReader = QSharedPointer<KisTIFFYCbCrReader<uint8_t>>::create(
831 layer->paintDevice(),
832 static_cast<quint32>(layer->image()->width()),
833 static_cast<quint32>(layer->image()->height()),
834 poses,
835 alphapos,
836 depth,
837 sampletype,
838 nbcolorsamples,
839 extrasamplescount,
840 hasPremultipliedAlpha,
841 transform,
842 postprocessor,
843 hsubsampling,
844 vsubsampling);
845 } else if (dstDepth == 16) {
846 if (sampletype == SAMPLEFORMAT_IEEEFP) {
847#ifdef HAVE_OPENEXR
848 tiffReader = QSharedPointer<KisTIFFYCbCrReader<half>>::create(
849 layer->paintDevice(),
850 static_cast<quint32>(layer->image()->width()),
851 static_cast<quint32>(layer->image()->height()),
852 poses,
853 alphapos,
854 depth,
855 sampletype,
856 nbcolorsamples,
857 extrasamplescount,
858 hasPremultipliedAlpha,
859 transform,
860 postprocessor,
861 hsubsampling,
862 vsubsampling);
863#endif
864 } else {
865 tiffReader =
867 layer->paintDevice(),
868 static_cast<quint32>(layer->image()->width()),
869 static_cast<quint32>(layer->image()->height()),
870 poses,
871 alphapos,
872 depth,
873 sampletype,
874 nbcolorsamples,
875 extrasamplescount,
876 hasPremultipliedAlpha,
877 transform,
878 postprocessor,
879 hsubsampling,
880 vsubsampling);
881 }
882 } else if (dstDepth == 32) {
883 if (sampletype == SAMPLEFORMAT_IEEEFP) {
884 tiffReader = QSharedPointer<KisTIFFYCbCrReader<float>>::create(
885 layer->paintDevice(),
886 static_cast<quint32>(layer->image()->width()),
887 static_cast<quint32>(layer->image()->height()),
888 poses,
889 alphapos,
890 depth,
891 sampletype,
892 nbcolorsamples,
893 extrasamplescount,
894 hasPremultipliedAlpha,
895 transform,
896 postprocessor,
897 hsubsampling,
898 vsubsampling);
899 } else {
900 tiffReader =
902 layer->paintDevice(),
903 static_cast<quint32>(layer->image()->width()),
904 static_cast<quint32>(layer->image()->height()),
905 poses,
906 alphapos,
907 depth,
908 sampletype,
909 nbcolorsamples,
910 extrasamplescount,
911 hasPremultipliedAlpha,
912 transform,
913 postprocessor,
914 hsubsampling,
915 vsubsampling);
916 }
917 }
918 } else if (dstDepth == 8) {
920 layer->paintDevice(),
921 poses,
922 alphapos,
923 depth,
924 sampletype,
925 nbcolorsamples,
926 extrasamplescount,
927 hasPremultipliedAlpha,
928 transform,
929 postprocessor,
930 quint8_MAX);
931 } else if (dstDepth == 16) {
932 if (sampletype == SAMPLEFORMAT_IEEEFP) {
933#ifdef HAVE_OPENEXR
934 tiffReader = QSharedPointer<KisTIFFReaderTarget<half>>::create(
935 layer->paintDevice(),
936 poses,
937 alphapos,
938 depth,
939 sampletype,
940 nbcolorsamples,
941 extrasamplescount,
942 hasPremultipliedAlpha,
943 transform,
944 postprocessor,
945 1.0);
946#endif
947 } else {
949 layer->paintDevice(),
950 poses,
951 alphapos,
952 depth,
953 sampletype,
954 nbcolorsamples,
955 extrasamplescount,
956 hasPremultipliedAlpha,
957 transform,
958 postprocessor,
960 }
961 } else if (dstDepth == 32) {
962 if (sampletype == SAMPLEFORMAT_IEEEFP) {
963 tiffReader = QSharedPointer<KisTIFFReaderTarget<float>>::create(
964 layer->paintDevice(),
965 poses,
966 alphapos,
967 depth,
968 sampletype,
969 nbcolorsamples,
970 extrasamplescount,
971 hasPremultipliedAlpha,
972 transform,
973 postprocessor,
974 1.0f);
975 } else {
977 layer->paintDevice(),
978 poses,
979 alphapos,
980 depth,
981 sampletype,
982 nbcolorsamples,
983 extrasamplescount,
984 hasPremultipliedAlpha,
985 transform,
986 postprocessor,
987 std::numeric_limits<uint32_t>::max());
988 }
989 }
990
991 if (!tiffReader) {
992 dbgFile << "Image has an invalid/unsupported color type: "
993 << color_type;
995 }
996
997 uint32_t compression = COMPRESSION_NONE;
998 TIFFGetFieldDefaulted(image, TIFFTAG_COMPRESSION, &compression, COMPRESSION_NONE);
999
1000#ifdef HAVE_JPEG_TURBO
1001 uint32_t hasSplitTables = 0;
1002 uint8_t *tables = nullptr;
1003 uint32_t sz = 0;
1004 QVector<unsigned char> jpegBuf;
1005
1006 auto handle = [&]() -> std::unique_ptr<void, decltype(&tjDestroy)> {
1007 if (planarconfig == PLANARCONFIG_CONTIG
1008 && color_type == PHOTOMETRIC_YCBCR
1009 && compression == COMPRESSION_JPEG) {
1010 return {tjInitDecompress(), &tjDestroy};
1011 } else {
1012 return {nullptr, &tjDestroy};
1013 }
1014 }();
1015
1016 if (color_type == PHOTOMETRIC_YCBCR && compression == COMPRESSION_JPEG
1017 && hsubsampling != 1 && vsubsampling != 1) {
1018 dbgFile << "Setting up libjpeg-turbo for handling subsampled JPEG...";
1019 if (!TIFFGetFieldDefaulted(image,
1020 TIFFTAG_JPEGTABLESMODE,
1021 &hasSplitTables)) {
1022 errFile << "Error when detecting the JPEG coefficient "
1023 "table mode";
1025 }
1026 if (hasSplitTables) {
1027 if (!TIFFGetField(image, TIFFTAG_JPEGTABLES, &sz, &tables)) {
1028 errFile << "Unable to retrieve the JPEG abbreviated datastream";
1030 }
1031 }
1032
1033 {
1034 int width = 0;
1035 int height = 0;
1036
1037 if (hasSplitTables
1038 && tjDecompressHeader(handle.get(), tables, sz, &width, &height)
1039 != 0) {
1040 errFile << tjGetErrorStr2(handle.get());
1041 m_doc->setErrorMessage(
1042 i18nc("TIFF errors",
1043 "This TIFF file is compressed with JPEG, but "
1044 "libjpeg-turbo could not load its coefficient "
1045 "quantization and/or Huffman coding tables. "
1046 "Please upgrade your version of libjpeg-turbo "
1047 "and try again."));
1049 }
1050 }
1051 }
1052#endif
1053
1054 if (TIFFIsTiled(image)) {
1055 dbgFile << "tiled image";
1056 uint32_t tileWidth = 0;
1057 uint32_t tileHeight = 0;
1058 uint32_t x = 0;
1059 uint32_t y = 0;
1060 TIFFGetField(image, TIFFTAG_TILEWIDTH, &tileWidth);
1061 TIFFGetField(image, TIFFTAG_TILELENGTH, &tileHeight);
1062 tmsize_t tileSize = TIFFTileSize(image);
1063
1064 if (planarconfig == PLANARCONFIG_CONTIG
1065 && !(color_type == PHOTOMETRIC_YCBCR
1066 && compression == COMPRESSION_JPEG && hsubsampling != 1
1067 && vsubsampling != 1)) {
1068 buf.reset(_TIFFmalloc(tileSize));
1069 if (depth < 16) {
1070 tiffstream =
1072 static_cast<uint8_t *>(buf.get()),
1073 depth,
1074 tileSize / tileHeight);
1075 } else if (depth >= 16 && depth < 32) {
1076 tiffstream =
1078 static_cast<uint8_t *>(buf.get()),
1079 depth,
1080 tileSize / tileHeight);
1081 } else {
1082 tiffstream =
1084 static_cast<uint8_t *>(buf.get()),
1085 depth,
1086 tileSize / tileHeight);
1087 }
1088 } else if (planarconfig == PLANARCONFIG_CONTIG
1089 && color_type == PHOTOMETRIC_YCBCR
1090 && compression == COMPRESSION_JPEG) {
1091#ifdef HAVE_JPEG_TURBO
1092 jpegBuf.resize(tileSize);
1093 ps_buf->resize(nbchannels);
1094 TIFFReadRawTile(image, 0, jpegBuf.data(), tileSize);
1095
1096 int width = tileWidth;
1097 int height = tileHeight;
1098 int jpegSubsamp = TJ_444;
1099 int jpegColorspace = TJCS_YCbCr;
1100
1101 if (tjDecompressHeader3(handle.get(),
1102 jpegBuf.data(),
1103 tileSize,
1104 &width,
1105 &height,
1106 &jpegSubsamp,
1107 &jpegColorspace)
1108 != 0) {
1109 errFile << tjGetErrorStr2(handle.get());
1111 }
1112
1113 QVector<tsize_t> lineSizes(nbchannels);
1114 for (uint32_t i = 0; i < nbchannels; i++) {
1115 const unsigned long uncompressedTileSize =
1116 tjPlaneSizeYUV(i, width, 0, height, jpegColorspace);
1118 uncompressedTileSize != (unsigned long)-1,
1120 dbgFile << QString("Uncompressed tile size (plane %1): %2")
1121 .arg(i)
1122 .arg(uncompressedTileSize)
1123 .toStdString()
1124 .c_str();
1125 tsize_t scanLineSize = uncompressedTileSize / tileHeight;
1126 dbgFile << QString("scan line size (plane %1): %2")
1127 .arg(i)
1128 .arg(scanLineSize)
1129 .toStdString()
1130 .c_str();
1131 (*ps_buf)[i] =
1132 static_cast<uint8_t *>(_TIFFmalloc(uncompressedTileSize));
1133 lineSizes[i] = scanLineSize;
1134 }
1135 tiffstream =
1137 ps_buf->data(),
1138 nbchannels,
1139 depth,
1140 lineSizes.data(),
1141 hsubsampling,
1142 vsubsampling);
1143#else
1144 m_doc->setErrorMessage(
1145 i18nc("TIFF",
1146 "Subsampled YCbCr TIFF files compressed with JPEG cannot "
1147 "be loaded."));
1149#endif
1150 } else {
1151 ps_buf->resize(nbchannels);
1152 tsize_t scanLineSize = tileSize / tileHeight;
1153 dbgFile << " scanLineSize for each plan =" << scanLineSize;
1154 QVector<tsize_t> lineSizes(nbchannels);
1155 for (uint32_t i = 0; i < nbchannels; i++) {
1156 (*ps_buf)[i] = static_cast<uint8_t *>(_TIFFmalloc(tileSize));
1157 lineSizes[i] = scanLineSize / lineSizeCoeffs[i];
1158 }
1160 ps_buf->data(),
1161 nbchannels,
1162 depth,
1163 lineSizes.data());
1164 }
1165 dbgFile << "Scanline size =" << TIFFRasterScanlineSize(image)
1166 << " / tile size =" << TIFFTileSize(image)
1167 << " / tile width =" << tileWidth
1168 << " tileSize/tileHeight =" << tileSize / tileHeight;
1169
1170 dbgFile << " NbOfTiles =" << TIFFNumberOfTiles(image)
1171 << " tileWidth =" << tileWidth << " tileSize =" << tileSize;
1172
1173 for (y = 0; y < height; y += tileHeight) {
1174 for (x = 0; x < width; x += tileWidth) {
1175 dbgFile << "Reading tile x =" << x << " y =" << y;
1176#ifdef HAVE_JPEG_TURBO
1177 if (planarconfig == PLANARCONFIG_CONTIG
1178 && !(color_type == PHOTOMETRIC_YCBCR
1179 && compression == COMPRESSION_JPEG && hsubsampling != 1
1180 && vsubsampling != 1)) {
1181#else
1182 if (planarconfig == PLANARCONFIG_CONTIG) {
1183#endif
1184 TIFFReadTile(image, buf.get(), x, y, 0, (tsample_t)-1);
1185#ifdef HAVE_JPEG_TURBO
1186 } else if (planarconfig == PLANARCONFIG_CONTIG
1187 && (color_type == PHOTOMETRIC_YCBCR
1188 && compression == COMPRESSION_JPEG)) {
1189 uint32_t tile =
1190 TIFFComputeTile(image, x, y, 0, (tsample_t)-1);
1191 TIFFReadRawTile(image, tile, jpegBuf.data(), tileSize);
1192
1193 int width = tileWidth;
1194 int height = tileHeight;
1195 int jpegSubsamp = TJ_444;
1196 int jpegColorspace = TJCS_YCbCr;
1197
1198 if (tjDecompressHeader3(handle.get(),
1199 jpegBuf.data(),
1200 tileSize,
1201 &width,
1202 &height,
1203 &jpegSubsamp,
1204 &jpegColorspace)
1205 != 0) {
1206 errFile << tjGetErrorStr2(handle.get());
1208 }
1209
1210 if (tjDecompressToYUVPlanes(handle.get(),
1211 jpegBuf.data(),
1212 tileSize,
1213 ps_buf->data(),
1214 width,
1215 nullptr,
1216 height,
1217 0)
1218 != 0) {
1219 errFile << tjGetErrorStr2(handle.get());
1221 }
1222#endif
1223 } else {
1224 for (uint16_t i = 0; i < nbchannels; i++) {
1225 TIFFReadTile(image, (*ps_buf)[i], x, y, 0, i);
1226 }
1227 }
1228 uint32_t realTileWidth =
1229 (x + tileWidth) < width ? tileWidth : width - x;
1230 for (uint32_t yintile = 0;
1231 yintile < tileHeight && y + yintile < height;) {
1232 uint32_t linesread =
1233 tiffReader->copyDataToChannels(x,
1234 y + yintile,
1235 realTileWidth,
1236 tiffstream);
1237 yintile += linesread;
1238 tiffstream->moveToLine(yintile);
1239 }
1240 tiffstream->restart();
1241 }
1242 }
1243 } else {
1244 dbgFile << "striped image";
1245 tsize_t stripsize = TIFFStripSize(image);
1246 uint32_t rowsPerStrip = 0;
1247 TIFFGetFieldDefaulted(image, TIFFTAG_ROWSPERSTRIP, &rowsPerStrip);
1248 dbgFile << rowsPerStrip << "" << height;
1249 rowsPerStrip =
1250 qMin(rowsPerStrip,
1251 height); // when TIFFNumberOfStrips(image) == 1 it might happen
1252 // that rowsPerStrip is incorrectly set
1253 if (planarconfig == PLANARCONFIG_CONTIG
1254 && !(color_type == PHOTOMETRIC_YCBCR
1255 && compression == COMPRESSION_JPEG && hsubsampling != 1
1256 && vsubsampling != 1)) {
1257 buf.reset(_TIFFmalloc(stripsize));
1258 if (depth < 16) {
1259 tiffstream =
1261 static_cast<uint8_t *>(buf.get()),
1262 depth,
1263 stripsize / rowsPerStrip);
1264 } else if (depth < 32) {
1265 tiffstream =
1267 static_cast<uint8_t *>(buf.get()),
1268 depth,
1269 stripsize / rowsPerStrip);
1270 } else {
1271 tiffstream =
1273 static_cast<uint8_t *>(buf.get()),
1274 depth,
1275 stripsize / rowsPerStrip);
1276 }
1277 } else if (planarconfig == PLANARCONFIG_CONTIG
1278 && color_type == PHOTOMETRIC_YCBCR
1279 && compression == COMPRESSION_JPEG) {
1280#ifdef HAVE_JPEG_TURBO
1281 jpegBuf.resize(stripsize);
1282 ps_buf->resize(nbchannels);
1283 TIFFReadRawStrip(image, 0, jpegBuf.data(), stripsize);
1284
1285 int width = basicInfo.width;
1286 int height = rowsPerStrip;
1287 int jpegSubsamp = TJ_444;
1288 int jpegColorspace = TJCS_YCbCr;
1289
1290 if (tjDecompressHeader3(handle.get(),
1291 jpegBuf.data(),
1292 stripsize,
1293 &width,
1294 &height,
1295 &jpegSubsamp,
1296 &jpegColorspace)
1297 != 0) {
1298 errFile << tjGetErrorStr2(handle.get());
1300 }
1301
1302 QVector<tsize_t> lineSizes(nbchannels);
1303 for (uint32_t i = 0; i < nbchannels; i++) {
1304 const unsigned long uncompressedStripsize =
1305 tjPlaneSizeYUV(i, width, 0, height, jpegColorspace);
1307 uncompressedStripsize != (unsigned long)-1,
1309 dbgFile << QString("Uncompressed strip size (plane %1): %2")
1310 .arg(i)
1311 .arg(uncompressedStripsize);
1312 tsize_t scanLineSize = uncompressedStripsize / rowsPerStrip;
1313 dbgFile << QString("scan line size (plane %1): %2")
1314 .arg(i)
1315 .arg(scanLineSize);
1316 (*ps_buf)[i] = static_cast<uint8_t*>(_TIFFmalloc(uncompressedStripsize));
1317 lineSizes[i] = scanLineSize;
1318 }
1320 ps_buf->data(),
1321 nbchannels,
1322 depth,
1323 lineSizes.data(),
1324 hsubsampling,
1325 vsubsampling);
1326#else
1327 m_doc->setErrorMessage(
1328 i18nc("TIFF",
1329 "Subsampled YCbCr TIFF files compressed with JPEG cannot "
1330 "be loaded."));
1332#endif
1333 } else {
1334 ps_buf->resize(nbchannels);
1335 tsize_t scanLineSize = stripsize / rowsPerStrip;
1336 dbgFile << " scanLineSize for each plan =" << scanLineSize;
1337 QVector<tsize_t> lineSizes(nbchannels);
1338 for (uint32_t i = 0; i < nbchannels; i++) {
1339 (*ps_buf)[i] = static_cast<uint8_t*>(_TIFFmalloc(stripsize));
1340 lineSizes[i] = scanLineSize / lineSizeCoeffs[i];
1341 }
1343 ps_buf->data(),
1344 nbchannels,
1345 depth,
1346 lineSizes.data());
1347 }
1348
1349 dbgFile << "Scanline size =" << TIFFRasterScanlineSize(image)
1350 << " / strip size =" << TIFFStripSize(image)
1351 << " / rowsPerStrip =" << rowsPerStrip
1352 << " stripsize/rowsPerStrip =" << stripsize / rowsPerStrip;
1353 uint32_t y = 0;
1354 dbgFile << " NbOfStrips =" << TIFFNumberOfStrips(image)
1355 << " rowsPerStrip =" << rowsPerStrip
1356 << " stripsize =" << stripsize;
1357
1358 for (uint32_t strip = 0; y < height; strip++) {
1359#ifdef HAVE_JPEG_TURBO
1360 if (planarconfig == PLANARCONFIG_CONTIG
1361 && !(color_type == PHOTOMETRIC_YCBCR
1362 && compression == COMPRESSION_JPEG && hsubsampling != 1
1363 && vsubsampling != 1)) {
1364#else
1365 if (planarconfig == PLANARCONFIG_CONTIG) {
1366#endif
1367 TIFFReadEncodedStrip(image,
1368 TIFFComputeStrip(image, y, 0),
1369 buf.get(),
1370 (tsize_t)-1);
1371#ifdef HAVE_JPEG_TURBO
1372 } else if (planarconfig == PLANARCONFIG_CONTIG
1373 && (color_type == PHOTOMETRIC_YCBCR
1374 && compression == COMPRESSION_JPEG)) {
1375 TIFFReadRawStrip(image, strip, jpegBuf.data(), stripsize);
1376
1377 int width = basicInfo.width;
1378 int height = rowsPerStrip;
1379 int jpegSubsamp = TJ_444;
1380 int jpegColorspace = TJCS_YCbCr;
1381
1382 if (tjDecompressHeader3(handle.get(),
1383 jpegBuf.data(),
1384 stripsize,
1385 &width,
1386 &height,
1387 &jpegSubsamp,
1388 &jpegColorspace)
1389 != 0) {
1390 errFile << tjGetErrorStr2(handle.get());
1392 }
1393
1394 if (tjDecompressToYUVPlanes(
1395 handle.get(),
1396 jpegBuf.data(),
1397 stripsize,
1398 ps_buf->data(),
1399 width,
1400 nullptr,
1401 height,
1402 0)
1403 != 0) {
1404 errFile << tjGetErrorStr2(handle.get());
1406 }
1407#endif
1408 } else {
1409 for (uint16_t i = 0; i < nbchannels; i++) {
1410 TIFFReadEncodedStrip(image,
1411 TIFFComputeStrip(image, y, i),
1412 (*ps_buf)[i],
1413 (tsize_t)-1);
1414 }
1415 }
1416 for (uint32_t yinstrip = 0;
1417 yinstrip < rowsPerStrip && y < height;) {
1418 uint32_t linesread =
1419 tiffReader->copyDataToChannels(0, y, width, tiffstream);
1420 y += linesread;
1421 yinstrip += linesread;
1422 tiffstream->moveToLine(yinstrip);
1423 }
1424 tiffstream->restart();
1425 }
1426 }
1427 tiffReader->finalize();
1428 tiffReader.reset();
1429 tiffstream.reset();
1430 ps_buf.reset();
1431
1433
1434 layer->paintDevice()->setX(static_cast<int>(basicInfo.x * basicInfo.xres));
1435 layer->paintDevice()->setY(static_cast<int>(basicInfo.y * basicInfo.yres));
1436
1437 // Process rotation before handing image over
1438 // https://developer.apple.com/documentation/imageio/cgimagepropertyorientation
1439 switch (orientation) {
1440 case ORIENTATION_TOPRIGHT:
1442 break;
1443 case ORIENTATION_BOTRIGHT:
1445 break;
1446 case ORIENTATION_BOTLEFT:
1448 break;
1449 case ORIENTATION_LEFTTOP:
1450 m_image->rotateImage(M_PI / 2);
1452 break;
1453 case ORIENTATION_RIGHTTOP:
1454 m_image->rotateImage(M_PI / 2);
1455 break;
1456 case ORIENTATION_RIGHTBOT:
1457 m_image->rotateImage(M_PI / 2);
1459 break;
1460 case ORIENTATION_LEFTBOT:
1461 m_image->rotateImage(-M_PI / 2 + M_PI * 2);
1462 break;
1463 default:
1464 break;
1465 }
1466
1467 // Process IPTC metadata
1468 if (iptc_profile_size > 0 && iptc_profile_data != nullptr) {
1469 dbgFile << "Loading IPTC profile. Size: "
1470 << sizeof(uint32_t) * iptc_profile_size;
1471
1472 // warning: profile is an array of uint32_t's
1473 if (TIFFIsByteSwapped(image) != 0) {
1474 TIFFSwabArrayOfLong(iptc_profile_data,
1475 iptc_profile_size / sizeof(uint32_t));
1476 }
1477
1478 KisMetaData::IOBackend *iptcIO =
1480
1481 // Copy the xmp data into the byte array
1482 QByteArray ba(reinterpret_cast<const char *>(iptc_profile_data),
1483 static_cast<int>(iptc_profile_size));
1484 QBuffer buf(&ba);
1485 iptcIO->loadFrom(layer->metaData(), &buf);
1486 }
1487
1488 // Process XMP metadata
1489 if (xmp_size > 0 && xmp_data != nullptr) {
1490 dbgFile << "Loading XMP data. Size: " << xmp_size;
1491
1492 KisMetaData::IOBackend *xmpIO =
1494
1495 // Copy the xmp data into the byte array
1496 QByteArray ba(reinterpret_cast<char *>(xmp_data),
1497 static_cast<int>(xmp_size));
1498 QBuffer buf(&ba);
1499 xmpIO->loadFrom(layer->metaData(), &buf);
1500 }
1501
1502 return ImportExportCodes::OK;
1503}
const Params2D p
constexpr qreal POINT_TO_CM(qreal px)
Definition KoUnit.h:33
constexpr qreal POINT_TO_INCH(qreal px)
Definition KoUnit.h:37
KisUndoStore * createUndoStore()
KoDocumentInfo * documentInfo() const
void setErrorMessage(const QString &errMsg)
void resizeImage(const QRect &newRect)
start asynchronous operation on resizing the image
Definition kis_image.cc:865
QString nextLayerName(const QString &baseName="") const
Definition kis_image.cc:715
void rotateImage(double radians)
start asynchronous operation on rotating the image
qint32 width() const
qint32 height() const
void setResolution(double xres, double yres)
void setX(qint32 x)
void setY(qint32 y)
static void mirrorY(KisPaintDeviceSP dev, qreal axis)
static void mirrorX(KisPaintDeviceSP dev, qreal axis)
virtual quint32 colorChannelCount() const =0
The class containing all meta information about a document.
void setAboutInfo(const QString &info, const QString &data)
void setAuthorInfo(const QString &info, const QString &data)
#define KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(cond, val)
Definition kis_assert.h:129
#define dbgPlugins
Definition kis_debug.h:51
const quint16 quint16_MAX
Definition kis_global.h:25
const quint8 quint8_MAX
Definition kis_global.h:24
#define M_PI
Definition kis_global.h:111
auto make_unique_with_deleter(T *data, Deleter d)
KisSharedPtr< KisNode > KisNodeSP
Definition kis_types.h:86
int depth(typename Forest< T >::const_child_iterator beginIt, typename Forest< T >::const_child_iterator endIt)
Definition KisForest.h:1213
KisImageWSP image
bool addNode(KisNodeSP node, KisNodeSP parent=KisNodeSP(), KisNodeAdditionFlags flags=KisNodeAdditionFlag::None)
KisPaintDeviceSP paintDevice
QPair< QString, QString > colorSpaceIdTag
TiffResolution resolution
KoColorTransformation * transform
const KoColorSpace * cs

References KisNodeFacade::addNode(), KisTiffBasicInfo::color_type, KoColorSpace::colorChannelCount(), KisTiffBasicInfo::colorSpaceIdTag, KisDocument::createUndoStore(), KisTiffBasicInfo::cs, KisSharedPtr< T >::data(), dbgFile, dbgPlugins, KisTiffBasicInfo::depth, KisDocument::documentInfo(), KisTiffBasicInfo::dstDepth, errFile, KisTiffBasicInfo::extrasamplescount, ImportExportCodes::FileFormatIncorrect, KisImage::height(), KisTiffBasicInfo::height, KisBaseNode::image, INCH, KisMetadataBackendRegistry::instance(), ImportExportCodes::InsufficientMemory, KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE, KisMetaData::IOBackend::loadFrom(), m_image, M_PI, make_unique_with_deleter(), KisLayer::metaData(), KisTransformWorker::mirrorX(), KisTransformWorker::mirrorY(), KisTiffBasicInfo::nbchannels, KisImage::nextLayerName(), ImportExportCodes::OK, p, KisPaintLayer::paintDevice, POINT_TO_CM(), POINT_TO_INCH(), quint16_MAX, quint8_MAX, KisImage::resizeImage(), KisTiffBasicInfo::resolution, KisImage::rootLayer(), KisImage::rotateImage(), KisTiffBasicInfo::sampleinfo, KisTiffBasicInfo::sampletype, KoDocumentInfo::setAboutInfo(), KoDocumentInfo::setAuthorInfo(), KisDocument::setErrorMessage(), KisImage::setResolution(), KisPaintDevice::setX(), KisPaintDevice::setY(), KisTiffBasicInfo::transform, KoGenericRegistry< T >::value(), KisImage::width(), KisTiffBasicInfo::width, KisTiffBasicInfo::x, KisTiffBasicInfo::xres, KisTiffBasicInfo::y, and KisTiffBasicInfo::yres.

◆ readTIFFDirectory()

KisImportExportErrorCode KisTIFFImport::readTIFFDirectory ( KisDocument * m_doc,
TIFF * image )
private

Definition at line 1613 of file kis_tiff_import.cc.

1615{
1616 // Read information about the tiff
1617
1618 KisTiffBasicInfo basicInfo;
1619
1620 if (TIFFGetField(image, TIFFTAG_IMAGEWIDTH, &basicInfo.width) == 0) {
1621 dbgFile << "Image does not define its width";
1623 }
1624
1625 if (TIFFGetField(image, TIFFTAG_IMAGELENGTH, &basicInfo.height) == 0) {
1626 dbgFile << "Image does not define its height";
1628 }
1629
1630 if (TIFFGetField(image, TIFFTAG_XRESOLUTION, &basicInfo.xres) == 0 || basicInfo.xres == 0) {
1631 dbgFile << "Image does not define x resolution";
1632 // but we don't stop
1633 basicInfo.xres = 100;
1634 }
1635
1636 if (TIFFGetField(image, TIFFTAG_YRESOLUTION, &basicInfo.yres) == 0 || basicInfo.yres == 0) {
1637 dbgFile << "Image does not define y resolution";
1638 // but we don't stop
1639 basicInfo.yres = 100;
1640 }
1641
1642 if (TIFFGetField(image, TIFFTAG_RESOLUTIONUNIT, &basicInfo.resolution) == 0) {
1643 dbgFile << "Image does not define resolution unit";
1644 // but we don't stop
1645 basicInfo.resolution = TiffResolution::INCH;
1646 }
1647
1648 if (TIFFGetField(image, TIFFTAG_XPOSITION, &basicInfo.x) == 0) {
1649 dbgFile << "Image does not define a horizontal offset";
1650 basicInfo.x = 0;
1651 }
1652
1653 if (TIFFGetField(image, TIFFTAG_YPOSITION, &basicInfo.y) == 0) {
1654 dbgFile << "Image does not define a vertical offset";
1655 basicInfo.y = 0;
1656 }
1657
1658 if ((TIFFGetField(image, TIFFTAG_BITSPERSAMPLE, &basicInfo.depth) == 0)) {
1659 dbgFile << "Image does not define its depth";
1660 basicInfo.depth = 1;
1661 }
1662
1663 if ((TIFFGetField(image, TIFFTAG_SAMPLEFORMAT, &basicInfo.sampletype)
1664 == 0)) {
1665 dbgFile << "Image does not define its sample type";
1666 basicInfo.sampletype = SAMPLEFORMAT_UINT;
1667 }
1668
1669 // Determine the number of channels (useful to know if a file has an alpha
1670 // or not
1671 if (TIFFGetField(image, TIFFTAG_SAMPLESPERPIXEL, &basicInfo.nbchannels)
1672 == 0) {
1673 dbgFile << "Image has an undefined number of samples per pixel";
1674 basicInfo.nbchannels = 0;
1675 }
1676
1677 // Get the number of extrasamples and information about them
1678 if (TIFFGetField(image,
1679 TIFFTAG_EXTRASAMPLES,
1680 &basicInfo.extrasamplescount,
1681 &basicInfo.sampleinfo)
1682 == 0) {
1683 basicInfo.extrasamplescount = 0;
1684 }
1685
1686 // Determine the colorspace
1687 if (TIFFGetField(image, TIFFTAG_PHOTOMETRIC, &basicInfo.color_type) == 0) {
1688 dbgFile << "Image has an undefined photometric interpretation";
1689 basicInfo.color_type = PHOTOMETRIC_MINISWHITE;
1690 }
1691
1692 basicInfo.colorSpaceIdTag =
1694 basicInfo.color_type,
1695 basicInfo.depth,
1696 image,
1697 basicInfo.nbchannels,
1698 basicInfo.extrasamplescount,
1699 basicInfo.dstDepth);
1700
1701 if (basicInfo.colorSpaceIdTag.first.isEmpty()) {
1702 dbgFile << "Image has an unsupported colorspace :"
1703 << basicInfo.color_type
1704 << " for this depth :" << basicInfo.depth;
1706 }
1707 dbgFile << "Color space is :" << basicInfo.colorSpaceIdTag.first
1708 << basicInfo.colorSpaceIdTag.second << " with a depth of"
1709 << basicInfo.depth << " and with a nb of channels of"
1710 << basicInfo.nbchannels;
1711
1712 // Read image profile
1713 dbgFile << "Reading profile";
1714 const KoColorProfile *profile = nullptr;
1715 quint32 EmbedLen = 0;
1716 uint8_t *EmbedBuffer = nullptr;
1717
1718 if (TIFFGetField(image, TIFFTAG_ICCPROFILE, &EmbedLen, &EmbedBuffer) == 1) {
1719 dbgFile << "Profile found";
1720 QByteArray rawdata(reinterpret_cast<char *>(EmbedBuffer),
1721 static_cast<int>(EmbedLen));
1723 basicInfo.colorSpaceIdTag.first,
1724 basicInfo.colorSpaceIdTag.second,
1725 rawdata);
1726 }
1727
1728 const QString colorSpaceId = KoColorSpaceRegistry::instance()->colorSpaceId(
1729 basicInfo.colorSpaceIdTag.first,
1730 basicInfo.colorSpaceIdTag.second);
1731
1732 // Check that the profile is used by the color space
1733 if (profile
1734 && !KoColorSpaceRegistry::instance()->profileIsCompatible(
1735 profile,
1736 colorSpaceId)) {
1737 dbgFile << "The profile " << profile->name()
1738 << " is not compatible with the color space model "
1739 << basicInfo.colorSpaceIdTag.first << " "
1740 << basicInfo.colorSpaceIdTag.second;
1741 profile = nullptr;
1742 }
1743
1744 // Do not use the linear gamma profile for 16 bits/channel by default, tiff
1745 // files are usually created with gamma correction. XXX: Should we ask the
1746 // user?
1747 if (!profile) {
1748 dbgFile << "No profile found; trying to assign a default one.";
1749 if (basicInfo.colorSpaceIdTag.first == RGBAColorModelID.id()) {
1751 "sRGB-elle-V2-srgbtrc.icc");
1752 } else if (basicInfo.colorSpaceIdTag.first == GrayAColorModelID.id()) {
1754 "Gray-D50-elle-V2-srgbtrc.icc");
1755 } else if (basicInfo.colorSpaceIdTag.first == CMYKAColorModelID.id()) {
1757 "Chemical proof");
1758 } else if (basicInfo.colorSpaceIdTag.first == LABAColorModelID.id()) {
1760 "Lab identity built-in");
1761 } else if (basicInfo.colorSpaceIdTag.first == YCbCrAColorModelID.id()) {
1763 "ITU-R BT.709-6 YCbCr ICC V4 profile");
1764 }
1765 if (!profile) {
1766 dbgFile << "No suitable default profile found.";
1767 }
1768 }
1769
1770 // Retrieve a pointer to the colorspace
1771 if (profile && profile->isSuitableForOutput()) {
1772 dbgFile << "image has embedded profile:" << profile->name() << "";
1774 basicInfo.colorSpaceIdTag.first,
1775 basicInfo.colorSpaceIdTag.second,
1776 profile);
1777 } else {
1778 // Ensure an empty profile name is supplied so that the fallback logic
1779 // in KoColorSpaceRegistry is triggered. BUG:464848
1780 basicInfo.cs = KoColorSpaceRegistry::instance()->colorSpace(basicInfo.colorSpaceIdTag.first,
1781 basicInfo.colorSpaceIdTag.second,
1782 "");
1783 }
1784
1785 if (basicInfo.cs == nullptr) {
1786 dbgFile << "Color space" << basicInfo.colorSpaceIdTag.first
1787 << basicInfo.colorSpaceIdTag.second
1788 << " is not available, please check your installation.";
1790 }
1791
1792 // Create the cmsTransform if needed
1793 if (profile && !profile->isSuitableForOutput()) {
1794 dbgFile << "The profile can't be used in krita, need conversion";
1795 basicInfo.transform =
1797 ->colorSpace(basicInfo.colorSpaceIdTag.first,
1798 basicInfo.colorSpaceIdTag.second,
1799 profile)
1801 basicInfo.cs,
1804 }
1805
1806 KisImportExportErrorCode result = readImageFromPsd(m_doc, image, basicInfo);
1807 if (!result.isOk()) {
1808 result = readImageFromTiff(m_doc, image, basicInfo);
1809 }
1810
1811 return result;
1812}
const KoID YCbCrAColorModelID("YCbCrA", ki18n("YCbCr/Alpha"))
const KoID GrayAColorModelID("GRAYA", ki18n("Grayscale/Alpha"))
const KoID CMYKAColorModelID("CMYKA", ki18n("CMYK/Alpha"))
const KoID LABAColorModelID("LABA", ki18n("L*a*b*/Alpha"))
const KoID RGBAColorModelID("RGBA", ki18n("RGB/Alpha"))
KisImportExportErrorCode readImageFromTiff(KisDocument *m_doc, TIFF *image, KisTiffBasicInfo &basicInfo)
KisImportExportErrorCode readImageFromPsd(KisDocument *m_doc, TIFF *image, KisTiffBasicInfo &basicInfo)
virtual KoColorConversionTransformation * createColorConverter(const KoColorSpace *dstColorSpace, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags) const
QString id() const
Definition KoID.cpp:63
QString getColorSpaceForColorType(uint16_t sampletype, uint16_t color_type, uint16_t color_nb_bits, TIFF *image, uint16_t &nbchannels, uint16_t &extrasamplescount, uint8_t &destDepth)
virtual bool isSuitableForOutput() const =0
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 * createColorProfile(const QString &colorModelId, const QString &colorDepthId, const QByteArray &rawData)

References CMYKAColorModelID, KisTiffBasicInfo::color_type, KoColorSpaceRegistry::colorSpace(), KoColorSpaceRegistry::colorSpaceId(), KisTiffBasicInfo::colorSpaceIdTag, KoColorSpace::createColorConverter(), KoColorSpaceRegistry::createColorProfile(), KisTiffBasicInfo::cs, dbgFile, KisTiffBasicInfo::depth, KisTiffBasicInfo::dstDepth, KisTiffBasicInfo::extrasamplescount, ImportExportCodes::FileFormatIncorrect, ImportExportCodes::FormatColorSpaceUnsupported, getColorSpaceForColorType(), GrayAColorModelID, KisTiffBasicInfo::height, KoID::id(), INCH, KoColorSpaceRegistry::instance(), KoColorConversionTransformation::internalConversionFlags(), KoColorConversionTransformation::internalRenderingIntent(), KisImportExportErrorCode::isOk(), KoColorProfile::isSuitableForOutput(), LABAColorModelID, KoColorProfile::name, KisTiffBasicInfo::nbchannels, KoColorSpaceRegistry::profileByName(), readImageFromPsd(), readImageFromTiff(), KisTiffBasicInfo::resolution, RGBAColorModelID, KisTiffBasicInfo::sampleinfo, KisTiffBasicInfo::sampletype, KisTiffBasicInfo::transform, KisTiffBasicInfo::width, KisTiffBasicInfo::x, KisTiffBasicInfo::xres, KisTiffBasicInfo::y, YCbCrAColorModelID, and KisTiffBasicInfo::yres.

◆ supportsIO()

bool KisTIFFImport::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 29 of file kis_tiff_import.h.

29{ return false; }

Member Data Documentation

◆ m_image

KisImageSP KisTIFFImport::m_image
private

Definition at line 66 of file kis_tiff_import.h.

◆ m_photoshopBlockParsed

bool KisTIFFImport::m_photoshopBlockParsed = false
private

Definition at line 67 of file kis_tiff_import.h.

◆ oldErrHandler

TIFFErrorHandler KisTIFFImport::oldErrHandler = nullptr
private

Definition at line 69 of file kis_tiff_import.h.

◆ oldWarnHandler

TIFFErrorHandler KisTIFFImport::oldWarnHandler = nullptr
private

Definition at line 70 of file kis_tiff_import.h.


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