LCOV - code coverage report
Current view: top level - frmts/gtiff - gtiffoddbitsband.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 352 405 86.9 %
Date: 2026-06-07 01:30:14 Functions: 3 3 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GeoTIFF Driver
       4             :  * Purpose:  GDAL GeoTIFF support.
       5             :  * Author:   Frank Warmerdam, warmerdam@pobox.com
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 1998, 2002, Frank Warmerdam <warmerdam@pobox.com>
       9             :  * Copyright (c) 2007-2015, Even Rouault <even dot rouault at spatialys dot com>
      10             :  *
      11             :  * SPDX-License-Identifier: MIT
      12             :  ****************************************************************************/
      13             : 
      14             : #include "gtiffoddbitsband.h"
      15             : 
      16             : #include <algorithm>
      17             : #include "gdal_priv.h"
      18             : #include "cpl_float.h"  // CPLFloatToHalf()
      19             : #include "gtiffdataset.h"
      20             : #include "tiffio.h"
      21             : 
      22             : /************************************************************************/
      23             : /*                          GTiffOddBitsBand()                          */
      24             : /************************************************************************/
      25             : 
      26         849 : GTiffOddBitsBand::GTiffOddBitsBand(GTiffDataset *m_poGDSIn, int nBandIn)
      27         849 :     : GTiffRasterBand(m_poGDSIn, nBandIn)
      28             : 
      29             : {
      30         849 :     eDataType = GDT_Unknown;
      31         849 :     if (m_poGDS->m_nBitsPerSample == 24 &&
      32          34 :         m_poGDS->m_nSampleFormat == SAMPLEFORMAT_IEEEFP)
      33           2 :         eDataType = GDT_Float32;
      34             :     // FIXME ? in autotest we currently open gcore/data/int24.tif
      35             :     // which is declared as signed, but we consider it as unsigned
      36         847 :     else if ((m_poGDS->m_nSampleFormat == SAMPLEFORMAT_UINT ||
      37           2 :               m_poGDS->m_nSampleFormat == SAMPLEFORMAT_INT) &&
      38         847 :              m_poGDS->m_nBitsPerSample < 8)
      39         586 :         eDataType = GDT_UInt8;
      40         261 :     else if ((m_poGDS->m_nSampleFormat == SAMPLEFORMAT_UINT ||
      41           2 :               m_poGDS->m_nSampleFormat == SAMPLEFORMAT_INT) &&
      42         261 :              m_poGDS->m_nBitsPerSample > 8 && m_poGDS->m_nBitsPerSample < 16)
      43         191 :         eDataType = GDT_UInt16;
      44          70 :     else if ((m_poGDS->m_nSampleFormat == SAMPLEFORMAT_UINT ||
      45           2 :               m_poGDS->m_nSampleFormat == SAMPLEFORMAT_INT) &&
      46          70 :              m_poGDS->m_nBitsPerSample > 16 && m_poGDS->m_nBitsPerSample < 32)
      47          69 :         eDataType = GDT_UInt32;
      48         849 : }
      49             : 
      50             : /************************************************************************/
      51             : /*                            IWriteBlock()                             */
      52             : /************************************************************************/
      53             : 
      54        8814 : CPLErr GTiffOddBitsBand::IWriteBlock(int nBlockXOff, int nBlockYOff,
      55             :                                      void *pImage)
      56             : 
      57             : {
      58        8814 :     m_poGDS->Crystalize();
      59             : 
      60        8814 :     if (m_poGDS->m_bWriteError)
      61             :     {
      62             :         // Report as an error if a previously loaded block couldn't be written
      63             :         // correctly.
      64           0 :         return CE_Failure;
      65             :     }
      66             : 
      67        8814 :     if (eDataType == GDT_Float32 && m_poGDS->m_nBitsPerSample != 16)
      68             :     {
      69           0 :         ReportError(
      70             :             CE_Failure, CPLE_NotSupported,
      71             :             "Writing float data with nBitsPerSample = %d is unsupported",
      72           0 :             m_poGDS->m_nBitsPerSample);
      73           0 :         return CE_Failure;
      74             :     }
      75             : 
      76             :     /* -------------------------------------------------------------------- */
      77             :     /*      Load the block buffer.                                          */
      78             :     /* -------------------------------------------------------------------- */
      79        8814 :     const int nBlockId = ComputeBlockId(nBlockXOff, nBlockYOff);
      80             : 
      81             :     // Only read content from disk in the CONTIG case.
      82             :     {
      83        8814 :         const CPLErr eErr = m_poGDS->LoadBlockBuf(
      84       17597 :             nBlockId, m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG &&
      85        8783 :                           m_poGDS->nBands > 1);
      86        8814 :         if (eErr != CE_None)
      87           0 :             return eErr;
      88             :     }
      89             : 
      90        8814 :     const GUInt32 nMaxVal = (1U << m_poGDS->m_nBitsPerSample) - 1;
      91             : 
      92             :     /* -------------------------------------------------------------------- */
      93             :     /*      Handle case of "separate" images or single band images where    */
      94             :     /*      no interleaving with other data is required.                    */
      95             :     /* -------------------------------------------------------------------- */
      96        8814 :     if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE ||
      97        8783 :         m_poGDS->nBands == 1)
      98             :     {
      99             :         // TODO(schwehr): Create a CplNumBits8Aligned.
     100             :         // Bits per line rounds up to next byte boundary.
     101        8703 :         GInt64 nBitsPerLine =
     102        8703 :             static_cast<GInt64>(nBlockXSize) * m_poGDS->m_nBitsPerSample;
     103        8703 :         if ((nBitsPerLine & 7) != 0)
     104          74 :             nBitsPerLine = (nBitsPerLine + 7) & (~7);
     105             : 
     106        8703 :         GPtrDiff_t iPixel = 0;
     107             : 
     108             :         // Small optimization in 1 bit case.
     109        8703 :         if (m_poGDS->m_nBitsPerSample == 1)
     110             :         {
     111      268024 :             for (int iY = 0; iY < nBlockYSize; ++iY, iPixel += nBlockXSize)
     112             :             {
     113      259413 :                 GInt64 iBitOffset = iY * nBitsPerLine;
     114             : 
     115      259413 :                 const GByte *pabySrc =
     116      259413 :                     static_cast<const GByte *>(pImage) + iPixel;
     117      259413 :                 auto iByteOffset = iBitOffset / 8;
     118      259413 :                 int iX = 0;  // Used after for.
     119     8012840 :                 for (; iX < nBlockXSize - 7; iX += 8, iByteOffset++)
     120             :                 {
     121     7753430 :                     int nRes = (!(!pabySrc[iX + 0])) << 7;
     122     7753430 :                     nRes |= (!(!pabySrc[iX + 1])) << 6;
     123     7753430 :                     nRes |= (!(!pabySrc[iX + 2])) << 5;
     124     7753430 :                     nRes |= (!(!pabySrc[iX + 3])) << 4;
     125     7753430 :                     nRes |= (!(!pabySrc[iX + 4])) << 3;
     126     7753430 :                     nRes |= (!(!pabySrc[iX + 5])) << 2;
     127     7753430 :                     nRes |= (!(!pabySrc[iX + 6])) << 1;
     128     7753430 :                     nRes |= (!(!pabySrc[iX + 7])) << 0;
     129     7753430 :                     m_poGDS->m_pabyBlockBuf[iByteOffset] =
     130             :                         static_cast<GByte>(nRes);
     131             :                 }
     132      259413 :                 iBitOffset = iByteOffset * 8;
     133      259413 :                 if (iX < nBlockXSize)
     134             :                 {
     135        2198 :                     int nRes = 0;
     136        9669 :                     for (; iX < nBlockXSize; ++iX)
     137             :                     {
     138        7471 :                         if (pabySrc[iX])
     139        2902 :                             nRes |= (0x80 >> (iBitOffset & 7));
     140        7471 :                         ++iBitOffset;
     141             :                     }
     142        2198 :                     m_poGDS->m_pabyBlockBuf[iBitOffset >> 3] =
     143             :                         static_cast<GByte>(nRes);
     144             :                 }
     145             :             }
     146             : 
     147        8611 :             m_poGDS->m_bLoadedBlockDirty = true;
     148             : 
     149        8611 :             return CE_None;
     150             :         }
     151             : 
     152          92 :         if (eDataType == GDT_Float32 && m_poGDS->m_nBitsPerSample == 16)
     153             :         {
     154           0 :             for (; iPixel < static_cast<GPtrDiff_t>(nBlockYSize) * nBlockXSize;
     155             :                  iPixel++)
     156             :             {
     157           0 :                 GUInt32 nInWord = static_cast<GUInt32 *>(pImage)[iPixel];
     158           0 :                 bool bClipWarn = m_poGDS->m_bClipWarn;
     159           0 :                 GUInt16 nHalf = CPLFloatToHalf(nInWord, bClipWarn);
     160           0 :                 m_poGDS->m_bClipWarn = bClipWarn;
     161           0 :                 reinterpret_cast<GUInt16 *>(m_poGDS->m_pabyBlockBuf)[iPixel] =
     162             :                     nHalf;
     163             :             }
     164             : 
     165           0 :             m_poGDS->m_bLoadedBlockDirty = true;
     166             : 
     167           0 :             return CE_None;
     168             :         }
     169             : 
     170             :         // Initialize to zero as we set the buffer with binary or operations.
     171          92 :         if (m_poGDS->m_nBitsPerSample != 24)
     172          87 :             memset(m_poGDS->m_pabyBlockBuf, 0,
     173          87 :                    static_cast<size_t>((nBitsPerLine / 8) * nBlockYSize));
     174             : 
     175        3027 :         for (int iY = 0; iY < nBlockYSize; ++iY)
     176             :         {
     177        2935 :             GInt64 iBitOffset = iY * nBitsPerLine;
     178             : 
     179        2935 :             if (m_poGDS->m_nBitsPerSample == 12)
     180             :             {
     181       37814 :                 for (int iX = 0; iX < nBlockXSize; ++iX)
     182             :                 {
     183       37280 :                     GUInt32 nInWord = static_cast<GUInt16 *>(pImage)[iPixel++];
     184       37280 :                     if (nInWord > nMaxVal)
     185             :                     {
     186           0 :                         nInWord = nMaxVal;
     187           0 :                         if (!m_poGDS->m_bClipWarn)
     188             :                         {
     189           0 :                             m_poGDS->m_bClipWarn = true;
     190           0 :                             ReportError(
     191             :                                 CE_Warning, CPLE_AppDefined,
     192             :                                 "One or more pixels clipped to fit %d bit "
     193             :                                 "domain.",
     194           0 :                                 m_poGDS->m_nBitsPerSample);
     195             :                         }
     196             :                     }
     197             : 
     198       37280 :                     if ((iBitOffset % 8) == 0)
     199             :                     {
     200       18640 :                         m_poGDS->m_pabyBlockBuf[iBitOffset >> 3] =
     201       18640 :                             static_cast<GByte>(nInWord >> 4);
     202             :                         // Let 4 lower bits to zero as they're going to be
     203             :                         // overridden by the next word.
     204       18640 :                         m_poGDS->m_pabyBlockBuf[(iBitOffset >> 3) + 1] =
     205       18640 :                             static_cast<GByte>((nInWord & 0xf) << 4);
     206             :                     }
     207             :                     else
     208             :                     {
     209             :                         // Must or to preserve the 4 upper bits written
     210             :                         // for the previous word.
     211       18640 :                         m_poGDS->m_pabyBlockBuf[iBitOffset >> 3] |=
     212       18640 :                             static_cast<GByte>(nInWord >> 8);
     213       18640 :                         m_poGDS->m_pabyBlockBuf[(iBitOffset >> 3) + 1] =
     214             :                             static_cast<GByte>(nInWord & 0xff);
     215             :                     }
     216             : 
     217       37280 :                     iBitOffset += m_poGDS->m_nBitsPerSample;
     218             :                 }
     219         534 :                 continue;
     220             :             }
     221             : 
     222        2401 :             if (m_poGDS->m_nBitsPerSample == 10 && eDataType == GDT_UInt16)
     223             :             {
     224             :                 // Optimized 10-bit packing: 4 pixels -> 5 bytes.
     225             :                 // Avoids the generic per-bit loop which is ~10x slower.
     226          11 :                 const GUInt16 *pSrc =
     227          11 :                     static_cast<const GUInt16 *>(pImage) + iPixel;
     228          11 :                 GByte *pDst = m_poGDS->m_pabyBlockBuf + (iBitOffset >> 3);
     229          11 :                 int iX = 0;
     230          11 :                 const int nFastLimit = nBlockXSize - 3;  // may be <= 0
     231         155 :                 for (; iX < nFastLimit; iX += 4)
     232             :                 {
     233         144 :                     GUInt32 v0 = pSrc[0];
     234         144 :                     GUInt32 v1 = pSrc[1];
     235         144 :                     GUInt32 v2 = pSrc[2];
     236         144 :                     GUInt32 v3 = pSrc[3];
     237         144 :                     if ((v0 | v1 | v2 | v3) > nMaxVal)
     238             :                     {
     239           0 :                         v0 = std::min(v0, nMaxVal);
     240           0 :                         v1 = std::min(v1, nMaxVal);
     241           0 :                         v2 = std::min(v2, nMaxVal);
     242           0 :                         v3 = std::min(v3, nMaxVal);
     243           0 :                         if (!m_poGDS->m_bClipWarn)
     244             :                         {
     245           0 :                             m_poGDS->m_bClipWarn = true;
     246           0 :                             ReportError(
     247             :                                 CE_Warning, CPLE_AppDefined,
     248             :                                 "One or more pixels clipped to fit %d bit "
     249             :                                 "domain.",
     250           0 :                                 m_poGDS->m_nBitsPerSample);
     251             :                         }
     252             :                     }
     253         144 :                     pDst[0] = static_cast<GByte>(v0 >> 2);
     254         144 :                     pDst[1] = static_cast<GByte>((v0 << 6) | (v1 >> 4));
     255         144 :                     pDst[2] = static_cast<GByte>((v1 << 4) | (v2 >> 6));
     256         144 :                     pDst[3] = static_cast<GByte>((v2 << 2) | (v3 >> 8));
     257         144 :                     pDst[4] = static_cast<GByte>(v3);
     258         144 :                     pSrc += 4;
     259         144 :                     pDst += 5;
     260             :                 }
     261             :                 // Handle remaining 1-3 pixels with the generic per-bit path
     262          11 :                 iPixel += iX;
     263          11 :                 iBitOffset += static_cast<GInt64>(iX) * 10;
     264          25 :                 for (; iX < nBlockXSize; ++iX)
     265             :                 {
     266          14 :                     GUInt32 nInWord = static_cast<GUInt16 *>(pImage)[iPixel++];
     267          14 :                     if (nInWord > nMaxVal)
     268           0 :                         nInWord = nMaxVal;
     269         154 :                     for (int iBit = 0; iBit < 10; ++iBit)
     270             :                     {
     271         140 :                         if (nInWord & (1 << (9 - iBit)))
     272          23 :                             m_poGDS->m_pabyBlockBuf[iBitOffset >> 3] |=
     273          23 :                                 (0x80 >> (iBitOffset & 7));
     274         140 :                         ++iBitOffset;
     275             :                     }
     276             :                 }
     277          11 :                 continue;
     278             :             }
     279             : 
     280      368160 :             for (int iX = 0; iX < nBlockXSize; ++iX)
     281             :             {
     282      365770 :                 GUInt32 nInWord = 0;
     283      365770 :                 if (eDataType == GDT_UInt8)
     284             :                 {
     285      361568 :                     nInWord = static_cast<GByte *>(pImage)[iPixel++];
     286             :                 }
     287        4202 :                 else if (eDataType == GDT_UInt16)
     288             :                 {
     289        1401 :                     nInWord = static_cast<GUInt16 *>(pImage)[iPixel++];
     290             :                 }
     291        2801 :                 else if (eDataType == GDT_UInt32)
     292             :                 {
     293        2801 :                     nInWord = static_cast<GUInt32 *>(pImage)[iPixel++];
     294             :                 }
     295             :                 else
     296             :                 {
     297           0 :                     CPLAssert(false);
     298             :                 }
     299             : 
     300      365770 :                 if (nInWord > nMaxVal)
     301             :                 {
     302         400 :                     nInWord = nMaxVal;
     303         400 :                     if (!m_poGDS->m_bClipWarn)
     304             :                     {
     305           1 :                         m_poGDS->m_bClipWarn = true;
     306           1 :                         ReportError(
     307             :                             CE_Warning, CPLE_AppDefined,
     308             :                             "One or more pixels clipped to fit %d bit domain.",
     309           1 :                             m_poGDS->m_nBitsPerSample);
     310             :                     }
     311             :                 }
     312             : 
     313      365770 :                 if (m_poGDS->m_nBitsPerSample == 24)
     314             :                 {
     315             : /* -------------------------------------------------------------------- */
     316             : /*      Special case for 24bit data which is pre-byteswapped since      */
     317             : /*      the size falls on a byte boundary ... ugh (#2361).              */
     318             : /* -------------------------------------------------------------------- */
     319             : #ifdef CPL_MSB
     320             :                     m_poGDS->m_pabyBlockBuf[(iBitOffset >> 3) + 0] =
     321             :                         static_cast<GByte>(nInWord);
     322             :                     m_poGDS->m_pabyBlockBuf[(iBitOffset >> 3) + 1] =
     323             :                         static_cast<GByte>(nInWord >> 8);
     324             :                     m_poGDS->m_pabyBlockBuf[(iBitOffset >> 3) + 2] =
     325             :                         static_cast<GByte>(nInWord >> 16);
     326             : #else
     327        1400 :                     m_poGDS->m_pabyBlockBuf[(iBitOffset >> 3) + 0] =
     328        1400 :                         static_cast<GByte>(nInWord >> 16);
     329        1400 :                     m_poGDS->m_pabyBlockBuf[(iBitOffset >> 3) + 1] =
     330        1400 :                         static_cast<GByte>(nInWord >> 8);
     331        1400 :                     m_poGDS->m_pabyBlockBuf[(iBitOffset >> 3) + 2] =
     332             :                         static_cast<GByte>(nInWord);
     333             : #endif
     334        1400 :                     iBitOffset += 24;
     335             :                 }
     336             :                 else
     337             :                 {
     338     2930970 :                     for (int iBit = 0; iBit < m_poGDS->m_nBitsPerSample; ++iBit)
     339             :                     {
     340     2566600 :                         if (nInWord &
     341     2566600 :                             (1 << (m_poGDS->m_nBitsPerSample - 1 - iBit)))
     342      256612 :                             m_poGDS->m_pabyBlockBuf[iBitOffset >> 3] |=
     343      256612 :                                 (0x80 >> (iBitOffset & 7));
     344     2566600 :                         ++iBitOffset;
     345             :                     }
     346             :                 }
     347             :             }
     348             :         }
     349             : 
     350          92 :         m_poGDS->m_bLoadedBlockDirty = true;
     351             : 
     352          92 :         return CE_None;
     353             :     }
     354             : 
     355             :     /* -------------------------------------------------------------------- */
     356             :     /*      Handle case of pixel interleaved (PLANARCONFIG_CONTIG) images.  */
     357             :     /* -------------------------------------------------------------------- */
     358             : 
     359             :     /* -------------------------------------------------------------------- */
     360             :     /*      On write of pixel interleaved data, we might as well flush      */
     361             :     /*      out any other bands that are dirty in our cache.  This is       */
     362             :     /*      especially helpful when writing compressed blocks.              */
     363             :     /* -------------------------------------------------------------------- */
     364         442 :     for (int iBand = 0; iBand < m_poGDS->nBands; ++iBand)
     365             :     {
     366         331 :         const GByte *pabyThisImage = nullptr;
     367         331 :         GDALRasterBlock *poBlock = nullptr;
     368             : 
     369         331 :         if (iBand + 1 == nBand)
     370             :         {
     371         111 :             pabyThisImage = static_cast<GByte *>(pImage);
     372             :         }
     373             :         else
     374             :         {
     375         220 :             poBlock = cpl::down_cast<GTiffOddBitsBand *>(
     376         220 :                           m_poGDS->GetRasterBand(iBand + 1))
     377         220 :                           ->TryGetLockedBlockRef(nBlockXOff, nBlockYOff);
     378             : 
     379         220 :             if (poBlock == nullptr)
     380          11 :                 continue;
     381             : 
     382         209 :             if (!poBlock->GetDirty())
     383             :             {
     384           3 :                 poBlock->DropLock();
     385           3 :                 continue;
     386             :             }
     387             : 
     388         206 :             pabyThisImage = static_cast<GByte *>(poBlock->GetDataRef());
     389             :         }
     390             : 
     391         317 :         const int iPixelBitSkip = m_poGDS->m_nBitsPerSample * m_poGDS->nBands;
     392         317 :         const int iBandBitOffset = iBand * m_poGDS->m_nBitsPerSample;
     393             : 
     394             :         // Bits per line rounds up to next byte boundary.
     395         317 :         GInt64 nBitsPerLine = static_cast<GInt64>(nBlockXSize) * iPixelBitSkip;
     396         317 :         if ((nBitsPerLine & 7) != 0)
     397          16 :             nBitsPerLine = (nBitsPerLine + 7) & (~7);
     398             : 
     399         317 :         GPtrDiff_t iPixel = 0;
     400             : 
     401         317 :         if (eDataType == GDT_Float32 && m_poGDS->m_nBitsPerSample == 16)
     402             :         {
     403           0 :             for (; iPixel < static_cast<GPtrDiff_t>(nBlockYSize) * nBlockXSize;
     404             :                  iPixel++)
     405             :             {
     406           0 :                 GUInt32 nInWord =
     407           0 :                     reinterpret_cast<const GUInt32 *>(pabyThisImage)[iPixel];
     408           0 :                 bool bClipWarn = m_poGDS->m_bClipWarn;
     409           0 :                 GUInt16 nHalf = CPLFloatToHalf(nInWord, bClipWarn);
     410           0 :                 m_poGDS->m_bClipWarn = bClipWarn;
     411             :                 reinterpret_cast<GUInt16 *>(
     412           0 :                     m_poGDS->m_pabyBlockBuf)[iPixel * m_poGDS->nBands + iBand] =
     413             :                     nHalf;
     414             :             }
     415             : 
     416           0 :             if (poBlock != nullptr)
     417             :             {
     418           0 :                 poBlock->MarkClean();
     419           0 :                 poBlock->DropLock();
     420             :             }
     421           0 :             continue;
     422             :         }
     423             : 
     424        5547 :         for (int iY = 0; iY < nBlockYSize; ++iY)
     425             :         {
     426        5230 :             GInt64 iBitOffset = iBandBitOffset + iY * nBitsPerLine;
     427             : 
     428        5230 :             if (m_poGDS->m_nBitsPerSample == 12)
     429             :             {
     430       29704 :                 for (int iX = 0; iX < nBlockXSize; ++iX)
     431             :                 {
     432             :                     GUInt32 nInWord = reinterpret_cast<const GUInt16 *>(
     433       29048 :                         pabyThisImage)[iPixel++];
     434       29048 :                     if (nInWord > nMaxVal)
     435             :                     {
     436           0 :                         nInWord = nMaxVal;
     437           0 :                         if (!m_poGDS->m_bClipWarn)
     438             :                         {
     439           0 :                             m_poGDS->m_bClipWarn = true;
     440           0 :                             ReportError(
     441             :                                 CE_Warning, CPLE_AppDefined,
     442             :                                 "One or more pixels clipped to fit %d bit "
     443             :                                 "domain.",
     444           0 :                                 m_poGDS->m_nBitsPerSample);
     445             :                         }
     446             :                     }
     447             : 
     448       29048 :                     if ((iBitOffset % 8) == 0)
     449             :                     {
     450       14624 :                         m_poGDS->m_pabyBlockBuf[iBitOffset >> 3] =
     451       14624 :                             static_cast<GByte>(nInWord >> 4);
     452       14624 :                         m_poGDS->m_pabyBlockBuf[(iBitOffset >> 3) + 1] =
     453             :                             static_cast<GByte>(
     454       14624 :                                 ((nInWord & 0xf) << 4) |
     455       14624 :                                 (m_poGDS
     456       14624 :                                      ->m_pabyBlockBuf[(iBitOffset >> 3) + 1] &
     457             :                                  0xf));
     458             :                     }
     459             :                     else
     460             :                     {
     461       14424 :                         m_poGDS->m_pabyBlockBuf[iBitOffset >> 3] =
     462             :                             static_cast<GByte>(
     463       14424 :                                 (m_poGDS->m_pabyBlockBuf[iBitOffset >> 3] &
     464       14424 :                                  0xf0) |
     465       14424 :                                 (nInWord >> 8));
     466       14424 :                         m_poGDS->m_pabyBlockBuf[(iBitOffset >> 3) + 1] =
     467             :                             static_cast<GByte>(nInWord & 0xff);
     468             :                     }
     469             : 
     470       29048 :                     iBitOffset += iPixelBitSkip;
     471             :                 }
     472         656 :                 continue;
     473             :             }
     474             : 
     475      382340 :             for (int iX = 0; iX < nBlockXSize; ++iX)
     476             :             {
     477      377766 :                 GUInt32 nInWord = 0;
     478      377766 :                 if (eDataType == GDT_UInt8)
     479             :                 {
     480      179166 :                     nInWord =
     481      179166 :                         static_cast<const GByte *>(pabyThisImage)[iPixel++];
     482             :                 }
     483      198600 :                 else if (eDataType == GDT_UInt16)
     484             :                 {
     485      195800 :                     nInWord = reinterpret_cast<const GUInt16 *>(
     486      195800 :                         pabyThisImage)[iPixel++];
     487             :                 }
     488        2800 :                 else if (eDataType == GDT_UInt32)
     489             :                 {
     490        2800 :                     nInWord = reinterpret_cast<const GUInt32 *>(
     491        2800 :                         pabyThisImage)[iPixel++];
     492             :                 }
     493             :                 else
     494             :                 {
     495           0 :                     CPLAssert(false);
     496             :                 }
     497             : 
     498      377766 :                 if (nInWord > nMaxVal)
     499             :                 {
     500       15154 :                     nInWord = nMaxVal;
     501       15154 :                     if (!m_poGDS->m_bClipWarn)
     502             :                     {
     503           3 :                         m_poGDS->m_bClipWarn = true;
     504           3 :                         ReportError(
     505             :                             CE_Warning, CPLE_AppDefined,
     506             :                             "One or more pixels clipped to fit %d bit domain.",
     507           3 :                             m_poGDS->m_nBitsPerSample);
     508             :                     }
     509             :                 }
     510             : 
     511      377766 :                 if (m_poGDS->m_nBitsPerSample == 24)
     512             :                 {
     513             : /* -------------------------------------------------------------------- */
     514             : /*      Special case for 24bit data which is pre-byteswapped since      */
     515             : /*      the size falls on a byte boundary ... ugh (#2361).              */
     516             : /* -------------------------------------------------------------------- */
     517             : #ifdef CPL_MSB
     518             :                     m_poGDS->m_pabyBlockBuf[(iBitOffset >> 3) + 0] =
     519             :                         static_cast<GByte>(nInWord);
     520             :                     m_poGDS->m_pabyBlockBuf[(iBitOffset >> 3) + 1] =
     521             :                         static_cast<GByte>(nInWord >> 8);
     522             :                     m_poGDS->m_pabyBlockBuf[(iBitOffset >> 3) + 2] =
     523             :                         static_cast<GByte>(nInWord >> 16);
     524             : #else
     525        1400 :                     m_poGDS->m_pabyBlockBuf[(iBitOffset >> 3) + 0] =
     526        1400 :                         static_cast<GByte>(nInWord >> 16);
     527        1400 :                     m_poGDS->m_pabyBlockBuf[(iBitOffset >> 3) + 1] =
     528        1400 :                         static_cast<GByte>(nInWord >> 8);
     529        1400 :                     m_poGDS->m_pabyBlockBuf[(iBitOffset >> 3) + 2] =
     530             :                         static_cast<GByte>(nInWord);
     531             : #endif
     532        1400 :                     iBitOffset += 24;
     533             :                 }
     534             :                 else
     535             :                 {
     536     4581720 :                     for (int iBit = 0; iBit < m_poGDS->m_nBitsPerSample; ++iBit)
     537             :                     {
     538             :                         // TODO(schwehr): Revisit this block.
     539     4205360 :                         if (nInWord &
     540     4205360 :                             (1 << (m_poGDS->m_nBitsPerSample - 1 - iBit)))
     541             :                         {
     542      800149 :                             m_poGDS->m_pabyBlockBuf[iBitOffset >> 3] |=
     543      800149 :                                 (0x80 >> (iBitOffset & 7));
     544             :                         }
     545             :                         else
     546             :                         {
     547             :                             // We must explicitly unset the bit as we
     548             :                             // may update an existing block.
     549     3405210 :                             m_poGDS->m_pabyBlockBuf[iBitOffset >> 3] &=
     550     3405210 :                                 ~(0x80 >> (iBitOffset & 7));
     551             :                         }
     552             : 
     553     4205360 :                         ++iBitOffset;
     554             :                     }
     555             :                 }
     556             : 
     557      377766 :                 iBitOffset =
     558      377766 :                     iBitOffset + iPixelBitSkip - m_poGDS->m_nBitsPerSample;
     559             :             }
     560             :         }
     561             : 
     562         317 :         if (poBlock != nullptr)
     563             :         {
     564         206 :             poBlock->MarkClean();
     565         206 :             poBlock->DropLock();
     566             :         }
     567             :     }
     568             : 
     569         111 :     m_poGDS->m_bLoadedBlockDirty = true;
     570             : 
     571         111 :     return CE_None;
     572             : }
     573             : 
     574             : /************************************************************************/
     575             : /*                             IReadBlock()                             */
     576             : /************************************************************************/
     577             : 
     578        7100 : CPLErr GTiffOddBitsBand::IReadBlock(int nBlockXOff, int nBlockYOff,
     579             :                                     void *pImage)
     580             : 
     581             : {
     582        7100 :     m_poGDS->Crystalize();
     583             : 
     584        7100 :     const int nBlockId = ComputeBlockId(nBlockXOff, nBlockYOff);
     585             : 
     586             :     /* -------------------------------------------------------------------- */
     587             :     /*      Handle the case of a strip in a writable file that doesn't      */
     588             :     /*      exist yet, but that we want to read.  Just set to zeros and     */
     589             :     /*      return.                                                         */
     590             :     /* -------------------------------------------------------------------- */
     591        7100 :     if (nBlockId != m_poGDS->m_nLoadedBlock)
     592             :     {
     593        7053 :         bool bErrOccurred = false;
     594        7053 :         if (!m_poGDS->IsBlockAvailable(nBlockId, nullptr, nullptr,
     595             :                                        &bErrOccurred))
     596             :         {
     597        4705 :             NullBlock(pImage);
     598        4705 :             if (bErrOccurred)
     599        4705 :                 return CE_Failure;
     600        4705 :             return CE_None;
     601             :         }
     602             :     }
     603             : 
     604             :     /* -------------------------------------------------------------------- */
     605             :     /*      Load the block buffer.                                          */
     606             :     /* -------------------------------------------------------------------- */
     607             :     {
     608        2395 :         const CPLErr eErr = m_poGDS->LoadBlockBuf(nBlockId);
     609        2395 :         if (eErr != CE_None)
     610           0 :             return eErr;
     611             :     }
     612             : 
     613        2395 :     if (m_poGDS->m_nBitsPerSample == 1 &&
     614        1971 :         (m_poGDS->nBands == 1 ||
     615          28 :          m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE))
     616             :     {
     617             :         // Translate 1bit data to eight bit.
     618        1947 :         const GByte *CPL_RESTRICT pabySrc = m_poGDS->m_pabyBlockBuf;
     619        1947 :         GByte *CPL_RESTRICT pabyDest = static_cast<GByte *>(pImage);
     620        1947 :         const int nSrcInc = cpl::div_round_up(nBlockXSize, 8);
     621             : 
     622       53235 :         for (int iLine = 0; iLine < nBlockYSize; ++iLine)
     623             :         {
     624       51288 :             if (m_poGDS->m_bPromoteTo8Bits)
     625             :             {
     626       44694 :                 GDALExpandPackedBitsToByteAt0Or255(pabySrc, pabyDest,
     627       44694 :                                                    nBlockXSize);
     628             :             }
     629             :             else
     630             :             {
     631        6594 :                 GDALExpandPackedBitsToByteAt0Or1(pabySrc, pabyDest,
     632        6594 :                                                  nBlockXSize);
     633             :             }
     634       51288 :             pabySrc += nSrcInc;
     635       51288 :             pabyDest += nBlockXSize;
     636        1947 :         }
     637             :     }
     638             :     /* -------------------------------------------------------------------- */
     639             :     /*      Handle the case of 16- and 24-bit floating point data as per    */
     640             :     /*      TIFF Technical Note 3.                                          */
     641             :     /* -------------------------------------------------------------------- */
     642         448 :     else if (eDataType == GDT_Float32)
     643             :     {
     644           1 :         const int nWordBytes = m_poGDS->m_nBitsPerSample / 8;
     645           1 :         const GByte *pabyImage =
     646           0 :             m_poGDS->m_pabyBlockBuf +
     647           1 :             ((m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE)
     648             :                  ? 0
     649           1 :                  : (nBand - 1) * nWordBytes);
     650           1 :         const int iSkipBytes =
     651           1 :             (m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE)
     652           1 :                 ? nWordBytes
     653           1 :                 : m_poGDS->nBands * nWordBytes;
     654             : 
     655           1 :         const auto nBlockPixels =
     656           1 :             static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize;
     657           1 :         if (m_poGDS->m_nBitsPerSample == 16)
     658             :         {
     659           0 :             for (GPtrDiff_t i = 0; i < nBlockPixels; ++i)
     660             :             {
     661           0 :                 static_cast<GUInt32 *>(pImage)[i] = CPLHalfToFloat(
     662           0 :                     *reinterpret_cast<const GUInt16 *>(pabyImage));
     663           0 :                 pabyImage += iSkipBytes;
     664             :             }
     665             :         }
     666           1 :         else if (m_poGDS->m_nBitsPerSample == 24)
     667             :         {
     668         401 :             for (GPtrDiff_t i = 0; i < nBlockPixels; ++i)
     669             :             {
     670             : #ifdef CPL_MSB
     671             :                 static_cast<GUInt32 *>(pImage)[i] = CPLTripleToFloat(
     672             :                     (static_cast<GUInt32>(*(pabyImage + 0)) << 16) |
     673             :                     (static_cast<GUInt32>(*(pabyImage + 1)) << 8) |
     674             :                     static_cast<GUInt32>(*(pabyImage + 2)));
     675             : #else
     676         800 :                 static_cast<GUInt32 *>(pImage)[i] = CPLTripleToFloat(
     677         400 :                     (static_cast<GUInt32>(*(pabyImage + 2)) << 16) |
     678         400 :                     (static_cast<GUInt32>(*(pabyImage + 1)) << 8) |
     679         400 :                     static_cast<GUInt32>(*pabyImage));
     680             : #endif
     681         400 :                 pabyImage += iSkipBytes;
     682             :             }
     683             :         }
     684             :     }
     685             : 
     686             :     /* -------------------------------------------------------------------- */
     687             :     /*      Special case for moving 12bit data somewhat more efficiently.   */
     688             :     /* -------------------------------------------------------------------- */
     689         447 :     else if (m_poGDS->m_nBitsPerSample == 12)
     690             :     {
     691          38 :         int iPixelBitSkip = 0;
     692          38 :         int iBandBitOffset = 0;
     693             : 
     694          38 :         if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG)
     695             :         {
     696          29 :             iPixelBitSkip = m_poGDS->nBands * m_poGDS->m_nBitsPerSample;
     697          29 :             iBandBitOffset = (nBand - 1) * m_poGDS->m_nBitsPerSample;
     698             :         }
     699             :         else
     700             :         {
     701           9 :             iPixelBitSkip = m_poGDS->m_nBitsPerSample;
     702             :         }
     703             : 
     704             :         // Bits per line rounds up to next byte boundary.
     705          38 :         GPtrDiff_t nBitsPerLine =
     706          38 :             static_cast<GPtrDiff_t>(nBlockXSize) * iPixelBitSkip;
     707          38 :         if ((nBitsPerLine & 7) != 0)
     708           0 :             nBitsPerLine = (nBitsPerLine + 7) & (~7);
     709             : 
     710          38 :         int iPixel = 0;
     711        1184 :         for (int iY = 0; iY < nBlockYSize; ++iY)
     712             :         {
     713        1146 :             GPtrDiff_t iBitOffset = iBandBitOffset + iY * nBitsPerLine;
     714             : 
     715       72994 :             for (int iX = 0; iX < nBlockXSize; ++iX)
     716             :             {
     717       71848 :                 const auto iByte = iBitOffset >> 3;
     718             : 
     719       71848 :                 if ((iBitOffset & 0x7) == 0)
     720             :                 {
     721             :                     // Starting on byte boundary.
     722             : 
     723       36792 :                     static_cast<GUInt16 *>(pImage)[iPixel++] =
     724       36792 :                         (m_poGDS->m_pabyBlockBuf[iByte] << 4) |
     725       36792 :                         (m_poGDS->m_pabyBlockBuf[iByte + 1] >> 4);
     726             :                 }
     727             :                 else
     728             :                 {
     729             :                     // Starting off byte boundary.
     730             : 
     731       35056 :                     static_cast<GUInt16 *>(pImage)[iPixel++] =
     732       35056 :                         ((m_poGDS->m_pabyBlockBuf[iByte] & 0xf) << 8) |
     733       35056 :                         (m_poGDS->m_pabyBlockBuf[iByte + 1]);
     734             :                 }
     735       71848 :                 iBitOffset += iPixelBitSkip;
     736             :             }
     737             :         }
     738             :     }
     739             : 
     740             :     /* -------------------------------------------------------------------- */
     741             :     /*      Special case for 24bit data which is pre-byteswapped since      */
     742             :     /*      the size falls on a byte boundary ... ugh (#2361).              */
     743             :     /* -------------------------------------------------------------------- */
     744         409 :     else if (m_poGDS->m_nBitsPerSample == 24)
     745             :     {
     746          11 :         int iPixelByteSkip = 0;
     747          11 :         int iBandByteOffset = 0;
     748             : 
     749          11 :         if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG)
     750             :         {
     751           8 :             iPixelByteSkip = (m_poGDS->nBands * m_poGDS->m_nBitsPerSample) / 8;
     752           8 :             iBandByteOffset = ((nBand - 1) * m_poGDS->m_nBitsPerSample) / 8;
     753             :         }
     754             :         else
     755             :         {
     756           3 :             iPixelByteSkip = m_poGDS->m_nBitsPerSample / 8;
     757             :         }
     758             : 
     759          11 :         const GPtrDiff_t nBytesPerLine =
     760          11 :             static_cast<GPtrDiff_t>(nBlockXSize) * iPixelByteSkip;
     761             : 
     762          11 :         GPtrDiff_t iPixel = 0;
     763         191 :         for (int iY = 0; iY < nBlockYSize; ++iY)
     764             :         {
     765         180 :             GByte *pabyImage =
     766         180 :                 m_poGDS->m_pabyBlockBuf + iBandByteOffset + iY * nBytesPerLine;
     767             : 
     768        3380 :             for (int iX = 0; iX < nBlockXSize; ++iX)
     769             :             {
     770             : #ifdef CPL_MSB
     771             :                 static_cast<GUInt32 *>(pImage)[iPixel++] =
     772             :                     (static_cast<GUInt32>(*(pabyImage + 2)) << 16) |
     773             :                     (static_cast<GUInt32>(*(pabyImage + 1)) << 8) |
     774             :                     static_cast<GUInt32>(*(pabyImage + 0));
     775             : #else
     776        3200 :                 static_cast<GUInt32 *>(pImage)[iPixel++] =
     777        3200 :                     (static_cast<GUInt32>(*(pabyImage + 0)) << 16) |
     778        3200 :                     (static_cast<GUInt32>(*(pabyImage + 1)) << 8) |
     779        3200 :                     static_cast<GUInt32>(*(pabyImage + 2));
     780             : #endif
     781        3200 :                 pabyImage += iPixelByteSkip;
     782             :             }
     783             :         }
     784             :     }
     785             : 
     786             :     /* -------------------------------------------------------------------- */
     787             :     /*      Handle 1-32 bit integer data.                                   */
     788             :     /* -------------------------------------------------------------------- */
     789             :     else
     790             :     {
     791         398 :         unsigned iPixelBitSkip = 0;
     792         398 :         unsigned iBandBitOffset = 0;
     793             : 
     794         398 :         if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG)
     795             :         {
     796         392 :             iPixelBitSkip = m_poGDS->nBands * m_poGDS->m_nBitsPerSample;
     797         392 :             iBandBitOffset = (nBand - 1) * m_poGDS->m_nBitsPerSample;
     798             :         }
     799             :         else
     800             :         {
     801           6 :             iPixelBitSkip = m_poGDS->m_nBitsPerSample;
     802             :         }
     803             : 
     804             :         // Bits per line rounds up to next byte boundary.
     805         398 :         GUIntBig nBitsPerLine =
     806         398 :             static_cast<GUIntBig>(nBlockXSize) * iPixelBitSkip;
     807         398 :         if ((nBitsPerLine & 7) != 0)
     808          59 :             nBitsPerLine = (nBitsPerLine + 7) & (~7);
     809             : 
     810         398 :         const GByte *const m_pabyBlockBuf = m_poGDS->m_pabyBlockBuf;
     811         398 :         const unsigned nBitsPerSample = m_poGDS->m_nBitsPerSample;
     812         398 :         GPtrDiff_t iPixel = 0;
     813             : 
     814         398 :         if (nBitsPerSample == 1 && eDataType == GDT_UInt8)
     815             :         {
     816        1851 :             for (unsigned iY = 0; iY < static_cast<unsigned>(nBlockYSize); ++iY)
     817             :             {
     818        1827 :                 GUIntBig iBitOffset = iBandBitOffset + iY * nBitsPerLine;
     819             : 
     820      171892 :                 for (unsigned iX = 0; iX < static_cast<unsigned>(nBlockXSize);
     821             :                      ++iX)
     822             :                 {
     823      170065 :                     if (m_pabyBlockBuf[iBitOffset >> 3] &
     824      170065 :                         (0x80 >> (iBitOffset & 7)))
     825      102120 :                         static_cast<GByte *>(pImage)[iPixel] = 1;
     826             :                     else
     827       67945 :                         static_cast<GByte *>(pImage)[iPixel] = 0;
     828      170065 :                     iBitOffset += iPixelBitSkip;
     829      170065 :                     iPixel++;
     830             :                 }
     831          24 :             }
     832             :         }
     833             :         else
     834             :         {
     835        7446 :             for (unsigned iY = 0; iY < static_cast<unsigned>(nBlockYSize); ++iY)
     836             :             {
     837        7072 :                 GUIntBig iBitOffset = iBandBitOffset + iY * nBitsPerLine;
     838             : 
     839      499125 :                 for (unsigned iX = 0; iX < static_cast<unsigned>(nBlockXSize);
     840             :                      ++iX)
     841             :                 {
     842      492053 :                     unsigned nOutWord = 0;
     843             : 
     844     5527330 :                     for (unsigned iBit = 0; iBit < nBitsPerSample; ++iBit)
     845             :                     {
     846     5035280 :                         if (m_pabyBlockBuf[iBitOffset >> 3] &
     847     5035280 :                             (0x80 >> (iBitOffset & 7)))
     848     1093360 :                             nOutWord |= (1 << (nBitsPerSample - 1 - iBit));
     849     5035280 :                         ++iBitOffset;
     850             :                     }
     851             : 
     852      492053 :                     iBitOffset = iBitOffset + iPixelBitSkip - nBitsPerSample;
     853             : 
     854      492053 :                     if (eDataType == GDT_UInt8)
     855             :                     {
     856      291061 :                         static_cast<GByte *>(pImage)[iPixel++] =
     857             :                             static_cast<GByte>(nOutWord);
     858             :                     }
     859      200992 :                     else if (eDataType == GDT_UInt16)
     860             :                     {
     861      198191 :                         static_cast<GUInt16 *>(pImage)[iPixel++] =
     862             :                             static_cast<GUInt16>(nOutWord);
     863             :                     }
     864        2801 :                     else if (eDataType == GDT_UInt32)
     865             :                     {
     866        2801 :                         static_cast<GUInt32 *>(pImage)[iPixel++] = nOutWord;
     867             :                     }
     868             :                     else
     869             :                     {
     870           0 :                         CPLAssert(false);
     871             :                     }
     872             :                 }
     873             :             }
     874             :         }
     875             :     }
     876             : 
     877        2395 :     CacheMaskForBlock(nBlockXOff, nBlockYOff);
     878             : 
     879        2395 :     return CE_None;
     880             : }

Generated by: LCOV version 1.14