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