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 775 : GTiffOddBitsBand::GTiffOddBitsBand(GTiffDataset *m_poGDSIn, int nBandIn)
25 775 : : GTiffRasterBand(m_poGDSIn, nBandIn)
26 :
27 : {
28 775 : eDataType = GDT_Unknown;
29 775 : 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 749 : else if ((m_poGDS->m_nSampleFormat == SAMPLEFORMAT_UINT ||
35 2 : m_poGDS->m_nSampleFormat == SAMPLEFORMAT_INT) &&
36 749 : m_poGDS->m_nBitsPerSample < 8)
37 510 : 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 775 : }
47 :
48 : /************************************************************************/
49 : /* IWriteBlock() */
50 : /************************************************************************/
51 :
52 7308 : CPLErr GTiffOddBitsBand::IWriteBlock(int nBlockXOff, int nBlockYOff,
53 : void *pImage)
54 :
55 : {
56 7308 : m_poGDS->Crystalize();
57 :
58 7308 : 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 7308 : 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 7308 : const int nBlockId = ComputeBlockId(nBlockXOff, nBlockYOff);
78 :
79 : // Only read content from disk in the CONTIG case.
80 : {
81 7308 : const CPLErr eErr = m_poGDS->LoadBlockBuf(
82 14525 : nBlockId, m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG &&
83 7217 : m_poGDS->nBands > 1);
84 7308 : if (eErr != CE_None)
85 0 : return eErr;
86 : }
87 :
88 7308 : 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 7308 : if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE ||
95 7217 : m_poGDS->nBands == 1)
96 : {
97 : // TODO(schwehr): Create a CplNumBits8Aligned.
98 : // Bits per line rounds up to next byte boundary.
99 7197 : GInt64 nBitsPerLine =
100 7197 : static_cast<GInt64>(nBlockXSize) * m_poGDS->m_nBitsPerSample;
101 7197 : if ((nBitsPerLine & 7) != 0)
102 62 : nBitsPerLine = (nBitsPerLine + 7) & (~7);
103 :
104 7197 : GPtrDiff_t iPixel = 0;
105 :
106 : // Small optimization in 1 bit case.
107 7197 : if (m_poGDS->m_nBitsPerSample == 1)
108 : {
109 244568 : for (int iY = 0; iY < nBlockYSize; ++iY, iPixel += nBlockXSize)
110 : {
111 237515 : GInt64 iBitOffset = iY * nBitsPerLine;
112 :
113 237515 : const GByte *pabySrc =
114 237515 : static_cast<const GByte *>(pImage) + iPixel;
115 237515 : auto iByteOffset = iBitOffset / 8;
116 237515 : int iX = 0; // Used after for.
117 6735920 : for (; iX + 7 < nBlockXSize; iX += 8, iByteOffset++)
118 : {
119 6498410 : int nRes = (!(!pabySrc[iX + 0])) << 7;
120 6498410 : nRes |= (!(!pabySrc[iX + 1])) << 6;
121 6498410 : nRes |= (!(!pabySrc[iX + 2])) << 5;
122 6498410 : nRes |= (!(!pabySrc[iX + 3])) << 4;
123 6498410 : nRes |= (!(!pabySrc[iX + 4])) << 3;
124 6498410 : nRes |= (!(!pabySrc[iX + 5])) << 2;
125 6498410 : nRes |= (!(!pabySrc[iX + 6])) << 1;
126 6498410 : nRes |= (!(!pabySrc[iX + 7])) << 0;
127 6498410 : m_poGDS->m_pabyBlockBuf[iByteOffset] =
128 : static_cast<GByte>(nRes);
129 : }
130 237515 : iBitOffset = iByteOffset * 8;
131 237515 : if (iX < nBlockXSize)
132 : {
133 2088 : int nRes = 0;
134 9219 : for (; iX < nBlockXSize; ++iX)
135 : {
136 7131 : if (pabySrc[iX])
137 2452 : nRes |= (0x80 >> (iBitOffset & 7));
138 7131 : ++iBitOffset;
139 : }
140 2088 : m_poGDS->m_pabyBlockBuf[iBitOffset >> 3] =
141 : static_cast<GByte>(nRes);
142 : }
143 : }
144 :
145 7053 : m_poGDS->m_bLoadedBlockDirty = true;
146 :
147 7053 : 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 344 : nInWord = nMaxVal;
441 344 : 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 699473 : m_poGDS->m_pabyBlockBuf[iBitOffset >> 3] |=
483 699473 : (0x80 >> (iBitOffset & 7));
484 : }
485 : else
486 : {
487 : // We must explicitly unset the bit as we
488 : // may update an existing block.
489 3505880 : m_poGDS->m_pabyBlockBuf[iBitOffset >> 3] &=
490 3505880 : ~(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 6594 : static void ExpandPacked8ToByte1(const GByte *const CPL_RESTRICT pabySrc,
519 : GByte *const CPL_RESTRICT pabyDest,
520 : GPtrDiff_t nBytes)
521 : {
522 141502 : for (decltype(nBytes) i = 0, j = 0; i < nBytes; i++, j += 8)
523 : {
524 134908 : const GByte byVal = pabySrc[i];
525 134908 : pabyDest[j + 0] = (byVal >> 7) & 0x1;
526 134908 : pabyDest[j + 1] = (byVal >> 6) & 0x1;
527 134908 : pabyDest[j + 2] = (byVal >> 5) & 0x1;
528 134908 : pabyDest[j + 3] = (byVal >> 4) & 0x1;
529 134908 : pabyDest[j + 4] = (byVal >> 3) & 0x1;
530 134908 : pabyDest[j + 5] = (byVal >> 2) & 0x1;
531 134908 : pabyDest[j + 6] = (byVal >> 1) & 0x1;
532 134908 : pabyDest[j + 7] = (byVal >> 0) & 0x1;
533 : }
534 6594 : }
535 :
536 : #if defined(__GNUC__) || defined(_MSC_VER)
537 : // Signedness of char implementation dependent, so be explicit.
538 : // Assumes 2-complement integer types and sign extension of right shifting
539 : // GCC guarantees such:
540 : // https://gcc.gnu.org/onlinedocs/gcc/Integers-implementation.html#Integers-implementation
541 6168190 : static inline GByte ExtractBitAndConvertTo255(GByte byVal, int nBit)
542 : {
543 6168190 : return static_cast<GByte>(static_cast<signed char>(byVal << (7 - nBit)) >>
544 6168190 : 7);
545 : }
546 : #else
547 : // Portable way
548 : static inline GByte ExtractBitAndConvertTo255(GByte byVal, int nBit)
549 : {
550 : return (byVal & (1 << nBit)) ? 255 : 0;
551 : }
552 : #endif
553 :
554 30234 : static void ExpandPacked8ToByte255(const GByte *const CPL_RESTRICT pabySrc,
555 : GByte *const CPL_RESTRICT pabyDest,
556 : GPtrDiff_t nBytes)
557 : {
558 801258 : for (decltype(nBytes) i = 0, j = 0; i < nBytes; i++, j += 8)
559 : {
560 771024 : const GByte byVal = pabySrc[i];
561 771024 : pabyDest[j + 0] = ExtractBitAndConvertTo255(byVal, 7);
562 771024 : pabyDest[j + 1] = ExtractBitAndConvertTo255(byVal, 6);
563 771024 : pabyDest[j + 2] = ExtractBitAndConvertTo255(byVal, 5);
564 771024 : pabyDest[j + 3] = ExtractBitAndConvertTo255(byVal, 4);
565 771024 : pabyDest[j + 4] = ExtractBitAndConvertTo255(byVal, 3);
566 771024 : pabyDest[j + 5] = ExtractBitAndConvertTo255(byVal, 2);
567 771024 : pabyDest[j + 6] = ExtractBitAndConvertTo255(byVal, 1);
568 771024 : pabyDest[j + 7] = ExtractBitAndConvertTo255(byVal, 0);
569 : }
570 30234 : }
571 :
572 5561 : CPLErr GTiffOddBitsBand::IReadBlock(int nBlockXOff, int nBlockYOff,
573 : void *pImage)
574 :
575 : {
576 5561 : m_poGDS->Crystalize();
577 :
578 5561 : const int nBlockId = ComputeBlockId(nBlockXOff, nBlockYOff);
579 :
580 : /* -------------------------------------------------------------------- */
581 : /* Handle the case of a strip in a writable file that doesn't */
582 : /* exist yet, but that we want to read. Just set to zeros and */
583 : /* return. */
584 : /* -------------------------------------------------------------------- */
585 5561 : if (nBlockId != m_poGDS->m_nLoadedBlock)
586 : {
587 5514 : bool bErrOccurred = false;
588 5514 : if (!m_poGDS->IsBlockAvailable(nBlockId, nullptr, nullptr,
589 : &bErrOccurred))
590 : {
591 4674 : NullBlock(pImage);
592 4674 : if (bErrOccurred)
593 4674 : return CE_Failure;
594 4674 : return CE_None;
595 : }
596 : }
597 :
598 : /* -------------------------------------------------------------------- */
599 : /* Load the block buffer. */
600 : /* -------------------------------------------------------------------- */
601 : {
602 887 : const CPLErr eErr = m_poGDS->LoadBlockBuf(nBlockId);
603 887 : if (eErr != CE_None)
604 0 : return eErr;
605 : }
606 :
607 887 : if (m_poGDS->m_nBitsPerSample == 1 &&
608 429 : (m_poGDS->nBands == 1 ||
609 28 : m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE))
610 : {
611 : /* --------------------------------------------------------------------
612 : */
613 : /* Translate 1bit data to eight bit. */
614 : /* --------------------------------------------------------------------
615 : */
616 405 : GPtrDiff_t iDstOffset = 0;
617 405 : const GByte *const CPL_RESTRICT m_pabyBlockBuf =
618 405 : m_poGDS->m_pabyBlockBuf;
619 405 : GByte *CPL_RESTRICT pabyDest = static_cast<GByte *>(pImage);
620 :
621 37233 : for (int iLine = 0; iLine < nBlockYSize; ++iLine)
622 : {
623 36828 : GPtrDiff_t iSrcOffsetByte =
624 36828 : static_cast<GPtrDiff_t>((nBlockXSize + 7) >> 3) * iLine;
625 :
626 36828 : if (!m_poGDS->m_bPromoteTo8Bits)
627 : {
628 6594 : ExpandPacked8ToByte1(m_pabyBlockBuf + iSrcOffsetByte,
629 6594 : pabyDest + iDstOffset, nBlockXSize / 8);
630 : }
631 : else
632 : {
633 30234 : ExpandPacked8ToByte255(m_pabyBlockBuf + iSrcOffsetByte,
634 30234 : pabyDest + iDstOffset, nBlockXSize / 8);
635 : }
636 36828 : GPtrDiff_t iSrcOffsetBit = (iSrcOffsetByte + nBlockXSize / 8) * 8;
637 36828 : iDstOffset += nBlockXSize & ~0x7;
638 36828 : const GByte bSetVal = m_poGDS->m_bPromoteTo8Bits ? 255 : 1;
639 49349 : for (int iPixel = nBlockXSize & ~0x7; iPixel < nBlockXSize;
640 : ++iPixel, ++iSrcOffsetBit)
641 : {
642 12521 : if (m_pabyBlockBuf[iSrcOffsetBit >> 3] &
643 12521 : (0x80 >> (iSrcOffsetBit & 0x7)))
644 3995 : static_cast<GByte *>(pImage)[iDstOffset++] = bSetVal;
645 : else
646 8526 : static_cast<GByte *>(pImage)[iDstOffset++] = 0;
647 : }
648 405 : }
649 : }
650 : /* -------------------------------------------------------------------- */
651 : /* Handle the case of 16- and 24-bit floating point data as per */
652 : /* TIFF Technical Note 3. */
653 : /* -------------------------------------------------------------------- */
654 482 : else if (eDataType == GDT_Float32)
655 : {
656 46 : const int nWordBytes = m_poGDS->m_nBitsPerSample / 8;
657 46 : const GByte *pabyImage =
658 40 : m_poGDS->m_pabyBlockBuf +
659 46 : ((m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE)
660 : ? 0
661 6 : : (nBand - 1) * nWordBytes);
662 46 : const int iSkipBytes =
663 46 : (m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE)
664 46 : ? nWordBytes
665 6 : : m_poGDS->nBands * nWordBytes;
666 :
667 46 : const auto nBlockPixels =
668 46 : static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize;
669 46 : if (m_poGDS->m_nBitsPerSample == 16)
670 : {
671 161277 : for (GPtrDiff_t i = 0; i < nBlockPixels; ++i)
672 : {
673 322464 : static_cast<GUInt32 *>(pImage)[i] = CPLHalfToFloat(
674 161232 : *reinterpret_cast<const GUInt16 *>(pabyImage));
675 161232 : pabyImage += iSkipBytes;
676 : }
677 : }
678 1 : else if (m_poGDS->m_nBitsPerSample == 24)
679 : {
680 401 : for (GPtrDiff_t i = 0; i < nBlockPixels; ++i)
681 : {
682 : #ifdef CPL_MSB
683 : static_cast<GUInt32 *>(pImage)[i] = CPLTripleToFloat(
684 : (static_cast<GUInt32>(*(pabyImage + 0)) << 16) |
685 : (static_cast<GUInt32>(*(pabyImage + 1)) << 8) |
686 : static_cast<GUInt32>(*(pabyImage + 2)));
687 : #else
688 800 : static_cast<GUInt32 *>(pImage)[i] = CPLTripleToFloat(
689 400 : (static_cast<GUInt32>(*(pabyImage + 2)) << 16) |
690 400 : (static_cast<GUInt32>(*(pabyImage + 1)) << 8) |
691 400 : static_cast<GUInt32>(*pabyImage));
692 : #endif
693 400 : pabyImage += iSkipBytes;
694 : }
695 : }
696 : }
697 :
698 : /* -------------------------------------------------------------------- */
699 : /* Special case for moving 12bit data somewhat more efficiently. */
700 : /* -------------------------------------------------------------------- */
701 436 : else if (m_poGDS->m_nBitsPerSample == 12)
702 : {
703 38 : int iPixelBitSkip = 0;
704 38 : int iBandBitOffset = 0;
705 :
706 38 : if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG)
707 : {
708 29 : iPixelBitSkip = m_poGDS->nBands * m_poGDS->m_nBitsPerSample;
709 29 : iBandBitOffset = (nBand - 1) * m_poGDS->m_nBitsPerSample;
710 : }
711 : else
712 : {
713 9 : iPixelBitSkip = m_poGDS->m_nBitsPerSample;
714 : }
715 :
716 : // Bits per line rounds up to next byte boundary.
717 38 : GPtrDiff_t nBitsPerLine =
718 38 : static_cast<GPtrDiff_t>(nBlockXSize) * iPixelBitSkip;
719 38 : if ((nBitsPerLine & 7) != 0)
720 0 : nBitsPerLine = (nBitsPerLine + 7) & (~7);
721 :
722 38 : int iPixel = 0;
723 1184 : for (int iY = 0; iY < nBlockYSize; ++iY)
724 : {
725 1146 : GPtrDiff_t iBitOffset = iBandBitOffset + iY * nBitsPerLine;
726 :
727 72994 : for (int iX = 0; iX < nBlockXSize; ++iX)
728 : {
729 71848 : const auto iByte = iBitOffset >> 3;
730 :
731 71848 : if ((iBitOffset & 0x7) == 0)
732 : {
733 : // Starting on byte boundary.
734 :
735 36792 : static_cast<GUInt16 *>(pImage)[iPixel++] =
736 36792 : (m_poGDS->m_pabyBlockBuf[iByte] << 4) |
737 36792 : (m_poGDS->m_pabyBlockBuf[iByte + 1] >> 4);
738 : }
739 : else
740 : {
741 : // Starting off byte boundary.
742 :
743 35056 : static_cast<GUInt16 *>(pImage)[iPixel++] =
744 35056 : ((m_poGDS->m_pabyBlockBuf[iByte] & 0xf) << 8) |
745 35056 : (m_poGDS->m_pabyBlockBuf[iByte + 1]);
746 : }
747 71848 : iBitOffset += iPixelBitSkip;
748 : }
749 : }
750 : }
751 :
752 : /* -------------------------------------------------------------------- */
753 : /* Special case for 24bit data which is pre-byteswapped since */
754 : /* the size falls on a byte boundary ... ugh (#2361). */
755 : /* -------------------------------------------------------------------- */
756 398 : else if (m_poGDS->m_nBitsPerSample == 24)
757 : {
758 11 : int iPixelByteSkip = 0;
759 11 : int iBandByteOffset = 0;
760 :
761 11 : if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG)
762 : {
763 8 : iPixelByteSkip = (m_poGDS->nBands * m_poGDS->m_nBitsPerSample) / 8;
764 8 : iBandByteOffset = ((nBand - 1) * m_poGDS->m_nBitsPerSample) / 8;
765 : }
766 : else
767 : {
768 3 : iPixelByteSkip = m_poGDS->m_nBitsPerSample / 8;
769 : }
770 :
771 11 : const GPtrDiff_t nBytesPerLine =
772 11 : static_cast<GPtrDiff_t>(nBlockXSize) * iPixelByteSkip;
773 :
774 11 : GPtrDiff_t iPixel = 0;
775 191 : for (int iY = 0; iY < nBlockYSize; ++iY)
776 : {
777 180 : GByte *pabyImage =
778 180 : m_poGDS->m_pabyBlockBuf + iBandByteOffset + iY * nBytesPerLine;
779 :
780 3380 : for (int iX = 0; iX < nBlockXSize; ++iX)
781 : {
782 : #ifdef CPL_MSB
783 : static_cast<GUInt32 *>(pImage)[iPixel++] =
784 : (static_cast<GUInt32>(*(pabyImage + 2)) << 16) |
785 : (static_cast<GUInt32>(*(pabyImage + 1)) << 8) |
786 : static_cast<GUInt32>(*(pabyImage + 0));
787 : #else
788 3200 : static_cast<GUInt32 *>(pImage)[iPixel++] =
789 3200 : (static_cast<GUInt32>(*(pabyImage + 0)) << 16) |
790 3200 : (static_cast<GUInt32>(*(pabyImage + 1)) << 8) |
791 3200 : static_cast<GUInt32>(*(pabyImage + 2));
792 : #endif
793 3200 : pabyImage += iPixelByteSkip;
794 : }
795 : }
796 : }
797 :
798 : /* -------------------------------------------------------------------- */
799 : /* Handle 1-32 bit integer data. */
800 : /* -------------------------------------------------------------------- */
801 : else
802 : {
803 387 : unsigned iPixelBitSkip = 0;
804 387 : unsigned iBandBitOffset = 0;
805 :
806 387 : if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG)
807 : {
808 381 : iPixelBitSkip = m_poGDS->nBands * m_poGDS->m_nBitsPerSample;
809 381 : iBandBitOffset = (nBand - 1) * m_poGDS->m_nBitsPerSample;
810 : }
811 : else
812 : {
813 6 : iPixelBitSkip = m_poGDS->m_nBitsPerSample;
814 : }
815 :
816 : // Bits per line rounds up to next byte boundary.
817 387 : GUIntBig nBitsPerLine =
818 387 : static_cast<GUIntBig>(nBlockXSize) * iPixelBitSkip;
819 387 : if ((nBitsPerLine & 7) != 0)
820 52 : nBitsPerLine = (nBitsPerLine + 7) & (~7);
821 :
822 387 : const GByte *const m_pabyBlockBuf = m_poGDS->m_pabyBlockBuf;
823 387 : const unsigned nBitsPerSample = m_poGDS->m_nBitsPerSample;
824 387 : GPtrDiff_t iPixel = 0;
825 :
826 387 : if (nBitsPerSample == 1 && eDataType == GDT_Byte)
827 : {
828 1851 : for (unsigned iY = 0; iY < static_cast<unsigned>(nBlockYSize); ++iY)
829 : {
830 1827 : GUIntBig iBitOffset = iBandBitOffset + iY * nBitsPerLine;
831 :
832 171892 : for (unsigned iX = 0; iX < static_cast<unsigned>(nBlockXSize);
833 : ++iX)
834 : {
835 170065 : if (m_pabyBlockBuf[iBitOffset >> 3] &
836 170065 : (0x80 >> (iBitOffset & 7)))
837 102120 : static_cast<GByte *>(pImage)[iPixel] = 1;
838 : else
839 67945 : static_cast<GByte *>(pImage)[iPixel] = 0;
840 170065 : iBitOffset += iPixelBitSkip;
841 170065 : iPixel++;
842 : }
843 24 : }
844 : }
845 : else
846 : {
847 7424 : for (unsigned iY = 0; iY < static_cast<unsigned>(nBlockYSize); ++iY)
848 : {
849 7061 : GUIntBig iBitOffset = iBandBitOffset + iY * nBitsPerLine;
850 :
851 498524 : for (unsigned iX = 0; iX < static_cast<unsigned>(nBlockXSize);
852 : ++iX)
853 : {
854 491463 : unsigned nOutWord = 0;
855 :
856 5520840 : for (unsigned iBit = 0; iBit < nBitsPerSample; ++iBit)
857 : {
858 5029380 : if (m_pabyBlockBuf[iBitOffset >> 3] &
859 5029380 : (0x80 >> (iBitOffset & 7)))
860 918393 : nOutWord |= (1 << (nBitsPerSample - 1 - iBit));
861 5029380 : ++iBitOffset;
862 : }
863 :
864 491463 : iBitOffset = iBitOffset + iPixelBitSkip - nBitsPerSample;
865 :
866 491463 : if (eDataType == GDT_Byte)
867 : {
868 291061 : static_cast<GByte *>(pImage)[iPixel++] =
869 : static_cast<GByte>(nOutWord);
870 : }
871 200402 : else if (eDataType == GDT_UInt16)
872 : {
873 197601 : static_cast<GUInt16 *>(pImage)[iPixel++] =
874 : static_cast<GUInt16>(nOutWord);
875 : }
876 2801 : else if (eDataType == GDT_UInt32)
877 : {
878 2801 : static_cast<GUInt32 *>(pImage)[iPixel++] = nOutWord;
879 : }
880 : else
881 : {
882 0 : CPLAssert(false);
883 : }
884 : }
885 : }
886 : }
887 : }
888 :
889 887 : CacheMaskForBlock(nBlockXOff, nBlockYOff);
890 :
891 887 : return CE_None;
892 : }
|