Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: GDAL Core
4 : * Purpose: Implementation of GDALNoDataMaskBand, a class implementing all
5 : * a default band mask based on nodata values.
6 : * Author: Frank Warmerdam, warmerdam@pobox.com
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2007, Frank Warmerdam
10 : * Copyright (c) 2008-2012, Even Rouault <even dot rouault at spatialys.com>
11 : *
12 : * SPDX-License-Identifier: MIT
13 : ****************************************************************************/
14 :
15 : #include "cpl_port.h"
16 : #include "gdal_priv.h"
17 :
18 : #include <algorithm>
19 : #include <cassert>
20 : #include <cmath>
21 : #include <cstring>
22 : #include <utility>
23 :
24 : #include "cpl_conv.h"
25 : #include "cpl_error.h"
26 : #include "cpl_vsi.h"
27 : #include "gdal.h"
28 : #include "gdal_priv_templates.hpp"
29 : #include "gdal_typetraits.h"
30 : #include "vrtdataset.h"
31 :
32 : //! @cond Doxygen_Suppress
33 : /************************************************************************/
34 : /* GDALNoDataMaskBand() */
35 : /************************************************************************/
36 :
37 1354 : GDALNoDataMaskBand::GDALNoDataMaskBand(GDALRasterBand *poParentIn)
38 1354 : : m_poParent(poParentIn)
39 : {
40 1354 : poDS = nullptr;
41 1354 : nBand = 0;
42 :
43 1354 : nRasterXSize = m_poParent->GetXSize();
44 1354 : nRasterYSize = m_poParent->GetYSize();
45 :
46 1354 : eDataType = GDT_UInt8;
47 1354 : m_poParent->GetBlockSize(&nBlockXSize, &nBlockYSize);
48 :
49 1354 : const auto eParentDT = m_poParent->GetRasterDataType();
50 1354 : if (eParentDT == GDT_Int64)
51 16 : m_nNoDataValueInt64 = m_poParent->GetNoDataValueAsInt64();
52 1338 : else if (eParentDT == GDT_UInt64)
53 15 : m_nNoDataValueUInt64 = m_poParent->GetNoDataValueAsUInt64();
54 : else
55 1323 : m_dfNoDataValue = m_poParent->GetNoDataValue();
56 1354 : }
57 :
58 : /************************************************************************/
59 : /* GDALNoDataMaskBand() */
60 : /************************************************************************/
61 :
62 4 : GDALNoDataMaskBand::GDALNoDataMaskBand(GDALRasterBand *poParentIn,
63 4 : double dfNoDataValue)
64 4 : : m_poParent(poParentIn)
65 : {
66 4 : poDS = nullptr;
67 4 : nBand = 0;
68 :
69 4 : nRasterXSize = m_poParent->GetXSize();
70 4 : nRasterYSize = m_poParent->GetYSize();
71 :
72 4 : eDataType = GDT_UInt8;
73 4 : m_poParent->GetBlockSize(&nBlockXSize, &nBlockYSize);
74 :
75 4 : const auto eParentDT = m_poParent->GetRasterDataType();
76 4 : if (eParentDT == GDT_Int64)
77 0 : m_nNoDataValueInt64 = static_cast<int64_t>(dfNoDataValue);
78 4 : else if (eParentDT == GDT_UInt64)
79 0 : m_nNoDataValueUInt64 = static_cast<uint64_t>(dfNoDataValue);
80 : else
81 4 : m_dfNoDataValue = dfNoDataValue;
82 4 : }
83 :
84 : /************************************************************************/
85 : /* ~GDALNoDataMaskBand() */
86 : /************************************************************************/
87 :
88 : GDALNoDataMaskBand::~GDALNoDataMaskBand() = default;
89 :
90 : /************************************************************************/
91 : /* GetWorkDataType() */
92 : /************************************************************************/
93 :
94 18846 : static GDALDataType GetWorkDataType(GDALDataType eDataType)
95 : {
96 18846 : GDALDataType eWrkDT = GDT_Unknown;
97 18846 : switch (eDataType)
98 : {
99 1653 : case GDT_UInt8:
100 1653 : eWrkDT = GDT_UInt8;
101 1653 : break;
102 :
103 1864 : case GDT_Int16:
104 1864 : eWrkDT = GDT_Int16;
105 1864 : break;
106 :
107 67 : case GDT_UInt16:
108 67 : eWrkDT = GDT_UInt16;
109 67 : break;
110 :
111 33 : case GDT_UInt32:
112 33 : eWrkDT = GDT_UInt32;
113 33 : break;
114 :
115 134 : case GDT_Int8:
116 : case GDT_Int32:
117 : case GDT_CInt16:
118 : case GDT_CInt32:
119 134 : eWrkDT = GDT_Int32;
120 134 : break;
121 :
122 14874 : case GDT_Float16:
123 : case GDT_CFloat16:
124 : case GDT_Float32:
125 : case GDT_CFloat32:
126 14874 : eWrkDT = GDT_Float32;
127 14874 : break;
128 :
129 169 : case GDT_Float64:
130 : case GDT_CFloat64:
131 169 : eWrkDT = GDT_Float64;
132 169 : break;
133 :
134 52 : case GDT_Int64:
135 : case GDT_UInt64:
136 52 : eWrkDT = eDataType;
137 52 : break;
138 :
139 0 : case GDT_Unknown:
140 : case GDT_TypeCount:
141 0 : CPLAssert(false);
142 : eWrkDT = GDT_Float64;
143 : break;
144 : }
145 18846 : return eWrkDT;
146 : }
147 :
148 : /************************************************************************/
149 : /* IsNoDataInRange() */
150 : /************************************************************************/
151 :
152 1362 : bool GDALNoDataMaskBand::IsNoDataInRange(double dfNoDataValue,
153 : GDALDataType eDataTypeIn)
154 : {
155 1362 : GDALDataType eWrkDT = GetWorkDataType(eDataTypeIn);
156 1362 : switch (eWrkDT)
157 : {
158 584 : case GDT_UInt8:
159 : {
160 584 : return GDALIsValueInRange<GByte>(dfNoDataValue);
161 : }
162 :
163 0 : case GDT_Int8:
164 : {
165 0 : return GDALIsValueInRange<signed char>(dfNoDataValue);
166 : }
167 :
168 152 : case GDT_Int16:
169 : {
170 152 : return GDALIsValueInRange<GInt16>(dfNoDataValue);
171 : }
172 :
173 55 : case GDT_UInt16:
174 : {
175 55 : return GDALIsValueInRange<GUInt16>(dfNoDataValue);
176 : }
177 :
178 22 : case GDT_UInt32:
179 : {
180 22 : return GDALIsValueInRange<GUInt32>(dfNoDataValue);
181 : }
182 47 : case GDT_Int32:
183 : {
184 47 : return GDALIsValueInRange<GInt32>(dfNoDataValue);
185 : }
186 :
187 0 : case GDT_UInt64:
188 : {
189 0 : return GDALIsValueInRange<uint64_t>(dfNoDataValue);
190 : }
191 :
192 0 : case GDT_Int64:
193 : {
194 0 : return GDALIsValueInRange<int64_t>(dfNoDataValue);
195 : }
196 :
197 0 : case GDT_Float16:
198 : {
199 0 : return std::isnan(dfNoDataValue) || std::isinf(dfNoDataValue) ||
200 0 : GDALIsValueInRange<GFloat16>(dfNoDataValue);
201 : }
202 :
203 401 : case GDT_Float32:
204 : {
205 745 : return std::isnan(dfNoDataValue) || std::isinf(dfNoDataValue) ||
206 745 : GDALIsValueInRange<float>(dfNoDataValue);
207 : }
208 :
209 101 : case GDT_Float64:
210 : {
211 101 : return true;
212 : }
213 :
214 0 : case GDT_CFloat16:
215 : case GDT_CFloat32:
216 : case GDT_CFloat64:
217 : case GDT_CInt16:
218 : case GDT_CInt32:
219 : case GDT_Unknown:
220 : case GDT_TypeCount:
221 0 : break;
222 : }
223 :
224 0 : CPLAssert(false);
225 : return false;
226 : }
227 :
228 : /************************************************************************/
229 : /* IReadBlock() */
230 : /************************************************************************/
231 :
232 34 : CPLErr GDALNoDataMaskBand::IReadBlock(int nXBlockOff, int nYBlockOff,
233 : void *pImage)
234 :
235 : {
236 34 : const int nXOff = nXBlockOff * nBlockXSize;
237 34 : const int nXSizeRequest = std::min(nBlockXSize, nRasterXSize - nXOff);
238 34 : const int nYOff = nYBlockOff * nBlockYSize;
239 34 : const int nYSizeRequest = std::min(nBlockYSize, nRasterYSize - nYOff);
240 :
241 34 : if (nBlockXSize != nXSizeRequest || nBlockYSize != nYSizeRequest)
242 : {
243 0 : memset(pImage, 0, static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize);
244 : }
245 :
246 : GDALRasterIOExtraArg sExtraArg;
247 34 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
248 68 : return IRasterIO(GF_Read, nXOff, nYOff, nXSizeRequest, nYSizeRequest,
249 : pImage, nXSizeRequest, nYSizeRequest, GDT_UInt8, 1,
250 68 : nBlockXSize, &sExtraArg);
251 : }
252 :
253 : /************************************************************************/
254 : /* SetZeroOr255() */
255 : /************************************************************************/
256 :
257 : #if (defined(__GNUC__) && !defined(__clang__))
258 : __attribute__((optimize("tree-vectorize")))
259 : #endif
260 966 : static void SetZeroOr255(GByte *pabyDestAndSrc, size_t nBufSize, GByte byNoData)
261 : {
262 4673420 : for (size_t i = 0; i < nBufSize; ++i)
263 : {
264 4672460 : pabyDestAndSrc[i] = (pabyDestAndSrc[i] == byNoData) ? 0 : 255;
265 : }
266 966 : }
267 :
268 : template <class T>
269 : #if (defined(__GNUC__) && !defined(__clang__))
270 : __attribute__((optimize("tree-vectorize")))
271 : #endif
272 3447 : static void SetZeroOr255(GByte *pabyDest, const T *panSrc, size_t nBufSize,
273 : T nNoData)
274 : {
275 999318 : for (size_t i = 0; i < nBufSize; ++i)
276 : {
277 995871 : pabyDest[i] = (panSrc[i] == nNoData) ? 0 : 255;
278 : }
279 3447 : }
280 :
281 : template <class T>
282 1848 : static void SetZeroOr255(GByte *pabyDest, const T *panSrc, int nBufXSize,
283 : int nBufYSize, GSpacing nPixelSpace,
284 : GSpacing nLineSpace, T nNoData)
285 : {
286 1848 : if (nPixelSpace == 1)
287 : {
288 5287 : for (int iY = 0; iY < nBufYSize; iY++)
289 : {
290 3447 : SetZeroOr255(pabyDest, panSrc, nBufXSize, nNoData);
291 3447 : pabyDest += nLineSpace;
292 3447 : panSrc += nBufXSize;
293 : }
294 : }
295 : else
296 : {
297 8 : size_t i = 0;
298 40 : for (int iY = 0; iY < nBufYSize; iY++)
299 : {
300 32 : GByte *pabyLineDest = pabyDest + iY * nLineSpace;
301 224 : for (int iX = 0; iX < nBufXSize; iX++)
302 : {
303 192 : *pabyLineDest = (panSrc[i] == nNoData) ? 0 : 255;
304 192 : ++i;
305 192 : pabyLineDest += nPixelSpace;
306 : }
307 : }
308 : }
309 1848 : }
310 :
311 : /************************************************************************/
312 : /* ParentBandIsNoData() */
313 : /************************************************************************/
314 :
315 : /** Callback function for a VRT raster band. Transforms input band into
316 : * a NoData mask, which can then be resampled.
317 : */
318 : template <GDALDataType GDALTransferDataType>
319 6 : static CPLErr ParentBandIsNoData(void *poData, int nXOff, int nYOff, int nXSize,
320 : int nYSize, void *pData)
321 : {
322 : using TransferType =
323 : typename gdal::GDALDataTypeTraits<GDALTransferDataType>::type;
324 :
325 6 : GDALRasterBand *poSrcBand = static_cast<GDALRasterBand *>(poData);
326 :
327 6 : std::unique_ptr<TransferType, decltype(&CPLFree)> pabySrc{
328 : static_cast<TransferType *>(
329 6 : VSI_MALLOC3_VERBOSE(sizeof(TransferType), nXSize, nYSize)),
330 6 : CPLFree};
331 6 : if (pabySrc == nullptr)
332 : {
333 0 : return CE_Failure;
334 : }
335 :
336 6 : const auto eErr = poSrcBand->RasterIO(GF_Read, nXOff, nYOff, nXSize, nYSize,
337 : pabySrc.get(), nXSize, nYSize,
338 : GDALTransferDataType, 0, 0, nullptr);
339 6 : if (eErr != CE_None)
340 : {
341 0 : return eErr;
342 : }
343 :
344 6 : const size_t nPixelCount = static_cast<size_t>(nXSize) * nYSize;
345 6 : GByte *pabyDst = static_cast<GByte *>(pData);
346 :
347 6 : const auto maybeNoData = poSrcBand->GetNoDataValue<TransferType>();
348 6 : if (!maybeNoData.has_value())
349 : {
350 0 : std::fill(pabyDst, pabyDst + nPixelCount, 255);
351 0 : return CE_None;
352 : }
353 6 : const TransferType noData = maybeNoData.value();
354 :
355 30 : for (size_t i = 0; i < nPixelCount; i++)
356 : {
357 : if constexpr (std::is_floating_point_v<TransferType>)
358 : {
359 10 : pabyDst[i] = (std::isnan(noData) && std::isnan(pabySrc.get()[i])) ||
360 2 : ARE_REAL_EQUAL(pabySrc.get()[i], noData)
361 : ? 0
362 : : 255;
363 : }
364 : else
365 : {
366 16 : pabyDst[i] = pabySrc.get()[i] == noData ? 0 : 255;
367 : }
368 : }
369 :
370 6 : return CE_None;
371 : }
372 :
373 : /************************************************************************/
374 : /* IRasterIO() */
375 : /************************************************************************/
376 :
377 17484 : CPLErr GDALNoDataMaskBand::IRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
378 : int nXSize, int nYSize, void *pData,
379 : int nBufXSize, int nBufYSize,
380 : GDALDataType eBufType,
381 : GSpacing nPixelSpace, GSpacing nLineSpace,
382 : GDALRasterIOExtraArg *psExtraArg)
383 : {
384 17484 : if (eRWFlag != GF_Read)
385 : {
386 0 : return CE_Failure;
387 : }
388 :
389 17484 : const auto eParentDT = m_poParent->GetRasterDataType();
390 17484 : const GDALDataType eWrkDT = GetWorkDataType(eParentDT);
391 :
392 17484 : if (psExtraArg->eResampleAlg == GRIORA_Mode)
393 : {
394 : // For mode resampling, we have to read the parent band at full resolution
395 : // and classify each pixel as valid / NoData.
396 : auto poVRT = VRTDataset::CreateVRTDataset("", nXSize, nYSize, 0,
397 12 : GDT_UInt8, nullptr);
398 6 : poVRT->AddBand(GDT_Byte, nullptr);
399 : VRTSourcedRasterBand *poVRTBand =
400 6 : cpl::down_cast<VRTSourcedRasterBand *>(poVRT->GetRasterBand(1));
401 :
402 6 : switch (eWrkDT)
403 : {
404 1 : case GDT_UInt8:
405 1 : poVRTBand->AddFuncSource(ParentBandIsNoData<GDT_UInt8>,
406 1 : m_poParent);
407 1 : break;
408 1 : case GDT_Int16:
409 1 : poVRTBand->AddFuncSource(ParentBandIsNoData<GDT_Int16>,
410 1 : m_poParent);
411 1 : break;
412 0 : case GDT_UInt16:
413 0 : poVRTBand->AddFuncSource(ParentBandIsNoData<GDT_UInt16>,
414 0 : m_poParent);
415 0 : break;
416 0 : case GDT_Int32:
417 0 : poVRTBand->AddFuncSource(ParentBandIsNoData<GDT_Int32>,
418 0 : m_poParent);
419 0 : break;
420 0 : case GDT_UInt32:
421 0 : poVRTBand->AddFuncSource(ParentBandIsNoData<GDT_UInt32>,
422 0 : m_poParent);
423 0 : break;
424 1 : case GDT_Float32:
425 1 : poVRTBand->AddFuncSource(ParentBandIsNoData<GDT_Float32>,
426 1 : m_poParent);
427 1 : break;
428 1 : case GDT_Float64:
429 1 : poVRTBand->AddFuncSource(ParentBandIsNoData<GDT_Float64>,
430 1 : m_poParent);
431 1 : break;
432 1 : case GDT_Int64:
433 1 : poVRTBand->AddFuncSource(ParentBandIsNoData<GDT_Int64>,
434 1 : m_poParent);
435 1 : break;
436 1 : case GDT_UInt64:
437 1 : poVRTBand->AddFuncSource(ParentBandIsNoData<GDT_UInt64>,
438 1 : m_poParent);
439 1 : break;
440 0 : default:
441 0 : CPLAssert(false);
442 : }
443 :
444 6 : return poVRTBand->RasterIO(GF_Read, nXOff, nYOff, nXSize, nYSize, pData,
445 : nBufXSize, nBufYSize, eBufType, nPixelSpace,
446 6 : nLineSpace, psExtraArg);
447 : }
448 :
449 : // Optimization in common use case (#4488).
450 : // This avoids triggering the block cache on this band, which helps
451 : // reducing the global block cache consumption.
452 17478 : if (eBufType == GDT_UInt8 && eWrkDT == GDT_UInt8 && nPixelSpace == 1 &&
453 963 : nLineSpace >= nBufXSize)
454 : {
455 963 : const CPLErr eErr = m_poParent->RasterIO(
456 : GF_Read, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize, nBufYSize,
457 : eBufType, nPixelSpace, nLineSpace, psExtraArg);
458 963 : if (eErr != CE_None)
459 0 : return eErr;
460 :
461 963 : GByte *pabyData = static_cast<GByte *>(pData);
462 963 : const GByte byNoData = static_cast<GByte>(m_dfNoDataValue);
463 :
464 963 : if (nLineSpace == nBufXSize)
465 : {
466 962 : const size_t nBufSize = static_cast<size_t>(nBufXSize) * nBufYSize;
467 962 : SetZeroOr255(pabyData, nBufSize, byNoData);
468 : }
469 : else
470 : {
471 1 : assert(nLineSpace > nBufXSize);
472 5 : for (int iY = 0; iY < nBufYSize; iY++)
473 : {
474 4 : SetZeroOr255(pabyData, nBufXSize, byNoData);
475 4 : pabyData += nLineSpace;
476 : }
477 : }
478 963 : return CE_None;
479 : }
480 :
481 : const auto AllocTempBufferOrFallback =
482 16515 : [this, eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize,
483 : nBufYSize, eBufType, nPixelSpace, nLineSpace,
484 33086 : psExtraArg](int nWrkDTSize) -> std::pair<CPLErr, void *>
485 : {
486 16515 : auto poParentDS = m_poParent->GetDataset();
487 : // Check if we must simulate a memory allocation failure
488 : // Before checking the env variable, which is slightly expensive,
489 : // check first for a special dataset name, which is a cheap test.
490 : const char *pszOptVal =
491 16515 : poParentDS && strcmp(poParentDS->GetDescription(), "__debug__") == 0
492 33030 : ? CPLGetConfigOption(
493 : "GDAL_SIMUL_MEM_ALLOC_FAILURE_NODATA_MASK_BAND", "NO")
494 16515 : : "NO";
495 : const bool bSimulMemAllocFailure =
496 33026 : EQUAL(pszOptVal, "ALWAYS") ||
497 16511 : (CPLTestBool(pszOptVal) &&
498 14 : GDALMajorObject::GetMetadataItem(__func__, "__INTERNAL__") ==
499 16515 : nullptr);
500 16515 : void *pTemp = nullptr;
501 16515 : if (!bSimulMemAllocFailure)
502 : {
503 16503 : CPLErrorStateBackuper oErrorStateBackuper(CPLQuietErrorHandler);
504 16503 : pTemp = VSI_MALLOC3_VERBOSE(nWrkDTSize, nBufXSize, nBufYSize);
505 : }
506 16515 : if (!pTemp)
507 : {
508 : const bool bAllocHasAlreadyFailed =
509 12 : GDALMajorObject::GetMetadataItem(__func__, "__INTERNAL__") !=
510 12 : nullptr;
511 12 : CPLError(bAllocHasAlreadyFailed ? CE_Failure : CE_Warning,
512 : CPLE_OutOfMemory,
513 : "GDALNoDataMaskBand::IRasterIO(): cannot allocate %d x %d "
514 : "x %d bytes%s",
515 : nBufXSize, nBufYSize, nWrkDTSize,
516 : bAllocHasAlreadyFailed
517 : ? ""
518 : : ". Falling back to block-based approach");
519 12 : if (bAllocHasAlreadyFailed)
520 2 : return std::pair(CE_Failure, nullptr);
521 : // Sets a metadata item to prevent potential infinite recursion
522 10 : GDALMajorObject::SetMetadataItem(__func__, "IN", "__INTERNAL__");
523 10 : const CPLErr eErr = GDALRasterBand::IRasterIO(
524 : eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize,
525 10 : nBufYSize, eBufType, nPixelSpace, nLineSpace, psExtraArg);
526 10 : GDALMajorObject::SetMetadataItem(__func__, nullptr, "__INTERNAL__");
527 10 : return std::pair(eErr, nullptr);
528 : }
529 16503 : return std::pair(CE_None, pTemp);
530 16515 : };
531 :
532 16515 : if (eBufType == GDT_UInt8)
533 : {
534 16386 : const int nWrkDTSize = GDALGetDataTypeSizeBytes(eWrkDT);
535 16386 : auto [eErr, pTemp] = AllocTempBufferOrFallback(nWrkDTSize);
536 16386 : if (!pTemp)
537 12 : return eErr;
538 :
539 32748 : eErr = m_poParent->RasterIO(
540 : GF_Read, nXOff, nYOff, nXSize, nYSize, pTemp, nBufXSize, nBufYSize,
541 16374 : eWrkDT, nWrkDTSize, static_cast<GSpacing>(nBufXSize) * nWrkDTSize,
542 : psExtraArg);
543 16374 : if (eErr != CE_None)
544 : {
545 0 : VSIFree(pTemp);
546 0 : return eErr;
547 : }
548 :
549 16374 : const bool bIsNoDataNan = std::isnan(m_dfNoDataValue) != 0;
550 16374 : GByte *pabyDest = static_cast<GByte *>(pData);
551 :
552 : /* --------------------------------------------------------------------
553 : */
554 : /* Process different cases. */
555 : /* --------------------------------------------------------------------
556 : */
557 16374 : switch (eWrkDT)
558 : {
559 1 : case GDT_UInt8:
560 : {
561 1 : const auto nNoData = static_cast<GByte>(m_dfNoDataValue);
562 1 : const auto *panSrc = static_cast<const GByte *>(pTemp);
563 1 : SetZeroOr255(pabyDest, panSrc, nBufXSize, nBufYSize,
564 : nPixelSpace, nLineSpace, nNoData);
565 : }
566 1 : break;
567 :
568 1708 : case GDT_Int16:
569 : {
570 1708 : const auto nNoData = static_cast<int16_t>(m_dfNoDataValue);
571 1708 : const auto *panSrc = static_cast<const int16_t *>(pTemp);
572 1708 : SetZeroOr255(pabyDest, panSrc, nBufXSize, nBufYSize,
573 : nPixelSpace, nLineSpace, nNoData);
574 : }
575 1708 : break;
576 :
577 10 : case GDT_UInt16:
578 : {
579 10 : const auto nNoData = static_cast<uint16_t>(m_dfNoDataValue);
580 10 : const auto *panSrc = static_cast<const uint16_t *>(pTemp);
581 10 : SetZeroOr255(pabyDest, panSrc, nBufXSize, nBufYSize,
582 : nPixelSpace, nLineSpace, nNoData);
583 : }
584 10 : break;
585 :
586 9 : case GDT_UInt32:
587 : {
588 9 : const auto nNoData = static_cast<GUInt32>(m_dfNoDataValue);
589 9 : const auto *panSrc = static_cast<const GUInt32 *>(pTemp);
590 9 : SetZeroOr255(pabyDest, panSrc, nBufXSize, nBufYSize,
591 : nPixelSpace, nLineSpace, nNoData);
592 : }
593 9 : break;
594 :
595 84 : case GDT_Int32:
596 : {
597 84 : const auto nNoData = static_cast<GInt32>(m_dfNoDataValue);
598 84 : const auto *panSrc = static_cast<const GInt32 *>(pTemp);
599 84 : SetZeroOr255(pabyDest, panSrc, nBufXSize, nBufYSize,
600 : nPixelSpace, nLineSpace, nNoData);
601 : }
602 84 : break;
603 :
604 14465 : case GDT_Float32:
605 : {
606 14465 : const float fNoData = static_cast<float>(m_dfNoDataValue);
607 14465 : const float *pafSrc = static_cast<const float *>(pTemp);
608 :
609 14465 : size_t i = 0;
610 32795 : for (int iY = 0; iY < nBufYSize; iY++)
611 : {
612 18330 : GByte *pabyLineDest = pabyDest + iY * nLineSpace;
613 15514100 : for (int iX = 0; iX < nBufXSize; iX++)
614 : {
615 15495700 : const float fVal = pafSrc[i];
616 15495700 : if (bIsNoDataNan && std::isnan(fVal))
617 69 : *pabyLineDest = 0;
618 15495700 : else if (ARE_REAL_EQUAL(fVal, fNoData))
619 1009610 : *pabyLineDest = 0;
620 : else
621 14486100 : *pabyLineDest = 255;
622 15495700 : ++i;
623 15495700 : pabyLineDest += nPixelSpace;
624 : }
625 : }
626 : }
627 14465 : break;
628 :
629 61 : case GDT_Float64:
630 : {
631 61 : const double *padfSrc = static_cast<const double *>(pTemp);
632 :
633 61 : size_t i = 0;
634 518 : for (int iY = 0; iY < nBufYSize; iY++)
635 : {
636 457 : GByte *pabyLineDest = pabyDest + iY * nLineSpace;
637 6379 : for (int iX = 0; iX < nBufXSize; iX++)
638 : {
639 5922 : const double dfVal = padfSrc[i];
640 5922 : if (bIsNoDataNan && std::isnan(dfVal))
641 75 : *pabyLineDest = 0;
642 5847 : else if (ARE_REAL_EQUAL(dfVal, m_dfNoDataValue))
643 241 : *pabyLineDest = 0;
644 : else
645 5606 : *pabyLineDest = 255;
646 5922 : ++i;
647 5922 : pabyLineDest += nPixelSpace;
648 : }
649 : }
650 : }
651 61 : break;
652 :
653 18 : case GDT_Int64:
654 : {
655 18 : const auto *panSrc = static_cast<const int64_t *>(pTemp);
656 18 : SetZeroOr255(pabyDest, panSrc, nBufXSize, nBufYSize,
657 : nPixelSpace, nLineSpace, m_nNoDataValueInt64);
658 : }
659 18 : break;
660 :
661 18 : case GDT_UInt64:
662 : {
663 18 : const auto *panSrc = static_cast<const uint64_t *>(pTemp);
664 18 : SetZeroOr255(pabyDest, panSrc, nBufXSize, nBufYSize,
665 : nPixelSpace, nLineSpace, m_nNoDataValueUInt64);
666 : }
667 18 : break;
668 :
669 0 : default:
670 0 : CPLAssert(false);
671 : break;
672 : }
673 :
674 16374 : VSIFree(pTemp);
675 16374 : return CE_None;
676 : }
677 :
678 : // Output buffer is non-Byte. Ask for Byte and expand to user requested
679 : // type
680 129 : auto [eErr, pTemp] = AllocTempBufferOrFallback(sizeof(GByte));
681 129 : if (!pTemp)
682 0 : return eErr;
683 :
684 129 : eErr = IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pTemp, nBufXSize,
685 : nBufYSize, GDT_UInt8, 1, nBufXSize, psExtraArg);
686 129 : if (eErr != CE_None)
687 : {
688 0 : VSIFree(pTemp);
689 0 : return eErr;
690 : }
691 :
692 290 : for (int iY = 0; iY < nBufYSize; iY++)
693 : {
694 161 : GDALCopyWords64(
695 161 : static_cast<GByte *>(pTemp) + static_cast<size_t>(iY) * nBufXSize,
696 161 : GDT_UInt8, 1, static_cast<GByte *>(pData) + iY * nLineSpace,
697 : eBufType, static_cast<int>(nPixelSpace), nBufXSize);
698 : }
699 129 : VSIFree(pTemp);
700 129 : return CE_None;
701 : }
702 :
703 : /************************************************************************/
704 : /* EmitErrorMessageIfWriteNotSupported() */
705 : /************************************************************************/
706 :
707 2 : bool GDALNoDataMaskBand::EmitErrorMessageIfWriteNotSupported(
708 : const char *pszCaller) const
709 : {
710 2 : ReportError(CE_Failure, CPLE_NoWriteAccess,
711 : "%s: attempt to write to a nodata implicit mask band.",
712 : pszCaller);
713 :
714 2 : return true;
715 : }
716 :
717 : //! @endcond
|