File indexing completed on 2024-12-22 04:15:58

0001 /*
0002  *  SPDX-FileCopyrightText: 2006 Cyrille Berger <cberger@cberger.net>
0003  *
0004  *  SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #ifndef _KIS_TIFF_READER_H_
0008 #define _KIS_TIFF_READER_H_
0009 
0010 #include <array>
0011 #include <cmath>
0012 #include <cstdint>
0013 #include <cstdio>
0014 #include <cstring>
0015 #include <limits>
0016 #include <tiffio.h>
0017 #include <type_traits>
0018 #include <utility>
0019 
0020 #include <kis_buffer_stream.h>
0021 #include <kis_debug.h>
0022 #include <kis_global.h>
0023 #include <kis_iterator_ng.h>
0024 #include <kis_paint_device.h>
0025 #include <kis_types.h>
0026 
0027 #include <KoConfig.h>
0028 #ifdef HAVE_OPENEXR
0029 #include <half.h>
0030 #endif // HAVE_OPENEXR
0031 
0032 class KisBufferStreamBase;
0033 
0034 class KisTIFFPostProcessor
0035 {
0036 public:
0037     KisTIFFPostProcessor(uint32_t nbcolorssamples)
0038         : m_nbcolorssamples(nbcolorssamples)
0039     {
0040     }
0041     virtual ~KisTIFFPostProcessor() = default;
0042 
0043 public:
0044     virtual void postProcess(void *) const = 0;
0045 
0046 protected:
0047     inline uint32_t nbColorsSamples() const
0048     {
0049         return m_nbcolorssamples;
0050     }
0051 
0052 private:
0053     uint32_t m_nbcolorssamples;
0054 };
0055 
0056 template<typename T> class KisTIFFPostProcessorDummy : public KisTIFFPostProcessor
0057 {
0058 public:
0059     KisTIFFPostProcessorDummy(uint32_t nbcolorssamples)
0060         : KisTIFFPostProcessor(nbcolorssamples)
0061     {
0062     }
0063     ~KisTIFFPostProcessorDummy() override = default;
0064 
0065     void postProcess(void *) const override
0066     {
0067     }
0068 };
0069 
0070 template<typename T> class KisTIFFPostProcessorInvert : public KisTIFFPostProcessor
0071 {
0072 public:
0073     KisTIFFPostProcessorInvert(uint32_t nbcolorssamples)
0074         : KisTIFFPostProcessor(nbcolorssamples)
0075     {
0076     }
0077     ~KisTIFFPostProcessorInvert() override = default;
0078 
0079 public:
0080     void postProcess(void *data) const override
0081     {
0082         postProcessImpl(reinterpret_cast<T *>(data));
0083     }
0084 
0085 private:
0086     template<typename U = T,
0087              typename std::enable_if<std::numeric_limits<U>::is_signed,
0088                                      void>::type * = nullptr>
0089     inline void postProcessImpl(T *data) const
0090     {
0091         for (uint32_t i = 0; i < this->nbColorsSamples(); i++) {
0092             data[i] = -data[i];
0093         }
0094     }
0095 
0096     template<typename U = T,
0097              typename std::enable_if<!std::numeric_limits<U>::is_signed,
0098                                      void>::type * = nullptr>
0099     inline void postProcessImpl(T *data) const
0100     {
0101         for (uint32_t i = 0; i < this->nbColorsSamples(); i++) {
0102             data[i] = std::numeric_limits<T>::max() - data[i];
0103         }
0104     }
0105 };
0106 
0107 template<typename T> class KisTIFFPostProcessorCIELABtoICCLAB : public KisTIFFPostProcessor
0108 {
0109 public:
0110     KisTIFFPostProcessorCIELABtoICCLAB(uint32_t nbcolorssamples)
0111         : KisTIFFPostProcessor(nbcolorssamples)
0112     {
0113     }
0114     ~KisTIFFPostProcessorCIELABtoICCLAB() override = default;
0115 
0116 public:
0117     void postProcess(void *data) const override
0118     {
0119         postProcessImpl(reinterpret_cast<T *>(data));
0120     }
0121 
0122 private:
0123     template<typename U = T,
0124              typename std::enable_if<!std::numeric_limits<U>::is_integer,
0125                                      void>::type * = nullptr>
0126     inline void postProcessImpl(T *data) const
0127     {
0128         for (uint32_t i = 1; i < this->nbColorsSamples(); i++) {
0129             data[i] += 128.0f;
0130         }
0131     }
0132 
0133     template<typename U = T,
0134              typename std::enable_if<std::numeric_limits<U>::is_integer,
0135                                      void>::type * = nullptr>
0136     inline void postProcessImpl(T *data) const
0137     {
0138         for (uint32_t i = 1; i < this->nbColorsSamples(); i++) {
0139             data[i] += std::numeric_limits<T>::max() / 2;
0140         }
0141     }
0142 };
0143 
0144 class KisTIFFReaderBase
0145 {
0146 public:
0147     KisTIFFReaderBase(KisPaintDeviceSP device,
0148                       const std::array<quint8, 5> &poses,
0149                       int32_t alphapos,
0150                       uint16_t sourceDepth,
0151                       uint16_t sample_format,
0152                       uint16_t nbcolorssamples,
0153                       uint16_t extrasamplescount,
0154                       bool premultipliedAlpha,
0155                       KoColorTransformation *transformProfile,
0156                       QSharedPointer<KisTIFFPostProcessor> postprocessor)
0157         : m_device(device)
0158         , m_alphapos(alphapos)
0159         , m_sourceDepth(sourceDepth)
0160         , m_sample_format(sample_format)
0161         , m_nbcolorssamples(nbcolorssamples)
0162         , m_nbextrasamples(extrasamplescount)
0163         , m_premultipliedAlpha(premultipliedAlpha)
0164         , m_poses(poses)
0165         , m_transformProfile(transformProfile)
0166         , mpostProcessImpl(std::move(postprocessor))
0167     {
0168 
0169     }
0170     virtual ~KisTIFFReaderBase() = default;
0171 
0172 public:
0173     /**
0174      * This function copy data from the tiff stream to the paint device starting at the given position.
0175      * @param x horizontal start position
0176      * @param y vertical start position
0177      * @param dataWidth width of the data to copy
0178      * @param tiffstream source of data
0179      *
0180      * @return the number of line which were copied
0181      */
0182     virtual uint32_t
0183     copyDataToChannels(quint32 x,
0184                        quint32 y,
0185                        quint32 dataWidth,
0186                        QSharedPointer<KisBufferStreamBase> tiffstream) = 0;
0187     /**
0188      * This function is called when all data has been read and should be used for any postprocessing.
0189      */
0190     virtual void finalize()
0191     {
0192     }
0193 
0194 protected:
0195     inline KisPaintDeviceSP paintDevice() const
0196     {
0197         return m_device;
0198     }
0199 
0200     inline qint32 alphaPos() const
0201     {
0202         return m_alphapos;
0203     }
0204 
0205     inline quint16 sourceDepth() const
0206     {
0207         return m_sourceDepth;
0208     }
0209     inline uint16_t sampleFormat() const
0210     {
0211         return m_sample_format;
0212     }
0213 
0214     inline quint16 nbColorsSamples() const
0215     {
0216         return m_nbcolorssamples;
0217     }
0218 
0219     inline quint16 nbExtraSamples() const
0220     {
0221         return m_nbextrasamples;
0222     }
0223 
0224     inline bool hasPremultipliedAlpha() const
0225     {
0226         return m_premultipliedAlpha;
0227     }
0228 
0229     inline const std::array<quint8, 5> &poses() const
0230     {
0231         return m_poses;
0232     }
0233 
0234     inline KoColorTransformation *transform() const
0235     {
0236         return m_transformProfile;
0237     }
0238 
0239     inline const KisTIFFPostProcessor *postProcessor() const
0240     {
0241         return mpostProcessImpl.get();
0242     }
0243 
0244 private:
0245     KisPaintDeviceSP m_device;
0246     qint32 m_alphapos;
0247     quint16 m_sourceDepth;
0248     uint16_t m_sample_format;
0249     quint16 m_nbcolorssamples;
0250     quint16 m_nbextrasamples;
0251     bool m_premultipliedAlpha;
0252     std::array<quint8, 5> m_poses;
0253     KoColorTransformation *m_transformProfile;
0254     QSharedPointer<KisTIFFPostProcessor> mpostProcessImpl;
0255 };
0256 
0257 template<typename T> class KisTIFFReaderTarget : public KisTIFFReaderBase
0258 {
0259 public:
0260     using type = T;
0261 
0262     KisTIFFReaderTarget(KisPaintDeviceSP device,
0263                         const std::array<quint8, 5> &poses,
0264                         int32_t alphapos,
0265                         uint16_t sourceDepth,
0266                         uint16_t sample_format,
0267                         uint16_t nbcolorssamples,
0268                         uint16_t extrasamplescount,
0269                         bool premultipliedAlpha,
0270                         KoColorTransformation *transformProfile,
0271                         QSharedPointer<KisTIFFPostProcessor> postprocessor,
0272                         T alphaValue)
0273         : KisTIFFReaderBase(device,
0274                             poses,
0275                             alphapos,
0276                             sourceDepth,
0277                             sample_format,
0278                             nbcolorssamples,
0279                             extrasamplescount,
0280                             premultipliedAlpha,
0281                             transformProfile,
0282                             postprocessor)
0283         , m_alphaValue(alphaValue)
0284     {
0285     }
0286 public:
0287     uint32_t
0288     copyDataToChannels(quint32 x,
0289                        quint32 y,
0290                        quint32 dataWidth,
0291                        QSharedPointer<KisBufferStreamBase> tiffstream) override
0292     {
0293         return _copyDataToChannels(x, y, dataWidth, tiffstream);
0294     }
0295 
0296 private:
0297     template<typename U = T,
0298              typename std::enable_if<!std::numeric_limits<U>::is_integer,
0299                                      void>::type * = nullptr>
0300     uint32_t _copyDataToChannels(quint32 x,
0301                                  quint32 y,
0302                                  quint32 dataWidth,
0303                                  QSharedPointer<KisBufferStreamBase> tiffstream)
0304     {
0305         KisHLineIteratorSP it = this->paintDevice()->createHLineIteratorNG(x, y, dataWidth);
0306         do {
0307             T *d = reinterpret_cast<T *>(it->rawData());
0308             quint8 i = 0;
0309             for (i = 0; i < this->nbColorsSamples(); i++) {
0310                 // XXX: for half this should use the bit constructor (plus downcast to uint16_t) (same as in the rest accesses)
0311                 const uint32_t v = tiffstream->nextValue();
0312                 std::memcpy(&d[this->poses()[i]], &v, sizeof(T));
0313             }
0314             this->postProcessor()->postProcess(d);
0315             if (this->transform()) {
0316                 this->transform()->transform(reinterpret_cast<quint8 *>(d), reinterpret_cast<quint8 *>(d), 1);
0317             }
0318             d[this->poses()[i]] = m_alphaValue;
0319             for (quint8 k = 0; k < this->nbExtraSamples(); k++) {
0320                 if (k == this->alphaPos()) {
0321                     const uint32_t v = tiffstream->nextValue();
0322                     std::memcpy(&d[this->poses()[i]], &v, sizeof(T));
0323                 } else {
0324                     (void)tiffstream->nextValue();
0325                 }
0326             }
0327 
0328             if (this->hasPremultipliedAlpha()) {
0329                 auto unmultipliedColorsConsistent = [this, i](T *d) { return !(std::abs(d[this->poses()[i]]) < std::numeric_limits<T>::epsilon()); };
0330 
0331                 auto checkUnmultipliedColorsConsistent = [this, i](const T *d) {
0332                     const T alpha = std::abs(d[this->poses()[i]]);
0333 
0334                     if (alpha >= static_cast<T>(0.01)) {
0335                         return true;
0336                     } else {
0337                         for (size_t i = 0; i < this->nbColorsSamples(); i++) {
0338                             if (!qFuzzyCompare(T(d[i] * alpha), d[i])) {
0339                                 return false;
0340                             }
0341                         }
0342                         return true;
0343                     }
0344                 };
0345 
0346                 if (!unmultipliedColorsConsistent(d)) {
0347                     while (true) {
0348                         T newAlpha = d[this->poses()[i]];
0349 
0350                         for (quint8 i = 0; i < this->nbColorsSamples(); i++) {
0351                             d[i] = std::lroundf(d[i] * newAlpha);
0352                         }
0353 
0354                         d[this->poses()[i]] = newAlpha;
0355 
0356                         if (checkUnmultipliedColorsConsistent(d)) {
0357                             break;
0358                         }
0359 
0360                         newAlpha += std::numeric_limits<T>::epsilon();
0361                     }
0362                 } else {
0363                     const T alpha = d[this->poses()[i]];
0364                     for (quint8 i = 0; i < this->nbColorsSamples(); i++) {
0365                         d[i] = std::lroundf(d[i] * alpha);
0366                     }
0367                 }
0368             }
0369         } while (it->nextPixel());
0370         return 1;
0371     }
0372 
0373     template<typename U = T,
0374              typename std::enable_if<std::numeric_limits<U>::is_integer,
0375                                      void>::type * = nullptr>
0376     uint32_t _copyDataToChannels(quint32 x,
0377                                  quint32 y,
0378                                  quint32 dataWidth,
0379                                  QSharedPointer<KisBufferStreamBase> tiffstream)
0380     {
0381         KisHLineIteratorSP it = this->paintDevice()->createHLineIteratorNG(x, y, dataWidth);
0382         const double coeff = std::numeric_limits<T>::max() / static_cast<double>(std::pow(2.0, this->sourceDepth()) - 1);
0383         const bool no_coeff = !std::is_same<T, uint8_t>::value && this->sourceDepth() == sizeof(T) * CHAR_BIT;
0384         //    dbgFile <<" depth expansion coefficient :" << coeff;
0385         do {
0386             T *d = reinterpret_cast<T *>(it->rawData());
0387             quint8 i;
0388             for (i = 0; i < this->nbColorsSamples(); i++) {
0389                 if (sampleFormat() == SAMPLEFORMAT_INT) {
0390                     T value;
0391                     const typename std::make_signed<T>::type v =
0392                         static_cast<typename std::make_signed<T>::type>(
0393                             tiffstream->nextValue());
0394                     value = v + (std::numeric_limits<T>::max() / 2) + 1;
0395                     if (no_coeff) {
0396                         d[this->poses()[i]] = static_cast<T>(value);
0397                     } else {
0398                         d[this->poses()[i]] = static_cast<T>(value * coeff);
0399                     }
0400                 } else {
0401                     if (no_coeff) {
0402                         d[this->poses()[i]] = static_cast<T>(tiffstream->nextValue());
0403                     } else {
0404                         d[this->poses()[i]] = static_cast<T>(tiffstream->nextValue() * coeff);
0405                     }
0406                 }
0407             }
0408             this->postProcessor()->postProcess(d);
0409             if (this->transform()) {
0410                 this->transform()->transform(reinterpret_cast<quint8 *>(d), reinterpret_cast<quint8 *>(d), 1);
0411             }
0412             d[this->poses()[i]] = m_alphaValue;
0413             for (quint8 k = 0; k < this->nbExtraSamples(); k++) {
0414                 if (k == this->alphaPos()) {
0415                     if (sampleFormat() == SAMPLEFORMAT_INT) {
0416                         T value;
0417                         const typename std::make_signed<T>::type v =
0418                             static_cast<typename std::make_signed<T>::type>(
0419                                 tiffstream->nextValue());
0420                         value = v + (std::numeric_limits<T>::max() / 2) + 1;
0421                         if (no_coeff) {
0422                             d[this->poses()[i]] = static_cast<T>(value);
0423                         } else {
0424                             d[this->poses()[i]] = static_cast<T>(value * coeff);
0425                         }
0426                     } else {
0427                         if (no_coeff) {
0428                             d[this->poses()[i]] = static_cast<T>(tiffstream->nextValue());
0429                         } else {
0430                             d[this->poses()[i]] = static_cast<T>(tiffstream->nextValue() * coeff);
0431                         }
0432                     }
0433                 } else {
0434                     tiffstream->nextValue();
0435                 }
0436             }
0437 
0438             if (hasPremultipliedAlpha()) {
0439                 const T alpha = d[poses()[i]];
0440                 const float factor = alpha == 0 ? 0 : static_cast<float>(std::numeric_limits<T>::max()) / alpha;
0441 
0442                 for (quint8 i = 0; i < nbColorsSamples(); i++) {
0443                     d[i] = std::lroundf(d[i] * factor);
0444                 }
0445             }
0446         } while (it->nextPixel());
0447         return 1;
0448     }
0449 
0450 private:
0451     T m_alphaValue;
0452 };
0453 
0454 class KisTIFFReaderFromPalette : public KisTIFFReaderBase
0455 {
0456 public:
0457     using type = uint16_t;
0458 
0459     KisTIFFReaderFromPalette(KisPaintDeviceSP device,
0460                              uint16_t *red,
0461                              uint16_t *green,
0462                              uint16_t *blue,
0463                              const std::array<quint8, 5> &poses,
0464                              int32_t alphapos,
0465                              uint16_t sourceDepth,
0466                              uint16_t sample_format,
0467                              uint16_t nbcolorssamples,
0468                              bool premultipliedAlpha,
0469                              uint8_t extrasamplescount,
0470                              KoColorTransformation *transformProfile,
0471                              QSharedPointer<KisTIFFPostProcessor> postprocessor)
0472         : KisTIFFReaderBase(device,
0473                             poses,
0474                             alphapos,
0475                             sourceDepth,
0476                             sample_format,
0477                             nbcolorssamples,
0478                             extrasamplescount,
0479                             premultipliedAlpha,
0480                             transformProfile,
0481                             postprocessor)
0482         , m_red(red)
0483         , m_green(green)
0484         , m_blue(blue)
0485     {
0486     }
0487 public:
0488     uint32_t
0489     copyDataToChannels(quint32 x,
0490                        quint32 y,
0491                        quint32 dataWidth,
0492                        QSharedPointer<KisBufferStreamBase> tiffstream) override
0493     {
0494         KisHLineIteratorSP it = paintDevice()->createHLineIteratorNG(static_cast<int>(x), static_cast<int>(y), static_cast<int>(dataWidth));
0495         do {
0496             KisTIFFReaderFromPalette::type *d =
0497                 reinterpret_cast<KisTIFFReaderFromPalette::type *>(
0498                     it->rawData());
0499             uint32_t index = tiffstream->nextValue();
0500             d[2] = m_red[index];
0501             d[1] = m_green[index];
0502             d[0] = m_blue[index];
0503             d[3] = std::numeric_limits<KisTIFFReaderFromPalette::type>::max();
0504 
0505         } while (it->nextPixel());
0506         return 1;
0507     }
0508 
0509 private:
0510     uint16_t *m_red, *m_green, *m_blue;
0511 };
0512 
0513 #endif