Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_tiff_import.cc
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2005 Cyrille Berger <cberger@cberger.net>
3 * SPDX-FileCopyrightText: 2022 L. E. Segovia <amy@amyspark.me>
4 *
5 * SPDX-License-Identifier: GPL-2.0-or-later
6 */
7
8#include "kis_tiff_import.h"
10#include "kis_assert.h"
11
12#include <QBuffer>
13#include <QPair>
14#include <QSharedPointer>
15#include <QStack>
16
17#include <array>
18
19#include <exiv2/exiv2.hpp>
20#include <kpluginfactory.h>
21#ifdef Q_OS_WIN
22#include <io.h>
23#endif
24#include <tiffio.h>
25
26#include <KisDocument.h>
28#include <KisViewManager.h>
29#include <KoColorProfile.h>
30#include <KoDocumentInfo.h>
31#include <KoUnit.h>
32#include <KisExiv2IODevice.h>
33#include <kis_group_layer.h>
34#include <kis_image.h>
36#include <kis_meta_data_tags.h>
37#include <kis_paint_layer.h>
40
41#ifdef TIFF_HAS_PSD_TAGS
42#include <psd_resource_block.h>
43
46
48#include <QMessageBox>
49#endif /* TIFF_HAS_PSD_TAGS */
50
51#ifdef HAVE_JPEG_TURBO
52#include <turbojpeg.h>
53#endif
54
55#include "kis_buffer_stream.h"
56#include "kis_tiff_logger.h"
57#include "kis_tiff_reader.h"
59
60enum class TiffResolution : quint8 {
61 NONE = RESUNIT_NONE,
62 INCH = RESUNIT_INCH,
63 CM = RESUNIT_CENTIMETER,
64};
65
67 uint32_t width{};
68 uint32_t height{};
69 float x{};
70 float y{};
71 float xres{};
72 float yres{};
73 uint16_t depth{};
74 uint16_t sampletype{};
75 uint16_t nbchannels{};
76 uint16_t color_type{};
77 uint16_t *sampleinfo = nullptr;
78 uint16_t extrasamplescount = 0;
79 const KoColorSpace *cs = nullptr;
80 QPair<QString, QString> colorSpaceIdTag;
82 uint8_t dstDepth{};
84};
85
87 "krita_tiff_import.json",
88 registerPlugin<KisTIFFImport>();)
89
90QPair<QString, QString> getColorSpaceForColorType(uint16_t sampletype,
91 uint16_t color_type,
92 uint16_t color_nb_bits,
93 TIFF *image,
94 uint16_t &nbchannels,
95 uint16_t &extrasamplescount,
96 uint8_t &destDepth)
97{
98 const int bits32 = 32;
99 const int bits16 = 16;
100 const int bits8 = 8;
101
102 if (sampletype == SAMPLEFORMAT_INT) {
103 dbgFile << "Detected signed TIFF image" << color_type << color_nb_bits;
104 }
105
106 if (color_type == PHOTOMETRIC_MINISWHITE
107 || color_type == PHOTOMETRIC_MINISBLACK) {
108 if (nbchannels == 0)
109 nbchannels = 1;
110 extrasamplescount =
111 nbchannels - 1; // FIX the extrasamples count in case of
112 if (sampletype == SAMPLEFORMAT_IEEEFP) {
113 if (color_nb_bits == 16) {
114#ifdef HAVE_OPENEXR
115 destDepth = 16;
117#endif
118 } else if (color_nb_bits == 32) {
119 destDepth = 32;
121 }
122 return {}; // sanity check; no support for float of
123 // higher or lower bit depth
124 }
125 if (color_nb_bits <= 8) {
126 destDepth = 8;
128 } else /* if (color_nb_bits == bits16) */ {
129 destDepth = 16;
131 }
132
133 } else if (color_type == PHOTOMETRIC_RGB /*|| color_type == */) {
134 if (nbchannels == 0)
135 nbchannels = 3;
136 extrasamplescount =
137 nbchannels - 3; // FIX the extrasamples count in case of
138 if (sampletype == SAMPLEFORMAT_IEEEFP) {
139 if (color_nb_bits == 16) {
140#ifdef HAVE_OPENEXR
141 destDepth = 16;
143#endif
144 } else if (color_nb_bits == 32) {
145 destDepth = 32;
147 }
148 return {}; // sanity check; no support for float of
149 // higher or lower bit depth
150 } else {
151 if (color_nb_bits <= 8) {
152 destDepth = 8;
154 } else /* if (color_nb_bits == bits16) */ {
155 destDepth = 16;
157 }
158 }
159 } else if (color_type == PHOTOMETRIC_YCBCR) {
160 if (nbchannels == 0)
161 nbchannels = 3;
162 extrasamplescount =
163 nbchannels - 3; // FIX the extrasamples count in case of
164 if (sampletype == SAMPLEFORMAT_IEEEFP) {
165 if (color_nb_bits == 16) {
166#ifdef HAVE_OPENEXR
167 destDepth = 16;
169#endif
170 } else if (color_nb_bits == 32) {
171 destDepth = 32;
173 }
174 return {}; // sanity check; no support for float of
175 // higher or lower bit depth
176 } else {
177 if (color_nb_bits <= 8) {
178 destDepth = 8;
180 } else /* if (color_nb_bits == bits16) */ {
181 destDepth = 16;
182 return {YCbCrAColorModelID.id(),
184 }
185 }
186 if (color_nb_bits <= 8) {
187 destDepth = 8;
189 } else if (color_nb_bits == bits16) {
190 destDepth = 16;
192 } else {
193 return {}; // sanity check; no support
194 // integers of higher bit depth
195 }
196 } else if (color_type == PHOTOMETRIC_SEPARATED) {
197 if (nbchannels == 0)
198 nbchannels = 4;
199 // SEPARATED is in general CMYK but not always, so we check
200 uint16_t inkset = 0;
201 if ((TIFFGetField(image, TIFFTAG_INKSET, &inkset) == 0)) {
202 dbgFile << "Image does not define the inkset.";
203 inkset = 2;
204 }
205 if (inkset != INKSET_CMYK) {
206 dbgFile << "Unsupported inkset (right now, only CMYK is supported)";
207 char **ink_names = nullptr;
208 uint16_t numberofinks = 0;
209 if (TIFFGetField(image, TIFFTAG_INKNAMES, &ink_names) == 1
210 && TIFFGetField(image, TIFFTAG_NUMBEROFINKS, &numberofinks)
211 == 1) {
212 dbgFile << "Inks are :";
213 for (uint32_t i = 0; i < numberofinks; i++) {
214 dbgFile << ink_names[i];
215 }
216 } else {
217 dbgFile << "inknames are not defined !";
218 // To be able to read stupid adobe files, if there are no
219 // information about inks and four channels, then it's a CMYK
220 // file :
221 if (nbchannels - extrasamplescount != 4) {
222 return {};
223 }
224 // else - assume it's CMYK and proceed
225 }
226 }
227 if (sampletype == SAMPLEFORMAT_IEEEFP) {
228 if (color_nb_bits == 16) {
229#ifdef HAVE_OPENEXR
230 destDepth = 16;
232#endif
233 } else if (color_nb_bits == 32) {
234 destDepth = 32;
236 }
237 return {}; // sanity check; no support for float of
238 // higher or lower bit depth
239 }
240 if (color_nb_bits <= 8) {
241 destDepth = 8;
243 } else if (color_nb_bits == 16) {
244 destDepth = 16;
246 } else {
247 return {}; // no support for other bit depths
248 }
249 } else if (color_type == PHOTOMETRIC_CIELAB
250 || color_type == PHOTOMETRIC_ICCLAB) {
251 if (nbchannels == 0)
252 nbchannels = 3;
253 extrasamplescount = nbchannels - 3; // FIX the extrasamples count
254
255 switch (color_nb_bits) {
256 case bits32: {
257 destDepth = bits32;
258 if (sampletype == SAMPLEFORMAT_IEEEFP) {
260 } else {
261 return {}; // no support for other bit depths
262 }
263 }
264 case bits16: {
265 destDepth = bits16;
266 if (sampletype == SAMPLEFORMAT_IEEEFP) {
267#ifdef HAVE_OPENEXR
269#endif
270 } else {
272 }
273 return {}; // no support for other bit depths
274 }
275 case bits8: {
276 destDepth = bits8;
278 }
279 default: {
280 return {};
281 }
282 }
283 } else if (color_type == PHOTOMETRIC_PALETTE) {
284 destDepth = 16;
285 if (nbchannels == 0)
286 nbchannels = 2;
287 extrasamplescount = nbchannels - 2; // FIX the extrasamples count
288 // <-- we will convert the index image to RGBA16 as the palette is
289 // always on 16bits colors
291 }
292 return {};
293}
294
295template<template<typename> class T>
297makePostProcessor(uint32_t nbsamples, const QPair<QString, QString> &id)
298{
299 if (id.second == Integer8BitsColorDepthID.id()) {
300 return QSharedPointer<T<uint8_t>>::create(nbsamples);
301 } else if (id.second == Integer16BitsColorDepthID.id()) {
302 return QSharedPointer<T<uint16_t>>::create(nbsamples);
303#ifdef HAVE_OPENEXR
304 } else if (id.second == Float16BitsColorDepthID.id()) {
305 return QSharedPointer<T<half>>::create(nbsamples);
306#endif
307 } else if (id.second == Float32BitsColorDepthID.id()) {
308 return QSharedPointer<T<float>>::create(nbsamples);
309 } else {
310 KIS_ASSERT(false && "TIFF does not support this bit depth!");
311 return {};
312 }
313}
314
315KisTIFFImport::KisTIFFImport(QObject *parent, const QVariantList &)
316 : KisImportExportFilter(parent)
317 , m_image(nullptr)
318 , oldErrHandler(TIFFSetErrorHandler(&KisTiffErrorHandler))
319 , oldWarnHandler(TIFFSetWarningHandler(&KisTiffWarningHandler))
320{
321}
322
324{
325 TIFFSetErrorHandler(oldErrHandler);
326 TIFFSetWarningHandler(oldWarnHandler);
327}
328
329template<typename T, typename Deleter>
330auto make_unique_with_deleter(T *data, Deleter d)
331{
332 return std::unique_ptr<T, Deleter>(data, d);
333}
334
335#ifdef TIFF_HAS_PSD_TAGS
336KisImportExportErrorCode KisTIFFImport::readImageFromPsdRecords(
337 KisDocument *m_doc,
338 const KisTiffPsdLayerRecord &photoshopLayerRecord,
339 KisTiffPsdResourceRecord &photoshopImageResourceRecord,
340 QBuffer &photoshopLayerData,
341 const KisTiffBasicInfo &basicInfo)
342{
343 QMap<KisTiffPsdResourceRecord::PSDResourceID, PSDResourceBlock *>
344 &resources = photoshopImageResourceRecord.resources;
345
346 const KoColorSpace *cs = basicInfo.cs;
347
348 // Attempt to get the ICC profile from the image resource section
349 if (resources.contains(KisTiffPsdResourceRecord::ICC_PROFILE)) {
350 const KoColorProfile *profile = nullptr;
351
352 // Use the color mode from the synthetic PSD header
353 QPair<QString, QString> colorSpaceId =
354 psd_colormode_to_colormodelid(photoshopLayerRecord.colorMode(),
355 photoshopLayerRecord.channelDepth());
356
357 if (colorSpaceId.first.isNull()) {
358 dbgFile << "Inconsistent PSD metadata, the color space"
359 << photoshopLayerRecord.colorMode()
360 << photoshopLayerRecord.channelDepth()
361 << "does not exist; falling back to the synthetic header "
362 "information";
363 colorSpaceId = basicInfo.colorSpaceIdTag;
364 }
365
366 ICC_PROFILE_1039 *iccProfileData = dynamic_cast<ICC_PROFILE_1039 *>(
367 resources[KisTiffPsdResourceRecord::ICC_PROFILE]->resource);
368 if (iccProfileData) {
370 colorSpaceId.first,
371 colorSpaceId.second,
372 iccProfileData->icc);
373 dbgFile << "Loaded ICC profile from PSD" << profile->name();
374 delete resources.take(KisTiffPsdResourceRecord::ICC_PROFILE);
375 }
376
377 if (profile) {
378 const KoColorSpace *tempCs =
380 colorSpaceId.first,
381 colorSpaceId.second,
382 profile);
383 if (tempCs) {
384 // Profile found, override the colorspace
385 dbgFile << "TIFF: PSD metadata overrides the color space!"
386 << cs->name() << cs->profile()->name();
387 cs = tempCs;
388 }
389 }
390 }
391
392 KisImageSP psdImage = new KisImage(m_doc->createUndoStore(),
393 static_cast<qint32>(basicInfo.width),
394 static_cast<qint32>(basicInfo.height),
395 cs,
396 "built image");
399
400 psdImage->setResolution(
401 POINT_TO_INCH(static_cast<qreal>(basicInfo.xres)),
402 POINT_TO_INCH(static_cast<qreal>(
403 basicInfo.yres))); // It is the "invert" macro because we convert
404 // from pointer-per-inch to points
405
406 // set the correct resolution
407 if (resources.contains(KisTiffPsdResourceRecord::RESN_INFO)) {
408 RESN_INFO_1005 *resInfo = dynamic_cast<RESN_INFO_1005 *>(
409 resources[KisTiffPsdResourceRecord::RESN_INFO]->resource);
410 if (resInfo) {
411 // check resolution size is not zero
412 if (resInfo->hRes * resInfo->vRes > 0)
413 psdImage->setResolution(POINT_TO_INCH(resInfo->hRes),
414 POINT_TO_INCH(resInfo->vRes));
415 // let's skip the unit for now; we can only set that on the
416 // KisDocument, and krita doesn't use it.
417 delete resources.take(KisTiffPsdResourceRecord::RESN_INFO);
418 }
419 }
420
421 // Preserve all the annotations
422 for (const auto &resourceBlock : resources.values()) {
423 psdImage->addAnnotation(resourceBlock);
424 }
425
426 dbgFile << "Loading Photoshop layers";
427
428 QStack<KisGroupLayerSP> groupStack;
429
430 groupStack << psdImage->rootLayer().data();
431
438 KisNodeSP lastAddedLayer;
439
440 using LayerStyleMapping = QPair<QDomDocument, KisLayerSP>;
441 QVector<LayerStyleMapping> allStylesXml;
442
443 const std::shared_ptr<PSDLayerMaskSection> &layerSection =
444 photoshopLayerRecord.record();
445
446 KIS_SAFE_ASSERT_RECOVER(layerSection->nLayers != 0)
447 {
449 }
450
451 for (int i = 0; i != layerSection->nLayers; i++) {
452 PSDLayerRecord *layerRecord = layerSection->layers.at(i);
453 dbgFile << "Going to read channels for layer" << i
454 << layerRecord->layerName;
455 KisLayerSP newLayer;
456 if (layerRecord->infoBlocks.keys.contains("lsct")
457 && layerRecord->infoBlocks.sectionDividerType != psd_other) {
458 if (layerRecord->infoBlocks.sectionDividerType
460 && !groupStack.isEmpty()) {
461 KisGroupLayerSP groupLayer =
462 new KisGroupLayer(psdImage, "temp", OPACITY_OPAQUE_U8);
463 psdImage->addNode(groupLayer, groupStack.top());
464 groupStack.push(groupLayer);
465 newLayer = groupLayer;
466 } else if ((layerRecord->infoBlocks.sectionDividerType
468 || layerRecord->infoBlocks.sectionDividerType
470 && (groupStack.size() > 1
471 || (lastAddedLayer && !groupStack.isEmpty()))) {
472 KisGroupLayerSP groupLayer;
473
474 if (groupStack.size() <= 1) {
475 groupLayer =
476 new KisGroupLayer(psdImage, "temp", OPACITY_OPAQUE_U8);
477 psdImage->addNode(groupLayer, groupStack.top());
478 psdImage->moveNode(lastAddedLayer, groupLayer, KisNodeSP());
479 } else {
480 groupLayer = groupStack.pop();
481 }
482
483 const QDomDocument &styleXml =
484 layerRecord->infoBlocks.layerStyleXml;
485
486 if (!styleXml.isNull()) {
487 allStylesXml << LayerStyleMapping(styleXml, groupLayer);
488 }
489
490 groupLayer->setName(layerRecord->layerName);
491 groupLayer->setVisible(layerRecord->visible);
492
493 QString compositeOp = psd_blendmode_to_composite_op(
495
496 // Krita doesn't support pass-through blend
497 // mode. Instead it is just a property of a group
498 // layer, so flip it
499 if (compositeOp == COMPOSITE_PASS_THROUGH) {
500 compositeOp = COMPOSITE_OVER;
501 groupLayer->setPassThroughMode(true);
502 }
503
504 groupLayer->setCompositeOpId(compositeOp);
505
506 newLayer = groupLayer;
507 } else {
518 warnKrita << "WARNING: Provided PSD has unbalanced group "
519 << "layer markers. Some masks and/or layers can "
520 << "be lost while loading this file. Please "
521 << "report a bug to Krita developers and attach "
522 << "this file to the bugreport\n"
523 << " " << ppVar(layerRecord->layerName) << "\n"
524 << " "
525 << ppVar(layerRecord->infoBlocks.sectionDividerType)
526 << "\n"
527 << " " << ppVar(groupStack.size());
528 continue;
529 }
530 } else {
531 KisPaintLayerSP layer = new KisPaintLayer(psdImage,
532 layerRecord->layerName,
533 layerRecord->opacity);
534 layer->setCompositeOpId(
536
537 const QDomDocument &styleXml =
538 layerRecord->infoBlocks.layerStyleXml;
539
540 if (!styleXml.isNull()) {
541 allStylesXml << LayerStyleMapping(styleXml, layer);
542 }
543
544 // XXX: does this require endianness handling?
545 if (!layerRecord->readPixelData(photoshopLayerData,
546 layer->paintDevice())) {
547 dbgFile << "failed reading channels for layer: "
548 << layerRecord->layerName << layerRecord->error;
550 }
551
552 if (!groupStack.isEmpty()) {
553 psdImage->addNode(layer, groupStack.top());
554 } else {
555 psdImage->addNode(layer, psdImage->root());
556 }
557 layer->setVisible(layerRecord->visible);
558 newLayer = layer;
559 }
560
561 for (ChannelInfo *channelInfo : layerRecord->channelInfoRecords) {
562 if (channelInfo->channelId < -1) {
564 new KisTransparencyMask(psdImage,
565 i18n("Transparency Mask"));
566 mask->initSelection(newLayer);
567 if (!layerRecord->readMask(photoshopLayerData,
568 mask->paintDevice(),
569 channelInfo)) {
570 dbgFile << "failed reading masks for layer: "
571 << layerRecord->layerName << layerRecord->error;
572 }
573 psdImage->addNode(mask, newLayer);
574 }
575 }
576
577 lastAddedLayer = newLayer;
578 }
579
580 // Only assign the image if the parsing was successful (for fallback
581 // purposes)
582 this->m_image = psdImage;
583 // Photoshop images only have one IFD plus the layer blob
584 // Ward off inconsistencies by blocking future attempts to parse them
585 this->m_photoshopBlockParsed = true;
586
588}
589#endif
590
593 TIFF *image,
594 KisTiffBasicInfo &basicInfo)
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}
1504
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}
1612
1614 TIFF *image)
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}
1813
1816 QIODevice * /*io*/,
1817 KisPropertiesConfigurationSP /*configuration*/)
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}
1967
1968#include <kis_tiff_import.moc>
qreal length(const QPointF &vec)
Definition Ellipse.cc:82
const Params2D p
const KoID Float32BitsColorDepthID("F32", ki18n("32-bit float/channel"))
const KoID YCbCrAColorModelID("YCbCrA", ki18n("YCbCr/Alpha"))
const KoID GrayAColorModelID("GRAYA", ki18n("Grayscale/Alpha"))
const KoID Float16BitsColorDepthID("F16", ki18n("16-bit float/channel"))
const KoID Integer8BitsColorDepthID("U8", ki18n("8-bit integer/channel"))
const KoID Integer16BitsColorDepthID("U16", ki18n("16-bit integer/channel"))
const KoID CMYKAColorModelID("CMYKA", ki18n("CMYK/Alpha"))
const KoID LABAColorModelID("LABA", ki18n("L*a*b*/Alpha"))
const KoID RGBAColorModelID("RGBA", ki18n("RGB/Alpha"))
const quint8 OPACITY_OPAQUE_U8
const QString COMPOSITE_OVER
const QString COMPOSITE_PASS_THROUGH
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)
Exiv2::BasicIo::AutoPtr ptr_type
void resizeImage(const QRect &newRect)
start asynchronous operation on resizing the image
Definition kis_image.cc:865
void addAnnotation(KisAnnotationSP annotation)
KisGroupLayerSP rootLayer() const
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)
The base class for import and export filters.
KisImportUserFeedbackInterface * importUserFeedBackInterface
virtual Result askUser(AskCallback callback)=0
ask the user a question about the loading process
virtual bool loadFrom(Store *store, QIODevice *ioDevice) const =0
static KisMetadataBackendRegistry * instance()
void setX(qint32 x)
void setY(qint32 y)
TIFFErrorHandler oldErrHandler
KisImportExportErrorCode readTIFFDirectory(KisDocument *m_doc, TIFF *image)
KisImportExportErrorCode readImageFromTiff(KisDocument *m_doc, TIFF *image, KisTiffBasicInfo &basicInfo)
KisImportExportErrorCode convert(KisDocument *document, QIODevice *io, KisPropertiesConfigurationSP configuration=nullptr) override
KisImageSP m_image
KisImportExportErrorCode readImageFromPsd(KisDocument *m_doc, TIFF *image, KisTiffBasicInfo &basicInfo)
~KisTIFFImport() override
TIFFErrorHandler oldWarnHandler
KisTIFFImport(QObject *parent, const QVariantList &)
bool m_photoshopBlockParsed
psd_color_mode colorMode() const
std::shared_ptr< PSDLayerMaskSection > record() const
QMap< PSDResourceID, PSDResourceBlock * > resources
static void mirrorY(KisPaintDeviceSP dev, qreal axis)
static void mirrorX(KisPaintDeviceSP dev, qreal axis)
virtual quint32 colorChannelCount() const =0
virtual const KoColorProfile * profile() const =0
virtual KoColorConversionTransformation * createColorConverter(const KoColorSpace *dstColorSpace, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags) const
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)
const T value(const QString &id) const
QString id() const
Definition KoID.cpp:63
PsdAdditionalLayerInfoBlock infoBlocks
bool readPixelData(QIODevice &io, KisPaintDeviceSP device)
bool readMask(QIODevice &io, KisPaintDeviceSP dev, ChannelInfo *channel)
#define KIS_ASSERT_RECOVER(cond)
Definition kis_assert.h:55
#define KIS_SAFE_ASSERT_RECOVER(cond)
Definition kis_assert.h:126
#define KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(cond, val)
Definition kis_assert.h:129
#define KIS_ASSERT(cond)
Definition kis_assert.h:33
#define errFile
Definition kis_debug.h:115
#define warnKrita
Definition kis_debug.h:87
#define ppVar(var)
Definition kis_debug.h:155
#define dbgMetaData
Definition kis_debug.h:61
#define dbgFile
Definition kis_debug.h:53
#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
QSharedPointer< KisTIFFPostProcessor > makePostProcessor(uint32_t nbsamples, const QPair< QString, QString > &id)
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)
auto make_unique_with_deleter(T *data, Deleter d)
K_PLUGIN_FACTORY_WITH_JSON(TIFFImportFactory, "krita_tiff_import.json", registerPlugin< KisTIFFImport >();) QPair< QString
TiffResolution
void KisTiffWarningHandler(const char *module, const char *fmt, va_list args)
void KisTiffErrorHandler(const char *module, const char *fmt, va_list args)
KisSharedPtr< KisNode > KisNodeSP
Definition kis_types.h:86
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
QPair< QString, QString > psd_colormode_to_colormodelid(psd_color_mode colormode, quint16 channelDepth)
Definition psd.cpp:16
QString psd_blendmode_to_composite_op(const QString &blendmode)
Definition psd.cpp:59
@ psd_other
Definition psd.h:144
@ psd_open_folder
Definition psd.h:144
@ psd_closed_folder
Definition psd.h:144
@ psd_bounding_divider
Definition psd.h:144
virtual void setVisible(bool visible, bool loading=false)
void setName(const QString &name)
KisImageWSP image
void setCompositeOpId(const QString &compositeOpId)
void setPassThroughMode(bool value)
KisMetaData::Store * metaData()
void initSelection(KisSelectionSP copyFrom, KisLayerSP parentLayer)
initSelection initializes the selection for the mask from the given selection's projection.
Definition kis_mask.cc:157
KisPaintDeviceSP paintDevice() const override
Definition kis_mask.cc:223
bool addNode(KisNodeSP node, KisNodeSP parent=KisNodeSP(), KisNodeAdditionFlags flags=KisNodeAdditionFlag::None)
bool moveNode(KisNodeSP node, KisNodeSP parent, KisNodeSP aboveThis)
KisNodeSP firstChild() const
Definition kis_node.cpp:361
KisPaintDeviceSP paintDevice
QPair< QString, QString > colorSpaceIdTag
TiffResolution resolution
KoColorTransformation * transform
const KoColorSpace * cs
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)