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 CPL_CVSID("$Id: gdalnodatavaluesmaskband.cpp 355b41831cd2685c85d1aabe5b95665a2c6e99b7 2019-06-19 17:07:04 +0200 Even Rouault $")
44
45 //! @cond Doxygen_Suppress
46 /************************************************************************/
47 /* GDALNoDataValuesMaskBand() */
48 /************************************************************************/
49
GDALNoDataValuesMaskBand(GDALDataset * poDSIn)50 GDALNoDataValuesMaskBand::GDALNoDataValuesMaskBand( GDALDataset* poDSIn ) :
51 padfNodataValues(nullptr)
52 {
53 const char* pszNoDataValues = poDSIn->GetMetadataItem("NODATA_VALUES");
54 char** papszNoDataValues =
55 CSLTokenizeStringComplex(pszNoDataValues, " ", FALSE, FALSE);
56
57 padfNodataValues = static_cast<double*>(
58 CPLMalloc(sizeof(double) * poDSIn->GetRasterCount()) );
59 for( int i = 0; i < poDSIn->GetRasterCount(); ++i )
60 {
61 padfNodataValues[i] = CPLAtof(papszNoDataValues[i]);
62 }
63
64 CSLDestroy(papszNoDataValues);
65
66 poDS = poDSIn;
67 nBand = 0;
68
69 nRasterXSize = poDS->GetRasterXSize();
70 nRasterYSize = poDS->GetRasterYSize();
71
72 eDataType = GDT_Byte;
73 poDS->GetRasterBand(1)->GetBlockSize( &nBlockXSize, &nBlockYSize );
74 }
75
76 /************************************************************************/
77 /* ~GDALNoDataValuesMaskBand() */
78 /************************************************************************/
79
~GDALNoDataValuesMaskBand()80 GDALNoDataValuesMaskBand::~GDALNoDataValuesMaskBand()
81
82 {
83 CPLFree(padfNodataValues);
84 }
85
86 /************************************************************************/
87 /* FillOutBuffer() */
88 /************************************************************************/
89
FillOutBuffer(GPtrDiff_t nBlockOffsetPixels,int nBands,const void * pabySrc,const double * padfNodataValues,void * pImage)90 template<class T> static void FillOutBuffer(GPtrDiff_t nBlockOffsetPixels,
91 int nBands,
92 const void* pabySrc,
93 const double* padfNodataValues,
94 void* pImage)
95 {
96 T* paNoData = static_cast<T*>(
97 CPLMalloc(nBands * sizeof(T)) );
98 for( int iBand = 0; iBand < nBands; ++iBand )
99 {
100 paNoData[iBand] = static_cast<T>(padfNodataValues[iBand]);
101 }
102
103 for( GPtrDiff_t i = 0; i < nBlockOffsetPixels; i++ )
104 {
105 int nCountNoData = 0;
106 for( int iBand = 0; iBand < nBands; ++iBand )
107 {
108 if( static_cast<const T *>(pabySrc)[i + iBand * nBlockOffsetPixels] ==
109 paNoData[iBand] )
110 ++nCountNoData;
111 }
112 static_cast<GByte *>(pImage)[i] =
113 nCountNoData == nBands ? 0 : 255;
114 }
115
116 CPLFree(paNoData);
117 }
118
119 /************************************************************************/
120 /* IReadBlock() */
121 /************************************************************************/
122
IReadBlock(int nXBlockOff,int nYBlockOff,void * pImage)123 CPLErr GDALNoDataValuesMaskBand::IReadBlock( int nXBlockOff, int nYBlockOff,
124 void * pImage )
125
126 {
127 GDALDataType eWrkDT = GDT_Unknown;
128
129 /* -------------------------------------------------------------------- */
130 /* Decide on a working type. */
131 /* -------------------------------------------------------------------- */
132 switch( poDS->GetRasterBand(1)->GetRasterDataType() )
133 {
134 case GDT_Byte:
135 eWrkDT = GDT_Byte;
136 break;
137
138 case GDT_UInt16:
139 case GDT_UInt32:
140 eWrkDT = GDT_UInt32;
141 break;
142
143 case GDT_Int16:
144 case GDT_Int32:
145 case GDT_CInt16:
146 case GDT_CInt32:
147 eWrkDT = GDT_Int32;
148 break;
149
150 case GDT_Float32:
151 case GDT_CFloat32:
152 eWrkDT = GDT_Float32;
153 break;
154
155 case GDT_Float64:
156 case GDT_CFloat64:
157 eWrkDT = GDT_Float64;
158 break;
159
160 default:
161 CPLAssert( false );
162 eWrkDT = GDT_Float64;
163 break;
164 }
165
166 /* -------------------------------------------------------------------- */
167 /* Read the image data. */
168 /* -------------------------------------------------------------------- */
169 const int nBands = poDS->GetRasterCount();
170 GByte *pabySrc = static_cast<GByte *>(
171 VSI_MALLOC3_VERBOSE( nBands * GDALGetDataTypeSizeBytes(eWrkDT),
172 nBlockXSize, nBlockYSize ) );
173 if (pabySrc == nullptr)
174 {
175 return CE_Failure;
176 }
177
178 int nXSizeRequest = nBlockXSize;
179 if (nXBlockOff * nBlockXSize + nBlockXSize > nRasterXSize)
180 nXSizeRequest = nRasterXSize - nXBlockOff * nBlockXSize;
181 int nYSizeRequest = nBlockYSize;
182 if (nYBlockOff * nBlockYSize + nBlockYSize > nRasterYSize)
183 nYSizeRequest = nRasterYSize - nYBlockOff * nBlockYSize;
184
185 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 memset( pabySrc, 0,
190 nBands * GDALGetDataTypeSizeBytes(eWrkDT) *
191 nBlockXSize * nBlockYSize );
192 }
193
194 const GPtrDiff_t nBlockOffsetPixels = static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize;
195 const GPtrDiff_t nBandOffsetByte =
196 GDALGetDataTypeSizeBytes(eWrkDT) * nBlockOffsetPixels;
197 for( int iBand = 0; iBand < nBands; ++iBand )
198 {
199 const CPLErr eErr =
200 poDS->GetRasterBand(iBand + 1)->RasterIO(
201 GF_Read,
202 nXBlockOff * nBlockXSize,
203 nYBlockOff * nBlockYSize,
204 nXSizeRequest,
205 nYSizeRequest,
206 pabySrc + iBand * nBandOffsetByte,
207 nXSizeRequest,
208 nYSizeRequest,
209 eWrkDT, 0,
210 static_cast<GSpacing>(nBlockXSize) * GDALGetDataTypeSizeBytes(eWrkDT),
211 nullptr );
212 if( eErr != CE_None )
213 return eErr;
214 }
215
216 /* -------------------------------------------------------------------- */
217 /* Process different cases. */
218 /* -------------------------------------------------------------------- */
219 switch( eWrkDT )
220 {
221 case GDT_Byte:
222 {
223 FillOutBuffer<GByte> (nBlockOffsetPixels, nBands,
224 pabySrc, padfNodataValues,
225 pImage);
226 }
227 break;
228
229 case GDT_UInt32:
230 {
231 FillOutBuffer<GUInt32>(nBlockOffsetPixels, nBands,
232 pabySrc, padfNodataValues,
233 pImage);
234 }
235 break;
236
237 case GDT_Int32:
238 {
239 FillOutBuffer<GInt32>(nBlockOffsetPixels, nBands,
240 pabySrc, padfNodataValues,
241 pImage);
242 }
243 break;
244
245 case GDT_Float32:
246 {
247 FillOutBuffer<float> (nBlockOffsetPixels, nBands,
248 pabySrc, padfNodataValues,
249 pImage);
250 }
251 break;
252
253 case GDT_Float64:
254 {
255 FillOutBuffer<double>(nBlockOffsetPixels, nBands,
256 pabySrc, padfNodataValues,
257 pImage);
258 }
259 break;
260
261 default:
262 CPLAssert( false );
263 break;
264 }
265
266 CPLFree( pabySrc );
267
268 return CE_None;
269 }
270 //! @endcond
271