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