1 /****************************************************************************** 2 * 3 * Project: GDAL Core 4 * Purpose: Implementation of GDALNoDataMaskBand, a class implementing all 5 * a default band mask based on nodata values. 6 * Author: Frank Warmerdam, warmerdam@pobox.com 7 * 8 ****************************************************************************** 9 * Copyright (c) 2007, Frank Warmerdam 10 * Copyright (c) 2008-2012, Even Rouault <even dot rouault at spatialys.com> 11 * 12 * Permission is hereby granted, free of charge, to any person obtaining a 13 * copy of this software and associated documentation files (the "Software"), 14 * to deal in the Software without restriction, including without limitation 15 * the rights to use, copy, modify, merge, publish, distribute, sublicense, 16 * and/or sell copies of the Software, and to permit persons to whom the 17 * Software is furnished to do so, subject to the following conditions: 18 * 19 * The above copyright notice and this permission notice shall be included 20 * in all copies or substantial portions of the Software. 21 * 22 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 23 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 24 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 25 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 26 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 27 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 28 * DEALINGS IN THE SOFTWARE. 29 ****************************************************************************/ 30 31 #include "cpl_port.h" 32 #include "gdal_priv.h" 33 34 #include <algorithm> 35 #include <cstring> 36 37 #include "cpl_conv.h" 38 #include "cpl_error.h" 39 #include "cpl_vsi.h" 40 #include "gdal.h" 41 #include "gdal_priv_templates.hpp" 42 43 CPL_CVSID("$Id: gdalnodatamaskband.cpp b1c9c12ad373e40b955162b45d704070d4ebf7b0 2019-06-19 16:50:15 +0200 Even Rouault $") 44 45 //! @cond Doxygen_Suppress 46 /************************************************************************/ 47 /* GDALNoDataMaskBand() */ 48 /************************************************************************/ 49 50 GDALNoDataMaskBand::GDALNoDataMaskBand( GDALRasterBand *poParentIn ) : 51 dfNoDataValue(poParentIn->GetNoDataValue()), 52 poParent(poParentIn) 53 { 54 poDS = nullptr; 55 nBand = 0; 56 57 nRasterXSize = poParent->GetXSize(); 58 nRasterYSize = poParent->GetYSize(); 59 60 eDataType = GDT_Byte; 61 poParent->GetBlockSize( &nBlockXSize, &nBlockYSize ); 62 } 63 64 /************************************************************************/ 65 /* ~GDALNoDataMaskBand() */ 66 /************************************************************************/ 67 68 GDALNoDataMaskBand::~GDALNoDataMaskBand() = default; 69 70 /************************************************************************/ 71 /* GetWorkDataType() */ 72 /************************************************************************/ 73 74 static GDALDataType GetWorkDataType(GDALDataType eDataType) 75 { 76 GDALDataType eWrkDT = GDT_Unknown; 77 switch( eDataType ) 78 { 79 case GDT_Byte: 80 eWrkDT = GDT_Byte; 81 break; 82 83 case GDT_UInt16: 84 case GDT_UInt32: 85 eWrkDT = GDT_UInt32; 86 break; 87 88 case GDT_Int16: 89 case GDT_Int32: 90 case GDT_CInt16: 91 case GDT_CInt32: 92 eWrkDT = GDT_Int32; 93 break; 94 95 case GDT_Float32: 96 case GDT_CFloat32: 97 eWrkDT = GDT_Float32; 98 break; 99 100 case GDT_Float64: 101 case GDT_CFloat64: 102 eWrkDT = GDT_Float64; 103 break; 104 105 default: 106 CPLAssert( false ); 107 eWrkDT = GDT_Float64; 108 break; 109 } 110 return eWrkDT; 111 } 112 113 /************************************************************************/ 114 /* IsNoDataInRange() */ 115 /************************************************************************/ 116 117 bool GDALNoDataMaskBand::IsNoDataInRange(double dfNoDataValue, 118 GDALDataType eDataType) 119 { 120 GDALDataType eWrkDT = GetWorkDataType( eDataType ); 121 switch( eWrkDT ) 122 { 123 case GDT_Byte: 124 { 125 return GDALIsValueInRange<GByte>(dfNoDataValue); 126 } 127 128 case GDT_UInt32: 129 { 130 return GDALIsValueInRange<GUInt32>(dfNoDataValue); 131 } 132 133 case GDT_Int32: 134 { 135 return GDALIsValueInRange<GInt32>(dfNoDataValue); 136 } 137 138 case GDT_Float32: 139 { 140 return CPLIsNan(dfNoDataValue) || 141 CPLIsInf(dfNoDataValue) || 142 GDALIsValueInRange<float>(dfNoDataValue); 143 } 144 145 case GDT_Float64: 146 { 147 return true; 148 } 149 150 default: 151 CPLAssert( false ); 152 return false; 153 } 154 } 155 156 /************************************************************************/ 157 /* IReadBlock() */ 158 /************************************************************************/ 159 160 CPLErr GDALNoDataMaskBand::IReadBlock( int nXBlockOff, int nYBlockOff, 161 void * pImage ) 162 163 { 164 const int nXOff = nXBlockOff * nBlockXSize; 165 const int nXSizeRequest = std::min(nBlockXSize, nRasterXSize - nXOff); 166 const int nYOff = nYBlockOff * nBlockYSize; 167 const int nYSizeRequest = std::min(nBlockYSize, nRasterYSize - nYOff); 168 169 if( nBlockXSize != nXSizeRequest || nBlockYSize != nYSizeRequest ) 170 { 171 memset(pImage, 0, static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize); 172 } 173 174 GDALRasterIOExtraArg sExtraArg; 175 INIT_RASTERIO_EXTRA_ARG(sExtraArg); 176 return IRasterIO(GF_Read, nXOff, nYOff, nXSizeRequest, nYSizeRequest, 177 pImage, nXSizeRequest, nYSizeRequest, 178 GDT_Byte, 1, nBlockXSize, &sExtraArg); 179 } 180 181 /************************************************************************/ 182 /* IRasterIO() */ 183 /************************************************************************/ 184 185 CPLErr GDALNoDataMaskBand::IRasterIO( GDALRWFlag eRWFlag, 186 int nXOff, int nYOff, 187 int nXSize, int nYSize, 188 void * pData, 189 int nBufXSize, int nBufYSize, 190 GDALDataType eBufType, 191 GSpacing nPixelSpace, GSpacing nLineSpace, 192 GDALRasterIOExtraArg* psExtraArg ) 193 { 194 if( eRWFlag != GF_Read ) 195 { 196 return CE_Failure; 197 } 198 199 const GDALDataType eWrkDT = GetWorkDataType( poParent->GetRasterDataType() ); 200 201 // Optimization in common use case (#4488). 202 // This avoids triggering the block cache on this band, which helps 203 // reducing the global block cache consumption. 204 if (eBufType == GDT_Byte && eWrkDT == GDT_Byte) 205 { 206 const CPLErr eErr = 207 poParent->RasterIO( GF_Read, nXOff, nYOff, nXSize, nYSize, 208 pData, nBufXSize, nBufYSize, 209 eBufType, 210 nPixelSpace, nLineSpace, psExtraArg ); 211 if (eErr != CE_None) 212 return eErr; 213 214 GByte* pabyData = static_cast<GByte*>( pData ); 215 const GByte byNoData = static_cast<GByte>( dfNoDataValue ); 216 217 if( nPixelSpace == 1 && nLineSpace == nBufXSize ) 218 { 219 const size_t nBufSize = static_cast<size_t>(nBufXSize) * nBufYSize; 220 for( size_t i = 0; i < nBufSize; ++i ) 221 { 222 pabyData[i] = pabyData[i] == byNoData ? 0 : 255; 223 } 224 } 225 else 226 { 227 for( int iY = 0; iY < nBufYSize; iY++ ) 228 { 229 GByte* pabyLine = pabyData + iY * nLineSpace; 230 for( int iX = 0; iX < nBufXSize; iX++ ) 231 { 232 *pabyLine = *pabyLine == byNoData ? 0 : 255; 233 pabyLine += nPixelSpace; 234 } 235 } 236 } 237 return CE_None; 238 } 239 240 if( eBufType == GDT_Byte ) 241 { 242 const int nWrkDTSize = GDALGetDataTypeSizeBytes(eWrkDT); 243 void *pTemp = 244 VSI_MALLOC3_VERBOSE( nWrkDTSize, nBufXSize, nBufYSize ); 245 if (pTemp == nullptr) 246 { 247 return GDALRasterBand::IRasterIO( 248 eRWFlag, nXOff, nYOff, nXSize, nYSize, 249 pTemp, nBufXSize, nBufYSize, 250 eWrkDT, 251 nWrkDTSize, nBufXSize * nWrkDTSize, 252 psExtraArg ); 253 } 254 255 const CPLErr eErr = 256 poParent->RasterIO( GF_Read, nXOff, nYOff, nXSize, nYSize, 257 pTemp, nBufXSize, nBufYSize, 258 eWrkDT, 259 nWrkDTSize, nBufXSize * nWrkDTSize, psExtraArg ); 260 if (eErr != CE_None) 261 { 262 VSIFree(pTemp); 263 return eErr; 264 } 265 266 const bool bIsNoDataNan = CPLIsNan(dfNoDataValue) != 0; 267 GByte* pabyDest = static_cast<GByte*>(pData); 268 269 /* -------------------------------------------------------------------- */ 270 /* Process different cases. */ 271 /* -------------------------------------------------------------------- */ 272 switch( eWrkDT ) 273 { 274 case GDT_UInt32: 275 { 276 const GUInt32 nNoData = static_cast<GUInt32>( dfNoDataValue ); 277 const GUInt32* panSrc = static_cast<const GUInt32 *>(pTemp); 278 279 size_t i = 0; 280 for( int iY = 0; iY < nBufYSize; iY++ ) 281 { 282 GByte* pabyLineDest = pabyDest + iY * nLineSpace; 283 for( int iX = 0; iX < nBufXSize; iX++ ) 284 { 285 *pabyLineDest = panSrc[i] == nNoData ? 0 : 255; 286 ++i; 287 pabyLineDest += nPixelSpace; 288 } 289 } 290 } 291 break; 292 293 case GDT_Int32: 294 { 295 const GInt32 nNoData = static_cast<GInt32>( dfNoDataValue ); 296 const GInt32* panSrc = static_cast<const GInt32 *>(pTemp); 297 298 size_t i = 0; 299 for( int iY = 0; iY < nBufYSize; iY++ ) 300 { 301 GByte* pabyLineDest = pabyDest + iY * nLineSpace; 302 for( int iX = 0; iX < nBufXSize; iX++ ) 303 { 304 *pabyLineDest = panSrc[i] == nNoData ? 0 : 255; 305 ++i; 306 pabyLineDest += nPixelSpace; 307 } 308 } 309 } 310 break; 311 312 case GDT_Float32: 313 { 314 const float fNoData = static_cast<float>( dfNoDataValue ); 315 const float* pafSrc = static_cast<const float *>(pTemp); 316 317 size_t i = 0; 318 for( int iY = 0; iY < nBufYSize; iY++ ) 319 { 320 GByte* pabyLineDest = pabyDest + iY * nLineSpace; 321 for( int iX = 0; iX < nBufXSize; iX++ ) 322 { 323 const float fVal = pafSrc[i]; 324 if( bIsNoDataNan && CPLIsNan(fVal)) 325 *pabyLineDest = 0; 326 else if( ARE_REAL_EQUAL(fVal, fNoData) ) 327 *pabyLineDest = 0; 328 else 329 *pabyLineDest = 255; 330 ++i; 331 pabyLineDest += nPixelSpace; 332 } 333 } 334 } 335 break; 336 337 case GDT_Float64: 338 { 339 const double* padfSrc = static_cast<const double *>(pTemp); 340 341 size_t i = 0; 342 for( int iY = 0; iY < nBufYSize; iY++ ) 343 { 344 GByte* pabyLineDest = pabyDest + iY * nLineSpace; 345 for( int iX = 0; iX < nBufXSize; iX++ ) 346 { 347 const double dfVal = padfSrc[i]; 348 if( bIsNoDataNan && CPLIsNan(dfVal)) 349 *pabyLineDest = 0; 350 else if( ARE_REAL_EQUAL(dfVal, dfNoDataValue) ) 351 *pabyLineDest = 0; 352 else 353 *pabyLineDest = 255; 354 ++i; 355 pabyLineDest += nPixelSpace; 356 } 357 } 358 } 359 break; 360 361 default: 362 CPLAssert( false ); 363 break; 364 } 365 366 VSIFree(pTemp); 367 return CE_None; 368 } 369 370 // Output buffer is non-Byte. Ask for Byte and expand to user requested 371 // type 372 GByte* pabyBuf = static_cast<GByte*>( 373 VSI_MALLOC2_VERBOSE( nBufXSize, nBufYSize )); 374 if( pabyBuf == nullptr ) 375 { 376 return GDALRasterBand::IRasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize, 377 pData, nBufXSize, nBufYSize, 378 eBufType, 379 nPixelSpace, nLineSpace, psExtraArg ); 380 } 381 const CPLErr eErr = IRasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize, 382 pabyBuf, nBufXSize, nBufYSize, 383 GDT_Byte, 384 1, nBufXSize, psExtraArg ); 385 if( eErr != CE_None ) 386 { 387 VSIFree(pabyBuf); 388 return eErr; 389 } 390 391 for( int iY = 0; iY < nBufYSize; iY++ ) 392 { 393 GDALCopyWords( pabyBuf + static_cast<size_t>(iY) * nBufXSize, 394 GDT_Byte, 1, 395 static_cast<GByte*>(pData) + 396 iY * nLineSpace, eBufType, 397 static_cast<int>(nPixelSpace), 398 nBufXSize ); 399 } 400 VSIFree(pabyBuf); 401 return CE_None; 402 } 403 //! @endcond 404