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

Generated by: LCOV version 1.14