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 : * Permission is hereby granted, free of charge, to any person obtaining a
14 : * copy of this software and associated documentation files (the "Software"),
15 : * to deal in the Software without restriction, including without limitation
16 : * the rights to use, copy, modify, merge, publish, distribute, sublicense,
17 : * and/or sell copies of the Software, and to permit persons to whom the
18 : * Software is furnished to do so, subject to the following conditions:
19 : *
20 : * The above copyright notice and this permission notice shall be included
21 : * in all copies or substantial portions of the Software.
22 : *
23 : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
24 : * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
26 : * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
28 : * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29 : * DEALINGS IN THE SOFTWARE.
30 : ****************************************************************************/
31 :
32 : #include "cpl_port.h"
33 : #include "gdal_priv.h"
34 :
35 : #include <cstring>
36 :
37 : #include "cpl_conv.h"
38 : #include "cpl_error.h"
39 : #include "cpl_string.h"
40 : #include "cpl_vsi.h"
41 : #include "gdal.h"
42 :
43 : //! @cond Doxygen_Suppress
44 : /************************************************************************/
45 : /* GDALNoDataValuesMaskBand() */
46 : /************************************************************************/
47 :
48 56 : GDALNoDataValuesMaskBand::GDALNoDataValuesMaskBand(GDALDataset *poDSIn)
49 56 : : padfNodataValues(nullptr)
50 : {
51 56 : const char *pszNoDataValues = poDSIn->GetMetadataItem("NODATA_VALUES");
52 : char **papszNoDataValues =
53 56 : CSLTokenizeStringComplex(pszNoDataValues, " ", FALSE, FALSE);
54 :
55 56 : padfNodataValues = static_cast<double *>(
56 56 : CPLMalloc(sizeof(double) * poDSIn->GetRasterCount()));
57 224 : for (int i = 0; i < poDSIn->GetRasterCount(); ++i)
58 : {
59 168 : padfNodataValues[i] = CPLAtof(papszNoDataValues[i]);
60 : }
61 :
62 56 : CSLDestroy(papszNoDataValues);
63 :
64 56 : poDS = poDSIn;
65 56 : nBand = 0;
66 :
67 56 : nRasterXSize = poDS->GetRasterXSize();
68 56 : nRasterYSize = poDS->GetRasterYSize();
69 :
70 56 : eDataType = GDT_Byte;
71 56 : poDS->GetRasterBand(1)->GetBlockSize(&nBlockXSize, &nBlockYSize);
72 56 : }
73 :
74 : /************************************************************************/
75 : /* ~GDALNoDataValuesMaskBand() */
76 : /************************************************************************/
77 :
78 112 : GDALNoDataValuesMaskBand::~GDALNoDataValuesMaskBand()
79 :
80 : {
81 56 : CPLFree(padfNodataValues);
82 112 : }
83 :
84 : /************************************************************************/
85 : /* FillOutBuffer() */
86 : /************************************************************************/
87 :
88 : template <class T>
89 38 : static void FillOutBuffer(GPtrDiff_t nBlockOffsetPixels, int nBands,
90 : const void *pabySrc, const double *padfNodataValues,
91 : void *pImage)
92 : {
93 38 : T *paNoData = static_cast<T *>(CPLMalloc(nBands * sizeof(T)));
94 152 : for (int iBand = 0; iBand < nBands; ++iBand)
95 : {
96 114 : paNoData[iBand] = static_cast<T>(padfNodataValues[iBand]);
97 : }
98 :
99 127547 : for (GPtrDiff_t i = 0; i < nBlockOffsetPixels; i++)
100 : {
101 127509 : int nCountNoData = 0;
102 510036 : for (int iBand = 0; iBand < nBands; ++iBand)
103 : {
104 382527 : if (static_cast<const T *>(
105 382527 : pabySrc)[i + iBand * nBlockOffsetPixels] == paNoData[iBand])
106 109087 : ++nCountNoData;
107 : }
108 127509 : static_cast<GByte *>(pImage)[i] = nCountNoData == nBands ? 0 : 255;
109 : }
110 :
111 38 : CPLFree(paNoData);
112 38 : }
113 :
114 : /************************************************************************/
115 : /* IReadBlock() */
116 : /************************************************************************/
117 :
118 38 : CPLErr GDALNoDataValuesMaskBand::IReadBlock(int nXBlockOff, int nYBlockOff,
119 : void *pImage)
120 :
121 : {
122 38 : GDALDataType eWrkDT = GDT_Unknown;
123 :
124 : /* -------------------------------------------------------------------- */
125 : /* Decide on a working type. */
126 : /* -------------------------------------------------------------------- */
127 38 : switch (poDS->GetRasterBand(1)->GetRasterDataType())
128 : {
129 30 : case GDT_Byte:
130 30 : eWrkDT = GDT_Byte;
131 30 : break;
132 :
133 2 : case GDT_UInt16:
134 : case GDT_UInt32:
135 2 : eWrkDT = GDT_UInt32;
136 2 : break;
137 :
138 2 : case GDT_Int8:
139 : case GDT_Int16:
140 : case GDT_Int32:
141 : case GDT_CInt16:
142 : case GDT_CInt32:
143 2 : eWrkDT = GDT_Int32;
144 2 : break;
145 :
146 2 : case GDT_Float32:
147 : case GDT_CFloat32:
148 2 : eWrkDT = GDT_Float32;
149 2 : break;
150 :
151 2 : case GDT_Float64:
152 : case GDT_CFloat64:
153 2 : eWrkDT = GDT_Float64;
154 2 : break;
155 :
156 0 : case GDT_Int64:
157 : case GDT_UInt64:
158 : // Lossy mapping...
159 0 : eWrkDT = GDT_Float64;
160 0 : break;
161 :
162 0 : case GDT_Unknown:
163 : case GDT_TypeCount:
164 0 : CPLAssert(false);
165 : eWrkDT = GDT_Float64;
166 : break;
167 : }
168 :
169 : /* -------------------------------------------------------------------- */
170 : /* Read the image data. */
171 : /* -------------------------------------------------------------------- */
172 38 : const int nBands = poDS->GetRasterCount();
173 38 : const int nWrkDTSize = GDALGetDataTypeSizeBytes(eWrkDT);
174 38 : GByte *pabySrc = static_cast<GByte *>(VSI_MALLOC3_VERBOSE(
175 : cpl::fits_on<int>(nBands * nWrkDTSize), nBlockXSize, nBlockYSize));
176 38 : if (pabySrc == nullptr)
177 : {
178 0 : return CE_Failure;
179 : }
180 :
181 38 : int nXSizeRequest = 0;
182 38 : int nYSizeRequest = 0;
183 38 : GetActualBlockSize(nXBlockOff, nYBlockOff, &nXSizeRequest, &nYSizeRequest);
184 :
185 38 : if (nXSizeRequest != nBlockXSize || nYSizeRequest != nBlockYSize)
186 : {
187 : // memset the whole buffer to avoid Valgrind warnings in case we can't
188 : // fetch a full block.
189 0 : memset(pabySrc, 0,
190 0 : static_cast<size_t>(nBands) * nWrkDTSize * nBlockXSize *
191 0 : nBlockYSize);
192 : }
193 :
194 38 : const GPtrDiff_t nBlockOffsetPixels =
195 38 : static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize;
196 38 : const GPtrDiff_t nBandOffsetByte = nWrkDTSize * nBlockOffsetPixels;
197 152 : for (int iBand = 0; iBand < nBands; ++iBand)
198 : {
199 114 : const CPLErr eErr = poDS->GetRasterBand(iBand + 1)->RasterIO(
200 114 : GF_Read, nXBlockOff * nBlockXSize, nYBlockOff * nBlockYSize,
201 114 : nXSizeRequest, nYSizeRequest, pabySrc + iBand * nBandOffsetByte,
202 : nXSizeRequest, nYSizeRequest, eWrkDT, 0,
203 114 : static_cast<GSpacing>(nBlockXSize) * nWrkDTSize, nullptr);
204 114 : if (eErr != CE_None)
205 0 : return eErr;
206 : }
207 :
208 : /* -------------------------------------------------------------------- */
209 : /* Process different cases. */
210 : /* -------------------------------------------------------------------- */
211 38 : switch (eWrkDT)
212 : {
213 30 : case GDT_Byte:
214 : {
215 30 : FillOutBuffer<GByte>(nBlockOffsetPixels, nBands, pabySrc,
216 30 : padfNodataValues, pImage);
217 : }
218 30 : break;
219 :
220 2 : case GDT_UInt32:
221 : {
222 2 : FillOutBuffer<GUInt32>(nBlockOffsetPixels, nBands, pabySrc,
223 2 : padfNodataValues, pImage);
224 : }
225 2 : break;
226 :
227 2 : case GDT_Int32:
228 : {
229 2 : FillOutBuffer<GInt32>(nBlockOffsetPixels, nBands, pabySrc,
230 2 : padfNodataValues, pImage);
231 : }
232 2 : break;
233 :
234 2 : case GDT_Float32:
235 : {
236 2 : FillOutBuffer<float>(nBlockOffsetPixels, nBands, pabySrc,
237 2 : padfNodataValues, pImage);
238 : }
239 2 : break;
240 :
241 2 : case GDT_Float64:
242 : {
243 2 : FillOutBuffer<double>(nBlockOffsetPixels, nBands, pabySrc,
244 2 : padfNodataValues, pImage);
245 : }
246 2 : break;
247 :
248 0 : default:
249 0 : CPLAssert(false);
250 : break;
251 : }
252 :
253 38 : CPLFree(pabySrc);
254 :
255 38 : return CE_None;
256 : }
257 :
258 : //! @endcond
|