Line data Source code
1 : /******************************************************************************
2 : *
3 : * Project: GDAL Core
4 : * Purpose: Implementation of GDALNoDataValuesMaskBand, a class implementing
5 : * a default band mask based on the NODATA_VALUES metadata item.
6 : * A pixel is considered nodata in all bands if and only if all bands
7 : * match the corresponding value in the NODATA_VALUES tuple
8 : * Author: Even Rouault, <even dot rouault at spatialys.com>
9 : *
10 : ******************************************************************************
11 : * Copyright (c) 2008-2009, Even Rouault <even dot rouault at spatialys.com>
12 : *
13 : * SPDX-License-Identifier: MIT
14 : ****************************************************************************/
15 :
16 : #include "cpl_port.h"
17 : #include "gdal_priv.h"
18 :
19 : #include <cstring>
20 :
21 : #include "cpl_conv.h"
22 : #include "cpl_error.h"
23 : #include "cpl_string.h"
24 : #include "cpl_vsi.h"
25 : #include "gdal.h"
26 :
27 : //! @cond Doxygen_Suppress
28 : /************************************************************************/
29 : /* GDALNoDataValuesMaskBand() */
30 : /************************************************************************/
31 :
32 56 : GDALNoDataValuesMaskBand::GDALNoDataValuesMaskBand(GDALDataset *poDSIn)
33 56 : : padfNodataValues(nullptr)
34 : {
35 56 : const char *pszNoDataValues = poDSIn->GetMetadataItem("NODATA_VALUES");
36 : char **papszNoDataValues =
37 56 : CSLTokenizeStringComplex(pszNoDataValues, " ", FALSE, FALSE);
38 :
39 56 : padfNodataValues = static_cast<double *>(
40 56 : CPLMalloc(sizeof(double) * poDSIn->GetRasterCount()));
41 224 : for (int i = 0; i < poDSIn->GetRasterCount(); ++i)
42 : {
43 168 : padfNodataValues[i] = CPLAtof(papszNoDataValues[i]);
44 : }
45 :
46 56 : CSLDestroy(papszNoDataValues);
47 :
48 56 : poDS = poDSIn;
49 56 : nBand = 0;
50 :
51 56 : nRasterXSize = poDS->GetRasterXSize();
52 56 : nRasterYSize = poDS->GetRasterYSize();
53 :
54 56 : eDataType = GDT_Byte;
55 56 : poDS->GetRasterBand(1)->GetBlockSize(&nBlockXSize, &nBlockYSize);
56 56 : }
57 :
58 : /************************************************************************/
59 : /* ~GDALNoDataValuesMaskBand() */
60 : /************************************************************************/
61 :
62 112 : GDALNoDataValuesMaskBand::~GDALNoDataValuesMaskBand()
63 :
64 : {
65 56 : CPLFree(padfNodataValues);
66 112 : }
67 :
68 : /************************************************************************/
69 : /* FillOutBuffer() */
70 : /************************************************************************/
71 :
72 : template <class T>
73 38 : static void FillOutBuffer(GPtrDiff_t nBlockOffsetPixels, int nBands,
74 : const void *pabySrc, const double *padfNodataValues,
75 : void *pImage)
76 : {
77 38 : T *paNoData = static_cast<T *>(CPLMalloc(nBands * sizeof(T)));
78 152 : for (int iBand = 0; iBand < nBands; ++iBand)
79 : {
80 114 : paNoData[iBand] = static_cast<T>(padfNodataValues[iBand]);
81 : }
82 :
83 127547 : for (GPtrDiff_t i = 0; i < nBlockOffsetPixels; i++)
84 : {
85 127509 : int nCountNoData = 0;
86 510036 : for (int iBand = 0; iBand < nBands; ++iBand)
87 : {
88 382527 : if (static_cast<const T *>(
89 382527 : pabySrc)[i + iBand * nBlockOffsetPixels] == paNoData[iBand])
90 109087 : ++nCountNoData;
91 : }
92 127509 : static_cast<GByte *>(pImage)[i] = nCountNoData == nBands ? 0 : 255;
93 : }
94 :
95 38 : CPLFree(paNoData);
96 38 : }
97 :
98 : /************************************************************************/
99 : /* IReadBlock() */
100 : /************************************************************************/
101 :
102 38 : CPLErr GDALNoDataValuesMaskBand::IReadBlock(int nXBlockOff, int nYBlockOff,
103 : void *pImage)
104 :
105 : {
106 38 : GDALDataType eWrkDT = GDT_Unknown;
107 :
108 : /* -------------------------------------------------------------------- */
109 : /* Decide on a working type. */
110 : /* -------------------------------------------------------------------- */
111 38 : switch (poDS->GetRasterBand(1)->GetRasterDataType())
112 : {
113 30 : case GDT_Byte:
114 30 : eWrkDT = GDT_Byte;
115 30 : break;
116 :
117 2 : case GDT_UInt16:
118 : case GDT_UInt32:
119 2 : eWrkDT = GDT_UInt32;
120 2 : break;
121 :
122 2 : case GDT_Int8:
123 : case GDT_Int16:
124 : case GDT_Int32:
125 : case GDT_CInt16:
126 : case GDT_CInt32:
127 2 : eWrkDT = GDT_Int32;
128 2 : break;
129 :
130 2 : case GDT_Float16:
131 : case GDT_CFloat16:
132 : case GDT_Float32:
133 : case GDT_CFloat32:
134 2 : eWrkDT = GDT_Float32;
135 2 : break;
136 :
137 2 : case GDT_Float64:
138 : case GDT_CFloat64:
139 2 : eWrkDT = GDT_Float64;
140 2 : break;
141 :
142 0 : case GDT_Int64:
143 : case GDT_UInt64:
144 : // Lossy mapping...
145 0 : eWrkDT = GDT_Float64;
146 0 : break;
147 :
148 0 : case GDT_Unknown:
149 : case GDT_TypeCount:
150 0 : CPLAssert(false);
151 : eWrkDT = GDT_Float64;
152 : break;
153 : }
154 :
155 : /* -------------------------------------------------------------------- */
156 : /* Read the image data. */
157 : /* -------------------------------------------------------------------- */
158 38 : const int nBands = poDS->GetRasterCount();
159 38 : const int nWrkDTSize = GDALGetDataTypeSizeBytes(eWrkDT);
160 38 : GByte *pabySrc = static_cast<GByte *>(VSI_MALLOC3_VERBOSE(
161 : cpl::fits_on<int>(nBands * nWrkDTSize), nBlockXSize, nBlockYSize));
162 38 : if (pabySrc == nullptr)
163 : {
164 0 : return CE_Failure;
165 : }
166 :
167 38 : int nXSizeRequest = 0;
168 38 : int nYSizeRequest = 0;
169 38 : GetActualBlockSize(nXBlockOff, nYBlockOff, &nXSizeRequest, &nYSizeRequest);
170 :
171 38 : if (nXSizeRequest != nBlockXSize || nYSizeRequest != nBlockYSize)
172 : {
173 : // memset the whole buffer to avoid Valgrind warnings in case we can't
174 : // fetch a full block.
175 0 : memset(pabySrc, 0,
176 0 : static_cast<size_t>(nBands) * nWrkDTSize * nBlockXSize *
177 0 : nBlockYSize);
178 : }
179 :
180 38 : const GPtrDiff_t nBlockOffsetPixels =
181 38 : static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize;
182 38 : const GPtrDiff_t nBandOffsetByte = nWrkDTSize * nBlockOffsetPixels;
183 152 : for (int iBand = 0; iBand < nBands; ++iBand)
184 : {
185 114 : const CPLErr eErr = poDS->GetRasterBand(iBand + 1)->RasterIO(
186 114 : GF_Read, nXBlockOff * nBlockXSize, nYBlockOff * nBlockYSize,
187 114 : nXSizeRequest, nYSizeRequest, pabySrc + iBand * nBandOffsetByte,
188 : nXSizeRequest, nYSizeRequest, eWrkDT, 0,
189 114 : static_cast<GSpacing>(nBlockXSize) * nWrkDTSize, nullptr);
190 114 : if (eErr != CE_None)
191 0 : return eErr;
192 : }
193 :
194 : /* -------------------------------------------------------------------- */
195 : /* Process different cases. */
196 : /* -------------------------------------------------------------------- */
197 38 : switch (eWrkDT)
198 : {
199 30 : case GDT_Byte:
200 : {
201 30 : FillOutBuffer<GByte>(nBlockOffsetPixels, nBands, pabySrc,
202 30 : padfNodataValues, pImage);
203 : }
204 30 : break;
205 :
206 2 : case GDT_UInt32:
207 : {
208 2 : FillOutBuffer<GUInt32>(nBlockOffsetPixels, nBands, pabySrc,
209 2 : padfNodataValues, pImage);
210 : }
211 2 : break;
212 :
213 2 : case GDT_Int32:
214 : {
215 2 : FillOutBuffer<GInt32>(nBlockOffsetPixels, nBands, pabySrc,
216 2 : padfNodataValues, pImage);
217 : }
218 2 : break;
219 :
220 2 : case GDT_Float32:
221 : {
222 2 : FillOutBuffer<float>(nBlockOffsetPixels, nBands, pabySrc,
223 2 : padfNodataValues, pImage);
224 : }
225 2 : break;
226 :
227 2 : case GDT_Float64:
228 : {
229 2 : FillOutBuffer<double>(nBlockOffsetPixels, nBands, pabySrc,
230 2 : padfNodataValues, pImage);
231 : }
232 2 : break;
233 :
234 0 : default:
235 0 : CPLAssert(false);
236 : break;
237 : }
238 :
239 38 : CPLFree(pabySrc);
240 :
241 38 : return CE_None;
242 : }
243 :
244 : //! @endcond
|