EVOLUTION-MANAGER
Edit File: gdalnodatamaskband.cpp
/****************************************************************************** * * Project: GDAL Core * Purpose: Implementation of GDALNoDataMaskBand, a class implementing all * a default band mask based on nodata values. * Author: Frank Warmerdam, warmerdam@pobox.com * ****************************************************************************** * Copyright (c) 2007, Frank Warmerdam * Copyright (c) 2008-2012, Even Rouault <even dot rouault at mines-paris dot org> * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. ****************************************************************************/ #include "cpl_port.h" #include "gdal_priv.h" #include <algorithm> #include <cstring> #include "cpl_conv.h" #include "cpl_error.h" #include "cpl_vsi.h" #include "gdal.h" #include "gdal_priv_templates.hpp" CPL_CVSID("$Id: gdalnodatamaskband.cpp 003ad4e9e410423af8b35843956f781e44a8daac 2019-02-18 15:48:35 +0100 Even Rouault $") //! @cond Doxygen_Suppress /************************************************************************/ /* GDALNoDataMaskBand() */ /************************************************************************/ GDALNoDataMaskBand::GDALNoDataMaskBand( GDALRasterBand *poParentIn ) : dfNoDataValue(poParentIn->GetNoDataValue()), poParent(poParentIn) { poDS = nullptr; nBand = 0; nRasterXSize = poParent->GetXSize(); nRasterYSize = poParent->GetYSize(); eDataType = GDT_Byte; poParent->GetBlockSize( &nBlockXSize, &nBlockYSize ); } /************************************************************************/ /* ~GDALNoDataMaskBand() */ /************************************************************************/ GDALNoDataMaskBand::~GDALNoDataMaskBand() = default; /************************************************************************/ /* GetWorkDataType() */ /************************************************************************/ static GDALDataType GetWorkDataType(GDALDataType eDataType) { GDALDataType eWrkDT = GDT_Unknown; switch( eDataType ) { case GDT_Byte: eWrkDT = GDT_Byte; break; case GDT_UInt16: case GDT_UInt32: eWrkDT = GDT_UInt32; break; case GDT_Int16: case GDT_Int32: case GDT_CInt16: case GDT_CInt32: eWrkDT = GDT_Int32; break; case GDT_Float32: case GDT_CFloat32: eWrkDT = GDT_Float32; break; case GDT_Float64: case GDT_CFloat64: eWrkDT = GDT_Float64; break; default: CPLAssert( false ); eWrkDT = GDT_Float64; break; } return eWrkDT; } /************************************************************************/ /* IsNoDataInRange() */ /************************************************************************/ bool GDALNoDataMaskBand::IsNoDataInRange(double dfNoDataValue, GDALDataType eDataType) { GDALDataType eWrkDT = GetWorkDataType( eDataType ); switch( eWrkDT ) { case GDT_Byte: { return GDALIsValueInRange<GByte>(dfNoDataValue); } case GDT_UInt32: { return GDALIsValueInRange<GUInt32>(dfNoDataValue); } case GDT_Int32: { return GDALIsValueInRange<GInt32>(dfNoDataValue); } case GDT_Float32: { return CPLIsNan(dfNoDataValue) || CPLIsInf(dfNoDataValue) || GDALIsValueInRange<float>(dfNoDataValue); } case GDT_Float64: { return true; } default: CPLAssert( false ); return false; } } /************************************************************************/ /* IReadBlock() */ /************************************************************************/ CPLErr GDALNoDataMaskBand::IReadBlock( int nXBlockOff, int nYBlockOff, void * pImage ) { const int nXOff = nXBlockOff * nBlockXSize; const int nXSizeRequest = std::min(nBlockXSize, nRasterXSize - nXOff); const int nYOff = nYBlockOff * nBlockYSize; const int nYSizeRequest = std::min(nBlockYSize, nRasterYSize - nYOff); if( nBlockXSize != nXSizeRequest || nBlockYSize != nYSizeRequest ) { memset(pImage, 0, static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize); } GDALRasterIOExtraArg sExtraArg; INIT_RASTERIO_EXTRA_ARG(sExtraArg); return IRasterIO(GF_Read, nXOff, nYOff, nXSizeRequest, nYSizeRequest, pImage, nXSizeRequest, nYSizeRequest, GDT_Byte, 1, nBlockXSize, &sExtraArg); } /************************************************************************/ /* IRasterIO() */ /************************************************************************/ CPLErr GDALNoDataMaskBand::IRasterIO( GDALRWFlag eRWFlag, int nXOff, int nYOff, int nXSize, int nYSize, void * pData, int nBufXSize, int nBufYSize, GDALDataType eBufType, GSpacing nPixelSpace, GSpacing nLineSpace, GDALRasterIOExtraArg* psExtraArg ) { if( eRWFlag != GF_Read ) { return CE_Failure; } const GDALDataType eWrkDT = GetWorkDataType( poParent->GetRasterDataType() ); // Optimization in common use case (#4488). // This avoids triggering the block cache on this band, which helps // reducing the global block cache consumption. if (eBufType == GDT_Byte && eWrkDT == GDT_Byte) { const CPLErr eErr = poParent->RasterIO( GF_Read, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize, nBufYSize, eBufType, nPixelSpace, nLineSpace, psExtraArg ); if (eErr != CE_None) return eErr; GByte* pabyData = static_cast<GByte*>( pData ); const GByte byNoData = static_cast<GByte>( dfNoDataValue ); if( nPixelSpace == 1 && nLineSpace == nBufXSize ) { const size_t nBufSize = static_cast<size_t>(nBufXSize) * nBufYSize; for( size_t i = 0; i < nBufSize; ++i ) { pabyData[i] = pabyData[i] == byNoData ? 0 : 255; } } else { for( int iY = 0; iY < nBufYSize; iY++ ) { GByte* pabyLine = pabyData + iY * nLineSpace; for( int iX = 0; iX < nBufXSize; iX++ ) { *pabyLine = *pabyLine == byNoData ? 0 : 255; pabyLine += nPixelSpace; } } } return CE_None; } if( eBufType == GDT_Byte ) { const int nWrkDTSize = GDALGetDataTypeSizeBytes(eWrkDT); void *pTemp = VSI_MALLOC3_VERBOSE( nWrkDTSize, nBufXSize, nBufYSize ); if (pTemp == nullptr) { return GDALRasterBand::IRasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize, pTemp, nBufXSize, nBufYSize, eWrkDT, nWrkDTSize, nBufXSize * nWrkDTSize, psExtraArg ); } const CPLErr eErr = poParent->RasterIO( GF_Read, nXOff, nYOff, nXSize, nYSize, pTemp, nBufXSize, nBufYSize, eWrkDT, nWrkDTSize, nBufXSize * nWrkDTSize, psExtraArg ); if (eErr != CE_None) { VSIFree(pTemp); return eErr; } const bool bIsNoDataNan = CPLIsNan(dfNoDataValue) != 0; GByte* pabyDest = static_cast<GByte*>(pData); /* -------------------------------------------------------------------- */ /* Process different cases. */ /* -------------------------------------------------------------------- */ switch( eWrkDT ) { case GDT_UInt32: { const GUInt32 nNoData = static_cast<GUInt32>( dfNoDataValue ); const GUInt32* panSrc = static_cast<const GUInt32 *>(pTemp); size_t i = 0; for( int iY = 0; iY < nBufYSize; iY++ ) { GByte* pabyLineDest = pabyDest + iY * nLineSpace; for( int iX = 0; iX < nBufXSize; iX++ ) { *pabyLineDest = panSrc[i] == nNoData ? 0 : 255; ++i; pabyLineDest += nPixelSpace; } } } break; case GDT_Int32: { const GInt32 nNoData = static_cast<GInt32>( dfNoDataValue ); const GInt32* panSrc = static_cast<const GInt32 *>(pTemp); size_t i = 0; for( int iY = 0; iY < nBufYSize; iY++ ) { GByte* pabyLineDest = pabyDest + iY * nLineSpace; for( int iX = 0; iX < nBufXSize; iX++ ) { *pabyLineDest = panSrc[i] == nNoData ? 0 : 255; ++i; pabyLineDest += nPixelSpace; } } } break; case GDT_Float32: { const float fNoData = static_cast<float>( dfNoDataValue ); const float* pafSrc = static_cast<const float *>(pTemp); size_t i = 0; for( int iY = 0; iY < nBufYSize; iY++ ) { GByte* pabyLineDest = pabyDest + iY * nLineSpace; for( int iX = 0; iX < nBufXSize; iX++ ) { const float fVal = pafSrc[i]; if( bIsNoDataNan && CPLIsNan(fVal)) *pabyLineDest = 0; else if( ARE_REAL_EQUAL(fVal, fNoData) ) *pabyLineDest = 0; else *pabyLineDest = 255; ++i; pabyLineDest += nPixelSpace; } } } break; case GDT_Float64: { const double* padfSrc = static_cast<const double *>(pTemp); size_t i = 0; for( int iY = 0; iY < nBufYSize; iY++ ) { GByte* pabyLineDest = pabyDest + iY * nLineSpace; for( int iX = 0; iX < nBufXSize; iX++ ) { const double dfVal = padfSrc[i]; if( bIsNoDataNan && CPLIsNan(dfVal)) *pabyLineDest = 0; else if( ARE_REAL_EQUAL(dfVal, dfNoDataValue) ) *pabyLineDest = 0; else *pabyLineDest = 255; ++i; pabyLineDest += nPixelSpace; } } } break; default: CPLAssert( false ); break; } VSIFree(pTemp); return CE_None; } // Output buffer is non-Byte. Ask for Byte and expand to user requested // type GByte* pabyBuf = static_cast<GByte*>( VSI_MALLOC2_VERBOSE( nBufXSize, nBufYSize )); if( pabyBuf == nullptr ) { return GDALRasterBand::IRasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize, nBufYSize, eBufType, nPixelSpace, nLineSpace, psExtraArg ); } const CPLErr eErr = IRasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize, pabyBuf, nBufXSize, nBufYSize, GDT_Byte, 1, nBufXSize, psExtraArg ); if( eErr != CE_None ) { VSIFree(pabyBuf); return eErr; } for( int iY = 0; iY < nBufYSize; iY++ ) { GDALCopyWords( pabyBuf + static_cast<size_t>(iY) * nBufXSize, GDT_Byte, 1, static_cast<GByte*>(pData) + iY * nLineSpace, eBufType, static_cast<int>(nPixelSpace), nBufXSize ); } VSIFree(pabyBuf); return CE_None; } //! @endcond