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 : * Permission is hereby granted, free of charge, to any person obtaining a
13 : * copy of this software and associated documentation files (the "Software"),
14 : * to deal in the Software without restriction, including without limitation
15 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
16 : * and/or sell copies of the Software, and to permit persons to whom the
17 : * Software is furnished to do so, subject to the following conditions:
18 : *
19 : * The above copyright notice and this permission notice shall be included
20 : * in all copies or substantial portions of the Software.
21 : *
22 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
23 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
25 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
26 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28 : * DEALINGS IN THE SOFTWARE.
29 : ****************************************************************************/
30 :
31 : #include "cpl_port.h"
32 : #include "gdal_priv.h"
33 :
34 : #include <algorithm>
35 : #include <cstring>
36 :
37 : #include "cpl_conv.h"
38 : #include "cpl_error.h"
39 : #include "cpl_vsi.h"
40 : #include "gdal.h"
41 : #include "gdal_priv_templates.hpp"
42 :
43 : //! @cond Doxygen_Suppress
44 : /************************************************************************/
45 : /* GDALNoDataMaskBand() */
46 : /************************************************************************/
47 :
48 734 : GDALNoDataMaskBand::GDALNoDataMaskBand(GDALRasterBand *poParentIn)
49 734 : : m_poParent(poParentIn)
50 : {
51 734 : poDS = nullptr;
52 734 : nBand = 0;
53 :
54 734 : nRasterXSize = m_poParent->GetXSize();
55 734 : nRasterYSize = m_poParent->GetYSize();
56 :
57 734 : eDataType = GDT_Byte;
58 734 : m_poParent->GetBlockSize(&nBlockXSize, &nBlockYSize);
59 :
60 734 : const auto eParentDT = m_poParent->GetRasterDataType();
61 734 : if (eParentDT == GDT_Int64)
62 8 : m_nNoDataValueInt64 = m_poParent->GetNoDataValueAsInt64();
63 726 : else if (eParentDT == GDT_UInt64)
64 7 : m_nNoDataValueUInt64 = m_poParent->GetNoDataValueAsUInt64();
65 : else
66 719 : m_dfNoDataValue = m_poParent->GetNoDataValue();
67 734 : }
68 :
69 : /************************************************************************/
70 : /* GDALNoDataMaskBand() */
71 : /************************************************************************/
72 :
73 1 : GDALNoDataMaskBand::GDALNoDataMaskBand(GDALRasterBand *poParentIn,
74 1 : double dfNoDataValue)
75 1 : : m_poParent(poParentIn)
76 : {
77 1 : poDS = nullptr;
78 1 : nBand = 0;
79 :
80 1 : nRasterXSize = m_poParent->GetXSize();
81 1 : nRasterYSize = m_poParent->GetYSize();
82 :
83 1 : eDataType = GDT_Byte;
84 1 : m_poParent->GetBlockSize(&nBlockXSize, &nBlockYSize);
85 :
86 1 : const auto eParentDT = m_poParent->GetRasterDataType();
87 1 : if (eParentDT == GDT_Int64)
88 0 : m_nNoDataValueInt64 = static_cast<int64_t>(dfNoDataValue);
89 1 : else if (eParentDT == GDT_UInt64)
90 0 : m_nNoDataValueUInt64 = static_cast<uint64_t>(dfNoDataValue);
91 : else
92 1 : m_dfNoDataValue = dfNoDataValue;
93 1 : }
94 :
95 : /************************************************************************/
96 : /* ~GDALNoDataMaskBand() */
97 : /************************************************************************/
98 :
99 : GDALNoDataMaskBand::~GDALNoDataMaskBand() = default;
100 :
101 : /************************************************************************/
102 : /* GetWorkDataType() */
103 : /************************************************************************/
104 :
105 10212 : static GDALDataType GetWorkDataType(GDALDataType eDataType)
106 : {
107 10212 : GDALDataType eWrkDT = GDT_Unknown;
108 10212 : switch (eDataType)
109 : {
110 752 : case GDT_Byte:
111 752 : eWrkDT = GDT_Byte;
112 752 : break;
113 :
114 77 : case GDT_UInt16:
115 : case GDT_UInt32:
116 77 : eWrkDT = GDT_UInt32;
117 77 : break;
118 :
119 1826 : case GDT_Int8:
120 : case GDT_Int16:
121 : case GDT_Int32:
122 : case GDT_CInt16:
123 : case GDT_CInt32:
124 1826 : eWrkDT = GDT_Int32;
125 1826 : break;
126 :
127 7480 : case GDT_Float32:
128 : case GDT_CFloat32:
129 7480 : eWrkDT = GDT_Float32;
130 7480 : break;
131 :
132 69 : case GDT_Float64:
133 : case GDT_CFloat64:
134 69 : eWrkDT = GDT_Float64;
135 69 : break;
136 :
137 8 : case GDT_Int64:
138 : case GDT_UInt64:
139 8 : eWrkDT = eDataType;
140 8 : break;
141 :
142 0 : default:
143 0 : CPLAssert(false);
144 : eWrkDT = GDT_Float64;
145 : break;
146 : }
147 10212 : return eWrkDT;
148 : }
149 :
150 : /************************************************************************/
151 : /* IsNoDataInRange() */
152 : /************************************************************************/
153 :
154 749 : bool GDALNoDataMaskBand::IsNoDataInRange(double dfNoDataValue,
155 : GDALDataType eDataTypeIn)
156 : {
157 749 : GDALDataType eWrkDT = GetWorkDataType(eDataTypeIn);
158 749 : switch (eWrkDT)
159 : {
160 316 : case GDT_Byte:
161 : {
162 316 : return GDALIsValueInRange<GByte>(dfNoDataValue);
163 : }
164 :
165 58 : case GDT_UInt32:
166 : {
167 58 : return GDALIsValueInRange<GUInt32>(dfNoDataValue);
168 : }
169 :
170 80 : case GDT_Int32:
171 : {
172 80 : return GDALIsValueInRange<GInt32>(dfNoDataValue);
173 : }
174 :
175 0 : case GDT_UInt64:
176 : {
177 0 : return GDALIsValueInRange<uint64_t>(dfNoDataValue);
178 : }
179 :
180 0 : case GDT_Int64:
181 : {
182 0 : return GDALIsValueInRange<int64_t>(dfNoDataValue);
183 : }
184 :
185 250 : case GDT_Float32:
186 : {
187 490 : return CPLIsNan(dfNoDataValue) || CPLIsInf(dfNoDataValue) ||
188 490 : GDALIsValueInRange<float>(dfNoDataValue);
189 : }
190 :
191 45 : case GDT_Float64:
192 : {
193 45 : return true;
194 : }
195 :
196 0 : default:
197 0 : CPLAssert(false);
198 : return false;
199 : }
200 : }
201 :
202 : /************************************************************************/
203 : /* IReadBlock() */
204 : /************************************************************************/
205 :
206 18 : CPLErr GDALNoDataMaskBand::IReadBlock(int nXBlockOff, int nYBlockOff,
207 : void *pImage)
208 :
209 : {
210 18 : const int nXOff = nXBlockOff * nBlockXSize;
211 18 : const int nXSizeRequest = std::min(nBlockXSize, nRasterXSize - nXOff);
212 18 : const int nYOff = nYBlockOff * nBlockYSize;
213 18 : const int nYSizeRequest = std::min(nBlockYSize, nRasterYSize - nYOff);
214 :
215 18 : if (nBlockXSize != nXSizeRequest || nBlockYSize != nYSizeRequest)
216 : {
217 0 : memset(pImage, 0, static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize);
218 : }
219 :
220 : GDALRasterIOExtraArg sExtraArg;
221 18 : INIT_RASTERIO_EXTRA_ARG(sExtraArg);
222 18 : return IRasterIO(GF_Read, nXOff, nYOff, nXSizeRequest, nYSizeRequest,
223 : pImage, nXSizeRequest, nYSizeRequest, GDT_Byte, 1,
224 36 : nBlockXSize, &sExtraArg);
225 : }
226 :
227 : /************************************************************************/
228 : /* IRasterIO() */
229 : /************************************************************************/
230 :
231 9463 : CPLErr GDALNoDataMaskBand::IRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
232 : int nXSize, int nYSize, void *pData,
233 : int nBufXSize, int nBufYSize,
234 : GDALDataType eBufType,
235 : GSpacing nPixelSpace, GSpacing nLineSpace,
236 : GDALRasterIOExtraArg *psExtraArg)
237 : {
238 9463 : if (eRWFlag != GF_Read)
239 : {
240 0 : return CE_Failure;
241 : }
242 9463 : const auto eParentDT = m_poParent->GetRasterDataType();
243 9463 : const GDALDataType eWrkDT = GetWorkDataType(eParentDT);
244 :
245 : // Optimization in common use case (#4488).
246 : // This avoids triggering the block cache on this band, which helps
247 : // reducing the global block cache consumption.
248 9463 : if (eBufType == GDT_Byte && eWrkDT == GDT_Byte)
249 : {
250 375 : const CPLErr eErr = m_poParent->RasterIO(
251 : GF_Read, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize, nBufYSize,
252 : eBufType, nPixelSpace, nLineSpace, psExtraArg);
253 375 : if (eErr != CE_None)
254 0 : return eErr;
255 :
256 375 : GByte *pabyData = static_cast<GByte *>(pData);
257 375 : const GByte byNoData = static_cast<GByte>(m_dfNoDataValue);
258 :
259 375 : if (nPixelSpace == 1 && nLineSpace == nBufXSize)
260 : {
261 375 : const size_t nBufSize = static_cast<size_t>(nBufXSize) * nBufYSize;
262 4064130 : for (size_t i = 0; i < nBufSize; ++i)
263 : {
264 4063760 : pabyData[i] = pabyData[i] == byNoData ? 0 : 255;
265 375 : }
266 : }
267 : else
268 : {
269 0 : for (int iY = 0; iY < nBufYSize; iY++)
270 : {
271 0 : GByte *pabyLine = pabyData + iY * nLineSpace;
272 0 : for (int iX = 0; iX < nBufXSize; iX++)
273 : {
274 0 : *pabyLine = *pabyLine == byNoData ? 0 : 255;
275 0 : pabyLine += nPixelSpace;
276 : }
277 : }
278 : }
279 375 : return CE_None;
280 : }
281 :
282 9088 : if (eBufType == GDT_Byte)
283 : {
284 9009 : const int nWrkDTSize = GDALGetDataTypeSizeBytes(eWrkDT);
285 9009 : void *pTemp = VSI_MALLOC3_VERBOSE(nWrkDTSize, nBufXSize, nBufYSize);
286 9009 : if (pTemp == nullptr)
287 : {
288 0 : return GDALRasterBand::IRasterIO(
289 : eRWFlag, nXOff, nYOff, nXSize, nYSize, pTemp, nBufXSize,
290 : nBufYSize, eWrkDT, nWrkDTSize,
291 0 : static_cast<GSpacing>(nBufXSize) * nWrkDTSize, psExtraArg);
292 : }
293 :
294 18018 : const CPLErr eErr = m_poParent->RasterIO(
295 : GF_Read, nXOff, nYOff, nXSize, nYSize, pTemp, nBufXSize, nBufYSize,
296 9009 : eWrkDT, nWrkDTSize, static_cast<GSpacing>(nBufXSize) * nWrkDTSize,
297 : psExtraArg);
298 9009 : if (eErr != CE_None)
299 : {
300 0 : VSIFree(pTemp);
301 0 : return eErr;
302 : }
303 :
304 9009 : const bool bIsNoDataNan = CPLIsNan(m_dfNoDataValue) != 0;
305 9009 : GByte *pabyDest = static_cast<GByte *>(pData);
306 :
307 : /* --------------------------------------------------------------------
308 : */
309 : /* Process different cases. */
310 : /* --------------------------------------------------------------------
311 : */
312 9009 : switch (eWrkDT)
313 : {
314 15 : case GDT_UInt32:
315 : {
316 15 : const GUInt32 nNoData = static_cast<GUInt32>(m_dfNoDataValue);
317 15 : const GUInt32 *panSrc = static_cast<const GUInt32 *>(pTemp);
318 :
319 15 : size_t i = 0;
320 53 : for (int iY = 0; iY < nBufYSize; iY++)
321 : {
322 38 : GByte *pabyLineDest = pabyDest + iY * nLineSpace;
323 260 : for (int iX = 0; iX < nBufXSize; iX++)
324 : {
325 222 : *pabyLineDest = panSrc[i] == nNoData ? 0 : 255;
326 222 : ++i;
327 222 : pabyLineDest += nPixelSpace;
328 : }
329 : }
330 : }
331 15 : break;
332 :
333 1742 : case GDT_Int32:
334 : {
335 1742 : const GInt32 nNoData = static_cast<GInt32>(m_dfNoDataValue);
336 1742 : const GInt32 *panSrc = static_cast<const GInt32 *>(pTemp);
337 :
338 1742 : size_t i = 0;
339 3540 : for (int iY = 0; iY < nBufYSize; iY++)
340 : {
341 1798 : GByte *pabyLineDest = pabyDest + iY * nLineSpace;
342 821115 : for (int iX = 0; iX < nBufXSize; iX++)
343 : {
344 819317 : *pabyLineDest = panSrc[i] == nNoData ? 0 : 255;
345 819317 : ++i;
346 819317 : pabyLineDest += nPixelSpace;
347 : }
348 : }
349 : }
350 1742 : break;
351 :
352 7225 : case GDT_Float32:
353 : {
354 7225 : const float fNoData = static_cast<float>(m_dfNoDataValue);
355 7225 : const float *pafSrc = static_cast<const float *>(pTemp);
356 :
357 7225 : size_t i = 0;
358 14512 : for (int iY = 0; iY < nBufYSize; iY++)
359 : {
360 7287 : GByte *pabyLineDest = pabyDest + iY * nLineSpace;
361 1962100 : for (int iX = 0; iX < nBufXSize; iX++)
362 : {
363 1954810 : const float fVal = pafSrc[i];
364 1954810 : if (bIsNoDataNan && CPLIsNan(fVal))
365 20 : *pabyLineDest = 0;
366 1954790 : else if (ARE_REAL_EQUAL(fVal, fNoData))
367 876101 : *pabyLineDest = 0;
368 : else
369 1078690 : *pabyLineDest = 255;
370 1954810 : ++i;
371 1954810 : pabyLineDest += nPixelSpace;
372 : }
373 : }
374 : }
375 7225 : break;
376 :
377 19 : case GDT_Float64:
378 : {
379 19 : const double *padfSrc = static_cast<const double *>(pTemp);
380 :
381 19 : size_t i = 0;
382 60 : for (int iY = 0; iY < nBufYSize; iY++)
383 : {
384 41 : GByte *pabyLineDest = pabyDest + iY * nLineSpace;
385 194 : for (int iX = 0; iX < nBufXSize; iX++)
386 : {
387 153 : const double dfVal = padfSrc[i];
388 153 : if (bIsNoDataNan && CPLIsNan(dfVal))
389 20 : *pabyLineDest = 0;
390 133 : else if (ARE_REAL_EQUAL(dfVal, m_dfNoDataValue))
391 71 : *pabyLineDest = 0;
392 : else
393 62 : *pabyLineDest = 255;
394 153 : ++i;
395 153 : pabyLineDest += nPixelSpace;
396 : }
397 : }
398 : }
399 19 : break;
400 :
401 4 : case GDT_Int64:
402 : {
403 4 : const auto *panSrc = static_cast<const int64_t *>(pTemp);
404 :
405 4 : size_t i = 0;
406 8 : for (int iY = 0; iY < nBufYSize; iY++)
407 : {
408 4 : GByte *pabyLineDest = pabyDest + iY * nLineSpace;
409 8 : for (int iX = 0; iX < nBufXSize; iX++)
410 : {
411 4 : const auto nVal = panSrc[i];
412 4 : if (nVal == m_nNoDataValueInt64)
413 3 : *pabyLineDest = 0;
414 : else
415 1 : *pabyLineDest = 255;
416 4 : ++i;
417 4 : pabyLineDest += nPixelSpace;
418 : }
419 : }
420 : }
421 4 : break;
422 :
423 4 : case GDT_UInt64:
424 : {
425 4 : const auto *panSrc = static_cast<const uint64_t *>(pTemp);
426 :
427 4 : size_t i = 0;
428 8 : for (int iY = 0; iY < nBufYSize; iY++)
429 : {
430 4 : GByte *pabyLineDest = pabyDest + iY * nLineSpace;
431 8 : for (int iX = 0; iX < nBufXSize; iX++)
432 : {
433 4 : const auto nVal = panSrc[i];
434 4 : if (nVal == m_nNoDataValueUInt64)
435 3 : *pabyLineDest = 0;
436 : else
437 1 : *pabyLineDest = 255;
438 4 : ++i;
439 4 : pabyLineDest += nPixelSpace;
440 : }
441 : }
442 : }
443 4 : break;
444 :
445 0 : default:
446 0 : CPLAssert(false);
447 : break;
448 : }
449 :
450 9009 : VSIFree(pTemp);
451 9009 : return CE_None;
452 : }
453 :
454 : // Output buffer is non-Byte. Ask for Byte and expand to user requested
455 : // type
456 : GByte *pabyBuf =
457 79 : static_cast<GByte *>(VSI_MALLOC2_VERBOSE(nBufXSize, nBufYSize));
458 79 : if (pabyBuf == nullptr)
459 : {
460 0 : return GDALRasterBand::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
461 : pData, nBufXSize, nBufYSize, eBufType,
462 0 : nPixelSpace, nLineSpace, psExtraArg);
463 : }
464 : const CPLErr eErr =
465 158 : IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pabyBuf, nBufXSize,
466 79 : nBufYSize, GDT_Byte, 1, nBufXSize, psExtraArg);
467 79 : if (eErr != CE_None)
468 : {
469 0 : VSIFree(pabyBuf);
470 0 : return eErr;
471 : }
472 :
473 186 : for (int iY = 0; iY < nBufYSize; iY++)
474 : {
475 107 : GDALCopyWords(pabyBuf + static_cast<size_t>(iY) * nBufXSize, GDT_Byte,
476 107 : 1, static_cast<GByte *>(pData) + iY * nLineSpace,
477 : eBufType, static_cast<int>(nPixelSpace), nBufXSize);
478 : }
479 79 : VSIFree(pabyBuf);
480 79 : return CE_None;
481 : }
482 :
483 : //! @endcond
|