CPLErr VRTFilteredSource::RasterIO( int nXOff, int nYOff, int nXSize, int nYSize, void *pData, int nBufXSize, int nBufYSize, GDALDataType eBufType, GSpacing nPixelSpace, GSpacing nLineSpace, GDALRasterIOExtraArg* psExtraArg ) { /* -------------------------------------------------------------------- */ /* For now we don't support filtered access to non-full */ /* resolution requests. Just collect the data directly without */ /* any operator. */ /* -------------------------------------------------------------------- */ if( nBufXSize != nXSize || nBufYSize != nYSize ) { return VRTComplexSource::RasterIO( nXOff, nYOff, nXSize, nYSize, pData, nBufXSize, nBufYSize, eBufType, nPixelSpace, nLineSpace, psExtraArg ); } // The window we will actually request from the source raster band. double dfReqXOff, dfReqYOff, dfReqXSize, dfReqYSize; int nReqXOff, nReqYOff, nReqXSize, nReqYSize; // The window we will actual set _within_ the pData buffer. int nOutXOff, nOutYOff, nOutXSize, nOutYSize; if( !GetSrcDstWindow( nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize, &dfReqXOff, &dfReqYOff, &dfReqXSize, &dfReqYSize, &nReqXOff, &nReqYOff, &nReqXSize, &nReqYSize, &nOutXOff, &nOutYOff, &nOutXSize, &nOutYSize ) ) return CE_None; pData = ((GByte *)pData) + nPixelSpace * nOutXOff + nLineSpace * nOutYOff; /* -------------------------------------------------------------------- */ /* Determine the data type we want to request. We try to match */ /* the source or destination request, and if both those fail we */ /* fallback to the first supported type at least as expressive */ /* as the request. */ /* -------------------------------------------------------------------- */ GDALDataType eOperDataType = GDT_Unknown; int i; if( IsTypeSupported( eBufType ) ) eOperDataType = eBufType; if( eOperDataType == GDT_Unknown && IsTypeSupported( poRasterBand->GetRasterDataType() ) ) eOperDataType = poRasterBand->GetRasterDataType(); if( eOperDataType == GDT_Unknown ) { for( i = 0; i < nSupportedTypesCount; i++ ) { if( GDALDataTypeUnion( aeSupportedTypes[i], eBufType ) == aeSupportedTypes[i] ) { eOperDataType = aeSupportedTypes[i]; } } } if( eOperDataType == GDT_Unknown ) { eOperDataType = aeSupportedTypes[0]; for( i = 1; i < nSupportedTypesCount; i++ ) { if( GDALGetDataTypeSize( aeSupportedTypes[i] ) > GDALGetDataTypeSize( eOperDataType ) ) { eOperDataType = aeSupportedTypes[i]; } } } /* -------------------------------------------------------------------- */ /* Allocate the buffer of data into which our imagery will be */ /* read, with the extra edge pixels as well. This will be the */ /* source data fed into the filter. */ /* -------------------------------------------------------------------- */ int nPixelOffset, nLineOffset; int nExtraXSize = nOutXSize + 2 * nExtraEdgePixels; int nExtraYSize = nOutYSize + 2 * nExtraEdgePixels; GByte *pabyWorkData; // FIXME? : risk of multiplication overflow pabyWorkData = (GByte *) VSICalloc( nExtraXSize * nExtraYSize, (GDALGetDataTypeSize(eOperDataType) / 8) ); if( pabyWorkData == NULL ) { CPLError( CE_Failure, CPLE_OutOfMemory, "Work buffer allocation failed." ); return CE_Failure; } nPixelOffset = GDALGetDataTypeSize( eOperDataType ) / 8; nLineOffset = nPixelOffset * nExtraXSize; /* -------------------------------------------------------------------- */ /* Allocate the output buffer if the passed in output buffer is */ /* not of the same type as our working format, or if the passed */ /* in buffer has an unusual organization. */ /* -------------------------------------------------------------------- */ GByte *pabyOutData; if( nPixelSpace != nPixelOffset || nLineSpace != nLineOffset || eOperDataType != eBufType ) { pabyOutData = (GByte *) VSIMalloc3(nOutXSize, nOutYSize, nPixelOffset ); if( pabyOutData == NULL ) { CPLError( CE_Failure, CPLE_OutOfMemory, "Work buffer allocation failed." ); return CE_Failure; } } else pabyOutData = (GByte *) pData; /* -------------------------------------------------------------------- */ /* Figure out the extended window that we want to load. Note */ /* that we keep track of the file window as well as the amount */ /* we will need to edge fill past the edge of the source dataset. */ /* -------------------------------------------------------------------- */ int nTopFill=0, nLeftFill=0, nRightFill=0, nBottomFill=0; int nFileXOff, nFileYOff, nFileXSize, nFileYSize; nFileXOff = nReqXOff - nExtraEdgePixels; nFileYOff = nReqYOff - nExtraEdgePixels; nFileXSize = nExtraXSize; nFileYSize = nExtraYSize; if( nFileXOff < 0 ) { nLeftFill = -nFileXOff; nFileXOff = 0; nFileXSize -= nLeftFill; } if( nFileYOff < 0 ) { nTopFill = -nFileYOff; nFileYOff = 0; nFileYSize -= nTopFill; } if( nFileXOff + nFileXSize > poRasterBand->GetXSize() ) { nRightFill = nFileXOff + nFileXSize - poRasterBand->GetXSize(); nFileXSize -= nRightFill; } if( nFileYOff + nFileYSize > poRasterBand->GetYSize() ) { nBottomFill = nFileYOff + nFileYSize - poRasterBand->GetYSize(); nFileYSize -= nBottomFill; } /* -------------------------------------------------------------------- */ /* Load the data. */ /* -------------------------------------------------------------------- */ CPLErr eErr; eErr = VRTComplexSource::RasterIOInternal( nFileXOff, nFileYOff, nFileXSize, nFileYSize, pabyWorkData + nLineOffset * nTopFill + nPixelOffset * nLeftFill, nFileXSize, nFileYSize, eOperDataType, nPixelOffset, nLineOffset, psExtraArg ); if( eErr != CE_None ) { if( pabyWorkData != pData ) VSIFree( pabyWorkData ); return eErr; } /* -------------------------------------------------------------------- */ /* Fill in missing areas. Note that we replicate the edge */ /* valid values out. We don't using "mirroring" which might be */ /* more suitable for some times of filters. We also don't mark */ /* these pixels as "nodata" though perhaps we should. */ /* -------------------------------------------------------------------- */ if( nLeftFill != 0 || nRightFill != 0 ) { for( i = nTopFill; i < nExtraYSize - nBottomFill; i++ ) { if( nLeftFill != 0 ) GDALCopyWords( pabyWorkData + nPixelOffset * nLeftFill + i * nLineOffset, eOperDataType, 0, pabyWorkData + i * nLineOffset, eOperDataType, nPixelOffset, nLeftFill ); if( nRightFill != 0 ) GDALCopyWords( pabyWorkData + i * nLineOffset + nPixelOffset * (nExtraXSize - nRightFill - 1), eOperDataType, 0, pabyWorkData + i * nLineOffset + nPixelOffset * (nExtraXSize - nRightFill), eOperDataType, nPixelOffset, nRightFill ); } } for( i = 0; i < nTopFill; i++ ) { memcpy( pabyWorkData + i * nLineOffset, pabyWorkData + nTopFill * nLineOffset, nLineOffset ); } for( i = nExtraYSize - nBottomFill; i < nExtraYSize; i++ ) { memcpy( pabyWorkData + i * nLineOffset, pabyWorkData + (nExtraYSize - nBottomFill - 1) * nLineOffset, nLineOffset ); } /* -------------------------------------------------------------------- */ /* Filter the data. */ /* -------------------------------------------------------------------- */ eErr = FilterData( nOutXSize, nOutYSize, eOperDataType, pabyWorkData, pabyOutData ); VSIFree( pabyWorkData ); if( eErr != CE_None ) { if( pabyOutData != pData ) VSIFree( pabyOutData ); return eErr; } /* -------------------------------------------------------------------- */ /* Copy from work buffer to target buffer. */ /* -------------------------------------------------------------------- */ if( pabyOutData != pData ) { for( i = 0; i < nOutYSize; i++ ) { GDALCopyWords( pabyOutData + i * (nPixelOffset * nOutXSize), eOperDataType, nPixelOffset, ((GByte *) pData) + i * nLineSpace, eBufType, nPixelSpace, nOutXSize ); } VSIFree( pabyOutData ); } return CE_None; }
CPLErr VRTFilteredSource::RasterIO( GDALDataType eBandDataType, int nXOff, int nYOff, int nXSize, int nYSize, void *pData, int nBufXSize, int nBufYSize, GDALDataType eBufType, GSpacing nPixelSpace, GSpacing nLineSpace, GDALRasterIOExtraArg* psExtraArg ) { /* -------------------------------------------------------------------- */ /* For now we don't support filtered access to non-full */ /* resolution requests. Just collect the data directly without */ /* any operator. */ /* -------------------------------------------------------------------- */ if( nBufXSize != nXSize || nBufYSize != nYSize ) { return VRTComplexSource::RasterIO( eBandDataType, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize, nBufYSize, eBufType, nPixelSpace, nLineSpace, psExtraArg ); } // The window we will actually request from the source raster band. double dfReqXOff = 0.0; double dfReqYOff = 0.0; double dfReqXSize = 0.0; double dfReqYSize = 0.0; int nReqXOff = 0; int nReqYOff = 0; int nReqXSize = 0; int nReqYSize = 0; // The window we will actual set _within_ the pData buffer. int nOutXOff = 0; int nOutYOff = 0; int nOutXSize = 0; int nOutYSize = 0; if( !GetSrcDstWindow( nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize, &dfReqXOff, &dfReqYOff, &dfReqXSize, &dfReqYSize, &nReqXOff, &nReqYOff, &nReqXSize, &nReqYSize, &nOutXOff, &nOutYOff, &nOutXSize, &nOutYSize ) ) return CE_None; pData = reinterpret_cast<GByte *>( pData ) + nPixelSpace * nOutXOff + nLineSpace * nOutYOff; /* -------------------------------------------------------------------- */ /* Determine the data type we want to request. We try to match */ /* the source or destination request, and if both those fail we */ /* fallback to the first supported type at least as expressive */ /* as the request. */ /* -------------------------------------------------------------------- */ GDALDataType eOperDataType = GDT_Unknown; if( IsTypeSupported( eBufType ) ) eOperDataType = eBufType; if( eOperDataType == GDT_Unknown && IsTypeSupported( m_poRasterBand->GetRasterDataType() ) ) eOperDataType = m_poRasterBand->GetRasterDataType(); if( eOperDataType == GDT_Unknown ) { for( int i = 0; i < m_nSupportedTypesCount; i++ ) { if( GDALDataTypeUnion( m_aeSupportedTypes[i], eBufType ) == m_aeSupportedTypes[i] ) { eOperDataType = m_aeSupportedTypes[i]; } } } if( eOperDataType == GDT_Unknown ) { eOperDataType = m_aeSupportedTypes[0]; for( int i = 1; i < m_nSupportedTypesCount; i++ ) { if( GDALGetDataTypeSize( m_aeSupportedTypes[i] ) > GDALGetDataTypeSize( eOperDataType ) ) { eOperDataType = m_aeSupportedTypes[i]; } } } /* -------------------------------------------------------------------- */ /* Allocate the buffer of data into which our imagery will be */ /* read, with the extra edge pixels as well. This will be the */ /* source data fed into the filter. */ /* -------------------------------------------------------------------- */ if( nOutXSize > INT_MAX - 2 * m_nExtraEdgePixels || nOutYSize > INT_MAX - 2 * m_nExtraEdgePixels ) { return CE_Failure; } const int nExtraXSize = nOutXSize + 2 * m_nExtraEdgePixels; const int nExtraYSize = nOutYSize + 2 * m_nExtraEdgePixels; GByte *pabyWorkData = static_cast<GByte *>( VSI_MALLOC3_VERBOSE( nExtraXSize, nExtraYSize, GDALGetDataTypeSizeBytes(eOperDataType)) ); if( pabyWorkData == nullptr ) { return CE_Failure; } const GPtrDiff_t nPixelOffset = GDALGetDataTypeSizeBytes( eOperDataType ); const GPtrDiff_t nLineOffset = nPixelOffset * nExtraXSize; memset( pabyWorkData, 0, nLineOffset * nExtraYSize ); /* -------------------------------------------------------------------- */ /* Allocate the output buffer in the same dimensions as the work */ /* buffer. This allows the filter process to write edge pixels */ /* if needed for two-pass (separable) filtering. */ /* -------------------------------------------------------------------- */ GByte *pabyOutData = static_cast<GByte *>( VSI_MALLOC3_VERBOSE( nExtraXSize, nExtraYSize, nPixelOffset ) ); if( pabyOutData == nullptr ) { CPLFree( pabyWorkData ); return CE_Failure; } /* -------------------------------------------------------------------- */ /* Figure out the extended window that we want to load. Note */ /* that we keep track of the file window as well as the amount */ /* we will need to edge fill past the edge of the source dataset. */ /* -------------------------------------------------------------------- */ int nFileXOff = nReqXOff - m_nExtraEdgePixels; int nFileYOff = nReqYOff - m_nExtraEdgePixels; int nFileXSize = nExtraXSize; int nFileYSize = nExtraYSize; int nTopFill = 0; int nLeftFill = 0; int nRightFill = 0; int nBottomFill = 0; if( nFileXOff < 0 ) { nLeftFill = -nFileXOff; nFileXOff = 0; nFileXSize -= nLeftFill; } if( nFileYOff < 0 ) { nTopFill = -nFileYOff; nFileYOff = 0; nFileYSize -= nTopFill; } if( nFileXOff + nFileXSize > m_poRasterBand->GetXSize() ) { nRightFill = nFileXOff + nFileXSize - m_poRasterBand->GetXSize(); nFileXSize -= nRightFill; } if( nFileYOff + nFileYSize > m_poRasterBand->GetYSize() ) { nBottomFill = nFileYOff + nFileYSize - m_poRasterBand->GetYSize(); nFileYSize -= nBottomFill; } /* -------------------------------------------------------------------- */ /* Load the data. */ /* -------------------------------------------------------------------- */ { const bool bIsComplex = CPL_TO_BOOL( GDALDataTypeIsComplex(eOperDataType) ); const CPLErr eErr = VRTComplexSource::RasterIOInternal<float>( nFileXOff, nFileYOff, nFileXSize, nFileYSize, pabyWorkData + nLineOffset * nTopFill + nPixelOffset * nLeftFill, nFileXSize, nFileYSize, eOperDataType, nPixelOffset, nLineOffset, psExtraArg, bIsComplex ? GDT_CFloat32 : GDT_Float32 ); if( eErr != CE_None ) { VSIFree( pabyWorkData ); VSIFree( pabyOutData ); return eErr; } } /* -------------------------------------------------------------------- */ /* Fill in missing areas. Note that we replicate the edge */ /* valid values out. We don't using "mirroring" which might be */ /* more suitable for some times of filters. We also don't mark */ /* these pixels as "nodata" though perhaps we should. */ /* -------------------------------------------------------------------- */ if( nLeftFill != 0 || nRightFill != 0 ) { for( int i = nTopFill; i < nExtraYSize - nBottomFill; i++ ) { if( nLeftFill != 0 ) GDALCopyWords( pabyWorkData + nPixelOffset * nLeftFill + i * nLineOffset, eOperDataType, 0, pabyWorkData + i * nLineOffset, eOperDataType, static_cast<int>(nPixelOffset), nLeftFill ); if( nRightFill != 0 ) GDALCopyWords( pabyWorkData + i * nLineOffset + nPixelOffset * (nExtraXSize - nRightFill - 1), eOperDataType, 0, pabyWorkData + i * nLineOffset + nPixelOffset * (nExtraXSize - nRightFill), eOperDataType, static_cast<int>(nPixelOffset), nRightFill ); } } for( int i = 0; i < nTopFill; i++ ) { memcpy( pabyWorkData + i * nLineOffset, pabyWorkData + nTopFill * nLineOffset, nLineOffset ); } for( int i = nExtraYSize - nBottomFill; i < nExtraYSize; i++ ) { memcpy( pabyWorkData + i * nLineOffset, pabyWorkData + (nExtraYSize - nBottomFill - 1) * nLineOffset, nLineOffset ); } /* -------------------------------------------------------------------- */ /* Filter the data. */ /* -------------------------------------------------------------------- */ const CPLErr eErr = FilterData( nExtraXSize, nExtraYSize, eOperDataType, pabyWorkData, pabyOutData ); VSIFree( pabyWorkData ); if( eErr != CE_None ) { VSIFree( pabyOutData ); return eErr; } /* -------------------------------------------------------------------- */ /* Copy from work buffer to target buffer. */ /* -------------------------------------------------------------------- */ GByte *pabySrcRow = pabyOutData + (nLineOffset + nPixelOffset) * m_nExtraEdgePixels; GByte *pabyDstRow = reinterpret_cast<GByte *>( pData ); for( int i = 0; i < nOutYSize; i++, pabySrcRow += nLineOffset, pabyDstRow += nLineSpace ) { GDALCopyWords( pabySrcRow, eOperDataType, static_cast<int>(nPixelOffset), pabyDstRow, eBufType, static_cast<int>(nPixelSpace), nOutXSize ); } VSIFree( pabyOutData ); return CE_None; }