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