File indexing completed on 2025-01-19 03:51:03
0001 /* ============================================================ 0002 * 0003 * This file is a part of digiKam project 0004 * https://www.digikam.org 0005 * 0006 * Date : 2005-06-17 0007 * Description : A TIFF IO file for DImg framework - load operations 0008 * 0009 * SPDX-FileCopyrightText: 2005 by Renchi Raju <renchi dot raju at gmail dot com> 0010 * SPDX-FileCopyrightText: 2006-2024 by Gilles Caulier <caulier dot gilles at gmail dot com> 0011 * 0012 * SPDX-License-Identifier: GPL-2.0-or-later 0013 * 0014 * ============================================================ */ 0015 0016 // C ANSI includes 0017 extern "C" 0018 { 0019 #include <tiffvers.h> 0020 } 0021 0022 // C++ includes 0023 0024 #include <cstdio> 0025 #include <cmath> 0026 0027 // Qt includes 0028 0029 #include <QFile> 0030 #include <QFloat16> 0031 #include <QByteArray> 0032 0033 // Local includes 0034 0035 #include "digikam_debug.h" 0036 #include "digikam_config.h" 0037 #include "dimgloaderobserver.h" 0038 #include "dimgtiffloader.h" //krazy:exclude=includes 0039 0040 namespace DigikamTIFFDImgPlugin 0041 { 0042 0043 bool DImgTIFFLoader::load(const QString& filePath, DImgLoaderObserver* const observer) 0044 { 0045 readMetadata(filePath); 0046 0047 // ------------------------------------------------------------------- 0048 // TIFF error handling. If an errors/warnings occurs during reading, 0049 // libtiff will call these methods 0050 0051 #ifdef Q_OS_WIN 0052 0053 TIFFSetWarningHandler(NULL); 0054 0055 #else 0056 0057 TIFFSetWarningHandler(dimg_tiff_warning); 0058 0059 #endif 0060 0061 TIFFSetErrorHandler(dimg_tiff_error); 0062 0063 // ------------------------------------------------------------------- 0064 // Open the file 0065 0066 #ifdef Q_OS_WIN 0067 0068 TIFF* const tif = TIFFOpenW((const wchar_t*)filePath.utf16(), "r"); 0069 0070 #else 0071 0072 TIFF* const tif = TIFFOpen(filePath.toUtf8().constData(), "r"); 0073 0074 #endif 0075 0076 if (!tif) 0077 { 0078 qCWarning(DIGIKAM_DIMG_LOG_TIFF) << "Cannot open image file."; 0079 loadingFailed(); 0080 return false; 0081 } 0082 /* 0083 if (DIGIKAM_DIMG_LOG_TIFF().isDebugEnabled()) 0084 { 0085 TIFFPrintDirectory(tif, stdout, 0); 0086 } 0087 */ 0088 // ------------------------------------------------------------------- 0089 // Get image information. 0090 0091 uint32 w, h; 0092 uint16 bits_per_sample; 0093 uint16 samples_per_pixel; 0094 uint16 sample_format; 0095 uint16 photometric; 0096 uint16 planar_config; 0097 uint32 rows_per_strip; 0098 tsize_t strip_size; 0099 tstrip_t num_of_strips; 0100 0101 TIFFGetFieldDefaulted(tif, TIFFTAG_IMAGEWIDTH, &w); 0102 TIFFGetFieldDefaulted(tif, TIFFTAG_IMAGELENGTH, &h); 0103 0104 TIFFGetFieldDefaulted(tif, TIFFTAG_BITSPERSAMPLE, &bits_per_sample); 0105 TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLESPERPIXEL, &samples_per_pixel); 0106 TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLEFORMAT, &sample_format); 0107 TIFFGetFieldDefaulted(tif, TIFFTAG_PLANARCONFIG, &planar_config); 0108 0109 if (TIFFGetFieldDefaulted(tif, TIFFTAG_ROWSPERSTRIP, &rows_per_strip) == 0 || rows_per_strip == 0) 0110 { 0111 qCWarning(DIGIKAM_DIMG_LOG_TIFF) << "TIFF loader: Cannot handle non-stripped images. Loading file " 0112 << filePath; 0113 TIFFClose(tif); 0114 loadingFailed(); 0115 0116 return false; 0117 } 0118 0119 if (rows_per_strip > h) 0120 { 0121 rows_per_strip = h; 0122 } 0123 0124 if ( (bits_per_sample == 0) 0125 || (samples_per_pixel == 0) 0126 || (rows_per_strip == 0) 0127 /* 0128 || (rows_per_strip > h) 0129 */ 0130 ) 0131 { 0132 qCWarning(DIGIKAM_DIMG_LOG_TIFF) << "TIFF loader: Encountered invalid value in image." << QT_ENDL 0133 << " bits_per_sample : " << bits_per_sample << QT_ENDL 0134 << " samples_per_pixel : " << samples_per_pixel << QT_ENDL 0135 << " rows_per_strip : " << rows_per_strip << QT_ENDL 0136 << " h : " << h << QT_ENDL 0137 << " Loading file : " << filePath; 0138 TIFFClose(tif); 0139 loadingFailed(); 0140 0141 return false; 0142 } 0143 0144 // TODO: check others TIFF color-spaces here. Actually, only RGB, PALETTE and MINISBLACK 0145 // have been tested. 0146 // Complete description of TIFFTAG_PHOTOMETRIC tag can be found at this Url: 0147 // www.awaresystems.be/imaging/tiff/tifftags/photometricinterpretation.html 0148 0149 TIFFGetFieldDefaulted(tif, TIFFTAG_PHOTOMETRIC, &photometric); 0150 0151 if ( 0152 (photometric != PHOTOMETRIC_RGB) && 0153 (photometric != PHOTOMETRIC_PALETTE) && 0154 (photometric != PHOTOMETRIC_MINISWHITE) && 0155 (photometric != PHOTOMETRIC_MINISBLACK) && 0156 ((photometric != PHOTOMETRIC_YCBCR) | (bits_per_sample != 8)) && 0157 ((photometric != PHOTOMETRIC_SEPARATED) | (bits_per_sample != 8)) && 0158 (m_loadFlags & LoadImageData) 0159 ) 0160 { 0161 qCWarning(DIGIKAM_DIMG_LOG_TIFF) << "Can not handle image without RGB color-space: " 0162 << photometric; 0163 TIFFClose(tif); 0164 loadingFailed(); 0165 0166 return false; 0167 } 0168 0169 int colorModel = DImg::COLORMODELUNKNOWN; 0170 0171 switch (photometric) 0172 { 0173 case PHOTOMETRIC_MINISWHITE: 0174 case PHOTOMETRIC_MINISBLACK: 0175 { 0176 colorModel = DImg::GRAYSCALE; 0177 break; 0178 } 0179 0180 case PHOTOMETRIC_RGB: 0181 { 0182 colorModel = DImg::RGB; 0183 break; 0184 } 0185 0186 case PHOTOMETRIC_PALETTE: 0187 { 0188 colorModel = DImg::INDEXED; 0189 break; 0190 } 0191 0192 case PHOTOMETRIC_MASK: 0193 { 0194 colorModel = DImg::MONOCHROME; 0195 break; 0196 } 0197 0198 case PHOTOMETRIC_SEPARATED: 0199 { 0200 colorModel = DImg::CMYK; 0201 break; 0202 } 0203 0204 case PHOTOMETRIC_YCBCR: 0205 { 0206 colorModel = DImg::YCBCR; 0207 break; 0208 } 0209 0210 case PHOTOMETRIC_CIELAB: 0211 case PHOTOMETRIC_ICCLAB: 0212 case PHOTOMETRIC_ITULAB: 0213 { 0214 colorModel = DImg::CIELAB; 0215 break; 0216 } 0217 0218 case PHOTOMETRIC_LOGL: 0219 case PHOTOMETRIC_LOGLUV: 0220 { 0221 colorModel = DImg::COLORMODELRAW; 0222 break; 0223 } 0224 } 0225 0226 if (samples_per_pixel == 4) 0227 { 0228 m_hasAlpha = true; 0229 } 0230 else 0231 { 0232 m_hasAlpha = false; 0233 } 0234 0235 if ((bits_per_sample == 16) || (bits_per_sample == 32)) 0236 { 0237 m_sixteenBit = true; 0238 } 0239 else 0240 { 0241 m_sixteenBit = false; 0242 } 0243 0244 // ------------------------------------------------------------------- 0245 // Read image ICC profile 0246 0247 if (m_loadFlags & LoadICCData) 0248 { 0249 uchar* profile_data = nullptr; 0250 uint32 profile_size; 0251 0252 if (TIFFGetField(tif, TIFFTAG_ICCPROFILE, &profile_size, &profile_data)) 0253 { 0254 QByteArray profile_rawdata; 0255 profile_rawdata.resize(profile_size); 0256 memcpy(profile_rawdata.data(), profile_data, profile_size); 0257 imageSetIccProfile(IccProfile(profile_rawdata)); 0258 } 0259 else 0260 { 0261 // If ICC profile is null, check Exif metadata. 0262 0263 checkExifWorkingColorSpace(); 0264 } 0265 } 0266 0267 // ------------------------------------------------------------------- 0268 // Get image data. 0269 0270 QScopedArrayPointer<uchar> data; 0271 0272 if (m_loadFlags & LoadImageData) 0273 { 0274 if (observer) 0275 { 0276 observer->progressInfo(0.1F); 0277 } 0278 0279 strip_size = TIFFStripSize(tif); 0280 num_of_strips = TIFFNumberOfStrips(tif); 0281 0282 if (bits_per_sample == 16) // 16 bits image. 0283 { 0284 data.reset(new_failureTolerant(w, h, 8)); 0285 QScopedArrayPointer<uchar> strip(new_failureTolerant(strip_size)); 0286 0287 if (!data || strip.isNull()) 0288 { 0289 qCWarning(DIGIKAM_DIMG_LOG_TIFF) << "Failed to allocate memory for TIFF image" << filePath; 0290 TIFFClose(tif); 0291 loadingFailed(); 0292 0293 return false; 0294 } 0295 0296 qint64 offset = 0; 0297 qint64 bytesRead = 0; 0298 uint checkpoint = 0; 0299 0300 for (tstrip_t st = 0 ; st < num_of_strips ; ++st) 0301 { 0302 if (observer && (st == checkpoint)) 0303 { 0304 checkpoint += granularity(observer, num_of_strips, 0.8F); 0305 0306 if (!observer->continueQuery()) 0307 { 0308 TIFFClose(tif); 0309 loadingFailed(); 0310 0311 return false; 0312 } 0313 0314 observer->progressInfo(0.1F + (0.8F * (((float)st) / ((float)num_of_strips)))); 0315 } 0316 0317 bytesRead = TIFFReadEncodedStrip(tif, st, strip.data(), strip_size); 0318 0319 if (bytesRead == -1) 0320 { 0321 qCWarning(DIGIKAM_DIMG_LOG_TIFF) << "Failed to read strip"; 0322 TIFFClose(tif); 0323 loadingFailed(); 0324 0325 return false; 0326 } 0327 0328 if ((num_of_strips != 0) && (samples_per_pixel != 0)) 0329 { 0330 if ((planar_config == PLANARCONFIG_SEPARATE) && 0331 (remainder((double)st, (double)(num_of_strips / samples_per_pixel)) == 0.0)) 0332 { 0333 offset = 0; 0334 } 0335 } 0336 0337 ushort* stripPtr = reinterpret_cast<ushort*>(strip.data()); 0338 ushort* dataPtr = reinterpret_cast<ushort*>(data.data() + offset); 0339 ushort* p = nullptr; 0340 0341 // tiff data is read as BGR or ABGR or Greyscale 0342 0343 if (samples_per_pixel == 1) // See bug #148400: Greyscale pictures only have _one_ sample per pixel 0344 { 0345 for (int i = 0 ; i < (bytesRead / 2) ; ++i) 0346 { 0347 // We have to read two bytes for one pixel 0348 0349 p = dataPtr; 0350 0351 if (sample_format == SAMPLEFORMAT_IEEEFP) 0352 { 0353 p[0] = (ushort)qBound(0.0F, (*reinterpret_cast<qfloat16*>(stripPtr)) * 65535.0F, 65535.0F); 0354 p[1] = (ushort)qBound(0.0F, (*reinterpret_cast<qfloat16*>(stripPtr)) * 65535.0F, 65535.0F); 0355 p[2] = (ushort)qBound(0.0F, (*reinterpret_cast<qfloat16*>(stripPtr++)) * 65535.0F, 65535.0F); 0356 p[3] = 0xFFFF; 0357 } 0358 else 0359 { 0360 p[0] = *stripPtr; // RGB have to be set to the _same_ value 0361 p[1] = *stripPtr; 0362 p[2] = *stripPtr++; 0363 p[3] = 0xFFFF; // set alpha to 100% 0364 } 0365 0366 dataPtr += 4; 0367 } 0368 0369 offset += bytesRead * 4; // The _byte_offset in the data array is, of course, four times bytesRead 0370 } 0371 0372 else if ((samples_per_pixel == 3) && 0373 (planar_config == PLANARCONFIG_CONTIG)) 0374 { 0375 for (int i = 0 ; i < (bytesRead / 6) ; ++i) 0376 { 0377 p = dataPtr; 0378 0379 if (sample_format == SAMPLEFORMAT_IEEEFP) 0380 { 0381 p[2] = (ushort)qBound(0.0F, (*reinterpret_cast<qfloat16*>(stripPtr++)) * 65535.0F, 65535.0F); 0382 p[1] = (ushort)qBound(0.0F, (*reinterpret_cast<qfloat16*>(stripPtr++)) * 65535.0F, 65535.0F); 0383 p[0] = (ushort)qBound(0.0F, (*reinterpret_cast<qfloat16*>(stripPtr++)) * 65535.0F, 65535.0F); 0384 p[3] = 0xFFFF; 0385 } 0386 else 0387 { 0388 p[2] = *stripPtr++; 0389 p[1] = *stripPtr++; 0390 p[0] = *stripPtr++; 0391 p[3] = 0xFFFF; 0392 } 0393 0394 dataPtr += 4; 0395 } 0396 0397 offset += bytesRead / 6 * 8; 0398 } 0399 0400 // cppcheck-suppress knownConditionTrueFalse 0401 else if ((samples_per_pixel == 3) && 0402 (planar_config == PLANARCONFIG_SEPARATE)) 0403 { 0404 for (int i = 0 ; i < (bytesRead / 2) ; ++i) 0405 { 0406 p = dataPtr; 0407 0408 // cppcheck-suppress knownConditionTrueFalse 0409 if (samples_per_pixel != 0) 0410 { 0411 int den = (int)num_of_strips / (int)samples_per_pixel; 0412 0413 if (den != 0) 0414 { 0415 int val = st / den; 0416 0417 if (sample_format == SAMPLEFORMAT_IEEEFP) 0418 { 0419 switch (val) 0420 { 0421 case 0: 0422 { 0423 p[2] = (ushort)qBound(0.0F, (*reinterpret_cast<qfloat16*>(stripPtr++)) * 65535.0F, 65535.0F); 0424 p[3] = 0xFFFF; 0425 break; 0426 } 0427 0428 case 1: 0429 { 0430 p[1] = (ushort)qBound(0.0F, (*reinterpret_cast<qfloat16*>(stripPtr++)) * 65535.0F, 65535.0F); 0431 break; 0432 } 0433 0434 case 2: 0435 { 0436 p[0] = (ushort)qBound(0.0F, (*reinterpret_cast<qfloat16*>(stripPtr++)) * 65535.0F, 65535.0F); 0437 break; 0438 } 0439 } 0440 } 0441 else 0442 { 0443 switch (val) 0444 { 0445 case 0: 0446 { 0447 p[2] = *stripPtr++; 0448 p[3] = 0xFFFF; 0449 break; 0450 } 0451 0452 case 1: 0453 { 0454 p[1] = *stripPtr++; 0455 break; 0456 } 0457 0458 case 2: 0459 { 0460 p[0] = *stripPtr++; 0461 break; 0462 } 0463 } 0464 } 0465 0466 dataPtr += 4; 0467 } 0468 } 0469 } 0470 0471 offset += bytesRead / 2 * 8; 0472 } 0473 0474 else if ((samples_per_pixel == 4) && 0475 (planar_config == PLANARCONFIG_CONTIG)) 0476 { 0477 for (int i = 0 ; i < (bytesRead / 8) ; ++i) 0478 { 0479 p = dataPtr; 0480 0481 if (sample_format == SAMPLEFORMAT_IEEEFP) 0482 { 0483 p[2] = (ushort)qBound(0.0F, (*reinterpret_cast<qfloat16*>(stripPtr++)) * 65535.0F, 65535.0F); 0484 p[1] = (ushort)qBound(0.0F, (*reinterpret_cast<qfloat16*>(stripPtr++)) * 65535.0F, 65535.0F); 0485 p[0] = (ushort)qBound(0.0F, (*reinterpret_cast<qfloat16*>(stripPtr++)) * 65535.0F, 65535.0F); 0486 p[3] = (ushort)qBound(0.0F, (*reinterpret_cast<qfloat16*>(stripPtr++)) * 65535.0F, 65535.0F); 0487 } 0488 else 0489 { 0490 p[2] = *stripPtr++; 0491 p[1] = *stripPtr++; 0492 p[0] = *stripPtr++; 0493 p[3] = *stripPtr++; 0494 } 0495 0496 dataPtr += 4; 0497 } 0498 0499 offset += bytesRead; 0500 } 0501 0502 // cppcheck-suppress knownConditionTrueFalse 0503 else if ((samples_per_pixel == 4) && 0504 (planar_config == PLANARCONFIG_SEPARATE)) 0505 { 0506 for (int i = 0 ; i < (bytesRead / 2) ; ++i) 0507 { 0508 p = dataPtr; 0509 0510 // cppcheck-suppress knownConditionTrueFalse 0511 if (samples_per_pixel != 0) 0512 { 0513 int den = (int)num_of_strips / (int)samples_per_pixel; 0514 0515 if (den != 0) 0516 { 0517 int val = st / den; 0518 0519 if (sample_format == SAMPLEFORMAT_IEEEFP) 0520 { 0521 switch (val) 0522 { 0523 case 0: 0524 { 0525 p[2] = (ushort)qBound(0.0F, (*reinterpret_cast<qfloat16*>(stripPtr++)) * 65535.0F, 65535.0F); 0526 break; 0527 } 0528 0529 case 1: 0530 { 0531 p[1] = (ushort)qBound(0.0F, (*reinterpret_cast<qfloat16*>(stripPtr++)) * 65535.0F, 65535.0F); 0532 break; 0533 } 0534 0535 case 2: 0536 { 0537 p[0] = (ushort)qBound(0.0F, (*reinterpret_cast<qfloat16*>(stripPtr++)) * 65535.0F, 65535.0F); 0538 break; 0539 } 0540 0541 case 3: 0542 { 0543 p[3] = (ushort)qBound(0.0F, (*reinterpret_cast<qfloat16*>(stripPtr++)) * 65535.0F, 65535.0F); 0544 break; 0545 } 0546 } 0547 } 0548 else 0549 { 0550 switch (val) 0551 { 0552 case 0: 0553 { 0554 p[2] = *stripPtr++; 0555 break; 0556 } 0557 0558 case 1: 0559 { 0560 p[1] = *stripPtr++; 0561 break; 0562 } 0563 0564 case 2: 0565 { 0566 p[0] = *stripPtr++; 0567 break; 0568 } 0569 0570 case 3: 0571 { 0572 p[3] = *stripPtr++; 0573 break; 0574 } 0575 } 0576 } 0577 0578 dataPtr += 4; 0579 } 0580 } 0581 } 0582 0583 offset += bytesRead / 2 * 8; 0584 } 0585 } 0586 } 0587 0588 else if ((bits_per_sample == 32) && (sample_format == SAMPLEFORMAT_IEEEFP)) // 32 bits float image. 0589 { 0590 data.reset(new_failureTolerant(w, h, 8)); 0591 QScopedArrayPointer<uchar> strip(new_failureTolerant(strip_size)); 0592 0593 if (!data || strip.isNull()) 0594 { 0595 qCWarning(DIGIKAM_DIMG_LOG_TIFF) << "Failed to allocate memory for TIFF image" << filePath; 0596 TIFFClose(tif); 0597 loadingFailed(); 0598 0599 return false; 0600 } 0601 0602 qint64 offset = 0; 0603 qint64 bytesRead = 0; 0604 uint checkpoint = 0; 0605 float maxValue = 0.0; 0606 0607 for (tstrip_t st = 0 ; st < num_of_strips ; ++st) 0608 { 0609 if (observer && !observer->continueQuery()) 0610 { 0611 TIFFClose(tif); 0612 loadingFailed(); 0613 0614 return false; 0615 } 0616 0617 bytesRead = TIFFReadEncodedStrip(tif, st, strip.data(), strip_size); 0618 0619 if (bytesRead == -1) 0620 { 0621 qCWarning(DIGIKAM_DIMG_LOG_TIFF) << "Failed to read strip"; 0622 TIFFClose(tif); 0623 loadingFailed(); 0624 0625 return false; 0626 } 0627 0628 float* stripPtr = reinterpret_cast<float*>(strip.data()); 0629 0630 for (int i = 0 ; i < (bytesRead / 4) ; ++i) 0631 { 0632 maxValue = qMax(maxValue, *stripPtr++); 0633 } 0634 } 0635 0636 double factor = (maxValue > 10.0) ? log10(maxValue) * 1.5 : 1.0; 0637 double scale = (factor > 1.0) ? 0.75 : 1.0; 0638 0639 if (factor > 1.0) 0640 { 0641 qCWarning(DIGIKAM_DIMG_LOG_TIFF) << "TIFF image cannot be converted lossless from 32 to 16 bits" << filePath; 0642 } 0643 0644 for (tstrip_t st = 0 ; st < num_of_strips ; ++st) 0645 { 0646 if (observer && st == checkpoint) 0647 { 0648 checkpoint += granularity(observer, num_of_strips, 0.8F); 0649 0650 if (!observer->continueQuery()) 0651 { 0652 TIFFClose(tif); 0653 loadingFailed(); 0654 0655 return false; 0656 } 0657 0658 observer->progressInfo(0.1F + (0.8F * (((float)st) / ((float)num_of_strips)))); 0659 } 0660 0661 bytesRead = TIFFReadEncodedStrip(tif, st, strip.data(), strip_size); 0662 0663 if (bytesRead == -1) 0664 { 0665 qCWarning(DIGIKAM_DIMG_LOG_TIFF) << "Failed to read strip"; 0666 TIFFClose(tif); 0667 loadingFailed(); 0668 return false; 0669 } 0670 0671 0672 if ((num_of_strips != 0) && (samples_per_pixel != 0)) 0673 { 0674 if ((planar_config == PLANARCONFIG_SEPARATE) && 0675 (remainder((double)st, (double)(num_of_strips / samples_per_pixel)) == 0.0)) 0676 { 0677 offset = 0; 0678 } 0679 } 0680 0681 float* stripPtr = reinterpret_cast<float*>(strip.data()); 0682 ushort* dataPtr = reinterpret_cast<ushort*>(data.data() + offset); 0683 ushort* p = nullptr; 0684 0685 if ((samples_per_pixel == 3) && 0686 (planar_config == PLANARCONFIG_CONTIG)) 0687 { 0688 for (int i = 0 ; i < (bytesRead / 12) ; ++i) 0689 { 0690 p = dataPtr; 0691 0692 p[2] = (ushort)qBound(0.0, pow((double)*stripPtr++ / factor, scale) * 65535.0, 65535.0); 0693 p[1] = (ushort)qBound(0.0, pow((double)*stripPtr++ / factor, scale) * 65535.0, 65535.0); 0694 p[0] = (ushort)qBound(0.0, pow((double)*stripPtr++ / factor, scale) * 65535.0, 65535.0); 0695 p[3] = 0xFFFF; 0696 0697 dataPtr += 4; 0698 } 0699 0700 offset += bytesRead / 12 * 8; 0701 } 0702 0703 // cppcheck-suppress knownConditionTrueFalse 0704 else if ((samples_per_pixel == 3) && 0705 (planar_config == PLANARCONFIG_SEPARATE)) 0706 { 0707 for (int i = 0 ; i < (bytesRead / 4) ; ++i) 0708 { 0709 p = dataPtr; 0710 0711 // cppcheck-suppress knownConditionTrueFalse 0712 if (samples_per_pixel != 0) 0713 { 0714 int den = (int)num_of_strips / (int)samples_per_pixel; 0715 0716 if (den != 0) 0717 { 0718 int val = st / den; 0719 0720 switch (val) 0721 { 0722 case 0: 0723 { 0724 p[2] = (ushort)qBound(0.0, pow((double)*stripPtr++ / factor, scale) * 65535.0, 65535.0); 0725 p[3] = 0xFFFF; 0726 break; 0727 } 0728 0729 case 1: 0730 { 0731 p[1] = (ushort)qBound(0.0, pow((double)*stripPtr++ / factor, scale) * 65535.0, 65535.0); 0732 break; 0733 } 0734 0735 case 2: 0736 { 0737 p[0] = (ushort)qBound(0.0, pow((double)*stripPtr++ / factor, scale) * 65535.0, 65535.0); 0738 break; 0739 } 0740 } 0741 0742 dataPtr += 4; 0743 } 0744 } 0745 } 0746 0747 offset += bytesRead / 4 * 8; 0748 } 0749 0750 else if ((samples_per_pixel == 4) && 0751 (planar_config == PLANARCONFIG_CONTIG)) 0752 { 0753 for (int i = 0 ; i < (bytesRead / 16) ; ++i) 0754 { 0755 p = dataPtr; 0756 0757 p[2] = (ushort)qBound(0.0, pow((double)*stripPtr++ / factor, scale) * 65535.0, 65535.0); 0758 p[1] = (ushort)qBound(0.0, pow((double)*stripPtr++ / factor, scale) * 65535.0, 65535.0); 0759 p[0] = (ushort)qBound(0.0, pow((double)*stripPtr++ / factor, scale) * 65535.0, 65535.0); 0760 p[3] = (ushort)qBound(0.0, (double)*stripPtr++ * 65535.0, 65535.0); 0761 0762 dataPtr += 4; 0763 } 0764 0765 offset += bytesRead / 16 * 8; 0766 } 0767 0768 // cppcheck-suppress knownConditionTrueFalse 0769 else if ((samples_per_pixel == 4) && 0770 (planar_config == PLANARCONFIG_SEPARATE)) 0771 { 0772 for (int i = 0 ; i < bytesRead / 4 ; ++i) 0773 { 0774 p = dataPtr; 0775 0776 // cppcheck-suppress knownConditionTrueFalse 0777 if (samples_per_pixel != 0) 0778 { 0779 int den = (int)num_of_strips / (int)samples_per_pixel; 0780 0781 if (den != 0) 0782 { 0783 int val = st / den; 0784 0785 switch (val) 0786 { 0787 case 0: 0788 { 0789 p[2] = (ushort)qBound(0.0, pow((double)*stripPtr++ / factor, scale) * 65535.0, 65535.0); 0790 break; 0791 } 0792 0793 case 1: 0794 { 0795 p[1] = (ushort)qBound(0.0, pow((double)*stripPtr++ / factor, scale) * 65535.0, 65535.0); 0796 break; 0797 } 0798 0799 case 2: 0800 { 0801 p[0] = (ushort)qBound(0.0, pow((double)*stripPtr++ / factor, scale) * 65535.0, 65535.0); 0802 break; 0803 } 0804 0805 case 3: 0806 { 0807 p[3] = (ushort)qBound(0.0, (double)*stripPtr++ * 65535.0, 65535.0); 0808 break; 0809 } 0810 } 0811 0812 dataPtr += 4; 0813 } 0814 } 0815 } 0816 0817 offset += bytesRead / 4 * 8; 0818 } 0819 } 0820 } 0821 0822 else // Non 16 or 32 bits images ==> get it on BGRA 8 bits. 0823 { 0824 data.reset(new_failureTolerant(w, h, 4)); 0825 QScopedArrayPointer<uchar> strip(new_failureTolerant(w, rows_per_strip, 4)); 0826 0827 if (!data || strip.isNull()) 0828 { 0829 qCWarning(DIGIKAM_DIMG_LOG_TIFF) << "Failed to allocate memory for TIFF image" << filePath; 0830 TIFFClose(tif); 0831 loadingFailed(); 0832 0833 return false; 0834 } 0835 0836 qint64 offset = 0; 0837 qint64 pixelsRead = 0; 0838 0839 // this is inspired by TIFFReadRGBAStrip, tif_getimage.c 0840 0841 char emsg[1024] = ""; 0842 uint32 rows_to_read = 0; 0843 uint checkpoint = 0; 0844 TIFFRGBAImage img; 0845 0846 // test whether libtiff can read format and initiate reading 0847 0848 if (!TIFFRGBAImageOK(tif, emsg) || !TIFFRGBAImageBegin(&img, tif, 0, emsg)) 0849 { 0850 qCWarning(DIGIKAM_DIMG_LOG_TIFF) << "Failed to set up RGBA reading of image, filename " 0851 << TIFFFileName(tif) << " error message from Libtiff: " << emsg; 0852 TIFFClose(tif); 0853 loadingFailed(); 0854 0855 return false; 0856 } 0857 0858 // libtiff cannot handle all possible orientations, it give weird results. 0859 // We rotate ourselves. (Bug 274865) 0860 0861 img.req_orientation = img.orientation; 0862 0863 // read strips from image: read rows_per_strip, so always start at beginning of a strip 0864 0865 for (uint row = 0 ; row < h ; row += rows_per_strip) 0866 { 0867 if (observer && (row >= checkpoint)) 0868 { 0869 checkpoint += granularity(observer, h, 0.8F); 0870 0871 if (!observer->continueQuery()) 0872 { 0873 TIFFClose(tif); 0874 loadingFailed(); 0875 0876 return false; 0877 } 0878 0879 observer->progressInfo(0.1F + (0.8F * (((float)row) / ((float)h)))); 0880 } 0881 0882 img.row_offset = row; 0883 img.col_offset = 0; 0884 0885 if (row + rows_per_strip > img.height) 0886 { 0887 rows_to_read = img.height - row; 0888 } 0889 else 0890 { 0891 rows_to_read = rows_per_strip; 0892 } 0893 0894 // Read data 0895 0896 if (TIFFRGBAImageGet(&img, reinterpret_cast<uint32*>(strip.data()), img.width, rows_to_read) == -1) 0897 { 0898 qCWarning(DIGIKAM_DIMG_LOG_TIFF) << "Failed to read image data"; 0899 TIFFClose(tif); 0900 loadingFailed(); 0901 0902 return false; 0903 } 0904 0905 pixelsRead = (qint64)rows_to_read * (qint64)img.width; 0906 0907 uchar* stripPtr = (uchar*)(strip.data()); 0908 uchar* dataPtr = (uchar*)(data.data() + offset); 0909 uchar* p = nullptr; 0910 0911 // Reverse red and blue 0912 0913 for (int i = 0 ; i < pixelsRead ; ++i) 0914 { 0915 p = dataPtr; 0916 0917 p[2] = *stripPtr++; 0918 p[1] = *stripPtr++; 0919 p[0] = *stripPtr++; 0920 p[3] = *stripPtr++; 0921 0922 dataPtr += 4; 0923 } 0924 0925 offset += pixelsRead * 4; 0926 } 0927 0928 TIFFRGBAImageEnd(&img); 0929 } 0930 } 0931 0932 // ------------------------------------------------------------------- 0933 0934 TIFFClose(tif); 0935 0936 if (observer) 0937 { 0938 observer->progressInfo(1.0F); 0939 } 0940 0941 imageWidth() = w; 0942 imageHeight() = h; 0943 imageData() = data.take(); 0944 imageSetAttribute(QLatin1String("format"), QLatin1String("TIFF")); 0945 imageSetAttribute(QLatin1String("originalColorModel"), colorModel); 0946 imageSetAttribute(QLatin1String("originalBitDepth"), bits_per_sample); 0947 imageSetAttribute(QLatin1String("originalSize"), QSize(w, h)); 0948 0949 return true; 0950 } 0951 0952 } // namespace DigikamTIFFDImgPlugin