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