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_Float32:
131 : case GDT_CFloat32:
132 2 : eWrkDT = GDT_Float32;
133 2 : break;
134 :
135 2 : case GDT_Float64:
136 : case GDT_CFloat64:
137 2 : eWrkDT = GDT_Float64;
138 2 : break;
139 :
140 0 : case GDT_Int64:
141 : case GDT_UInt64:
142 : // Lossy mapping...
143 0 : eWrkDT = GDT_Float64;
144 0 : break;
145 :
146 0 : case GDT_Unknown:
147 : case GDT_TypeCount:
148 0 : CPLAssert(false);
149 : eWrkDT = GDT_Float64;
150 : break;
151 : }
152 :
153 : /* -------------------------------------------------------------------- */
154 : /* Read the image data. */
155 : /* -------------------------------------------------------------------- */
156 38 : const int nBands = poDS->GetRasterCount();
157 38 : const int nWrkDTSize = GDALGetDataTypeSizeBytes(eWrkDT);
158 38 : GByte *pabySrc = static_cast<GByte *>(VSI_MALLOC3_VERBOSE(
159 : cpl::fits_on<int>(nBands * nWrkDTSize), nBlockXSize, nBlockYSize));
160 38 : if (pabySrc == nullptr)
161 : {
162 0 : return CE_Failure;
163 : }
164 :
165 38 : int nXSizeRequest = 0;
166 38 : int nYSizeRequest = 0;
167 38 : GetActualBlockSize(nXBlockOff, nYBlockOff, &nXSizeRequest, &nYSizeRequest);
168 :
169 38 : if (nXSizeRequest != nBlockXSize || nYSizeRequest != nBlockYSize)
170 : {
171 : // memset the whole buffer to avoid Valgrind warnings in case we can't
172 : // fetch a full block.
173 0 : memset(pabySrc, 0,
174 0 : static_cast<size_t>(nBands) * nWrkDTSize * nBlockXSize *
175 0 : nBlockYSize);
176 : }
177 :
178 38 : const GPtrDiff_t nBlockOffsetPixels =
179 38 : static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize;
180 38 : const GPtrDiff_t nBandOffsetByte = nWrkDTSize * nBlockOffsetPixels;
181 152 : for (int iBand = 0; iBand < nBands; ++iBand)
182 : {
183 114 : const CPLErr eErr = poDS->GetRasterBand(iBand + 1)->RasterIO(
184 114 : GF_Read, nXBlockOff * nBlockXSize, nYBlockOff * nBlockYSize,
185 114 : nXSizeRequest, nYSizeRequest, pabySrc + iBand * nBandOffsetByte,
186 : nXSizeRequest, nYSizeRequest, eWrkDT, 0,
187 114 : static_cast<GSpacing>(nBlockXSize) * nWrkDTSize, nullptr);
188 114 : if (eErr != CE_None)
189 0 : return eErr;
190 : }
191 :
192 : /* -------------------------------------------------------------------- */
193 : /* Process different cases. */
194 : /* -------------------------------------------------------------------- */
195 38 : switch (eWrkDT)
196 : {
197 30 : case GDT_Byte:
198 : {
199 30 : FillOutBuffer<GByte>(nBlockOffsetPixels, nBands, pabySrc,
200 30 : padfNodataValues, pImage);
201 : }
202 30 : break;
203 :
204 2 : case GDT_UInt32:
205 : {
206 2 : FillOutBuffer<GUInt32>(nBlockOffsetPixels, nBands, pabySrc,
207 2 : padfNodataValues, pImage);
208 : }
209 2 : break;
210 :
211 2 : case GDT_Int32:
212 : {
213 2 : FillOutBuffer<GInt32>(nBlockOffsetPixels, nBands, pabySrc,
214 2 : padfNodataValues, pImage);
215 : }
216 2 : break;
217 :
218 2 : case GDT_Float32:
219 : {
220 2 : FillOutBuffer<float>(nBlockOffsetPixels, nBands, pabySrc,
221 2 : padfNodataValues, pImage);
222 : }
223 2 : break;
224 :
225 2 : case GDT_Float64:
226 : {
227 2 : FillOutBuffer<double>(nBlockOffsetPixels, nBands, pabySrc,
228 2 : padfNodataValues, pImage);
229 : }
230 2 : break;
231 :
232 0 : default:
233 0 : CPLAssert(false);
234 : break;
235 : }
236 :
237 38 : CPLFree(pabySrc);
238 :
239 38 : return CE_None;
240 : }
241 :
242 : //! @endcond
|