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