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 : }
|