Coverage Report

Created: 2025-11-15 08:43

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