QgsRasterDataProvider* QgsRasterFileWriter::createPartProvider( const QgsRectangle& extent, int nCols, int iterCols, int iterRows, int iterLeft, int iterTop, const QString& outputUrl, int fileIndex, int nBands, QGis::DataType type, const QgsCoordinateReferenceSystem& crs ) { double mup = extent.width() / nCols; double mapLeft = extent.xMinimum() + iterLeft * mup; double mapRight = mapLeft + mup * iterCols; double mapTop = extent.yMaximum() - iterTop * mup; double mapBottom = mapTop - iterRows * mup; QgsRectangle mapRect( mapLeft, mapBottom, mapRight, mapTop ); QString outputFile = outputUrl + "/" + partFileName( fileIndex ); //geotransform double geoTransform[6]; geoTransform[0] = mapRect.xMinimum(); geoTransform[1] = mup; geoTransform[2] = 0.0; geoTransform[3] = mapRect.yMaximum(); geoTransform[4] = 0.0; geoTransform[5] = -mup; // perhaps we need a separate createOptions for tiles ? QgsRasterDataProvider* destProvider = QgsRasterDataProvider::create( mOutputProviderKey, outputFile, mOutputFormat, nBands, type, iterCols, iterRows, geoTransform, crs, mCreateOptions ); // TODO: return provider and report error return destProvider; }
QgsRasterFileWriter::WriterError QgsRasterFileWriter::writeDataRaster( const QgsRasterPipe* pipe, QgsRasterIterator* iter, int nCols, int nRows, const QgsRectangle& outputExtent, const QgsCoordinateReferenceSystem& crs, QGis::DataType destDataType, QList<bool> destHasNoDataValueList, QList<double> destNoDataValueList, QgsRasterDataProvider* destProvider, QProgressDialog* progressDialog ) { Q_UNUSED( pipe ); Q_UNUSED( destHasNoDataValueList ); QgsDebugMsg( "Entered" ); const QgsRasterInterface* iface = iter->input(); const QgsRasterDataProvider* srcProvider = dynamic_cast<const QgsRasterDataProvider*>( iface->srcInput() ); int nBands = iface->bandCount(); QgsDebugMsg( QString( "nBands = %1" ).arg( nBands ) ); //Get output map units per pixel int iterLeft = 0; int iterTop = 0; int iterCols = 0; int iterRows = 0; QList<QgsRasterBlock*> blockList; for ( int i = 1; i <= nBands; ++i ) { iter->startRasterRead( i, nCols, nRows, outputExtent ); blockList.push_back( 0 ); if ( destProvider ) // no tiles { destProvider->setNoDataValue( i, destNoDataValueList.value( i - 1 ) ); } } int nParts = 0; int fileIndex = 0; if ( progressDialog ) { int nPartsX = nCols / iter->maximumTileWidth() + 1; int nPartsY = nRows / iter->maximumTileHeight() + 1; nParts = nPartsX * nPartsY; progressDialog->setMaximum( nParts ); progressDialog->show(); progressDialog->setLabelText( QObject::tr( "Reading raster part %1 of %2" ).arg( fileIndex + 1 ).arg( nParts ) ); } // hmm why is there a for(;;) here .. // not good coding practice IMHO, it might be better to use [ for() and break ] or [ while (test) ] for ( ;; ) { for ( int i = 1; i <= nBands; ++i ) { if ( !iter->readNextRasterPart( i, iterCols, iterRows, &( blockList[i - 1] ), iterLeft, iterTop ) ) { // No more parts, create VRT and return if ( mTiledMode ) { QString vrtFilePath( mOutputUrl + "/" + vrtFileName() ); writeVRT( vrtFilePath ); if ( mBuildPyramidsFlag == QgsRaster::PyramidsFlagYes ) { buildPyramids( vrtFilePath ); } } else { if ( mBuildPyramidsFlag == QgsRaster::PyramidsFlagYes ) { buildPyramids( mOutputUrl ); } } QgsDebugMsg( "Done" ); return NoError; //reached last tile, bail out } // TODO: verify if NoDataConflict happened, to do that we need the whole pipe or nuller interface } if ( progressDialog && fileIndex < ( nParts - 1 ) ) { progressDialog->setValue( fileIndex + 1 ); progressDialog->setLabelText( QObject::tr( "Reading raster part %1 of %2" ).arg( fileIndex + 2 ).arg( nParts ) ); QCoreApplication::processEvents( QEventLoop::AllEvents, 1000 ); if ( progressDialog->wasCanceled() ) { for ( int i = 0; i < nBands; ++i ) { delete blockList[i]; } break; } } // It may happen that internal data type (dataType) is wider than destDataType QList<QgsRasterBlock*> destBlockList; for ( int i = 1; i <= nBands; ++i ) { if ( srcProvider->dataType( i ) == destDataType ) { destBlockList.push_back( blockList[i-1] ); } else { // TODO: this conversion should go to QgsRasterDataProvider::write with additional input data type param blockList[i-1]->convert( destDataType ); destBlockList.push_back( blockList[i-1] ); } blockList[i-1] = 0; } if ( mTiledMode ) //write to file { QgsRasterDataProvider* partDestProvider = createPartProvider( outputExtent, nCols, iterCols, iterRows, iterLeft, iterTop, mOutputUrl, fileIndex, nBands, destDataType, crs ); if ( partDestProvider ) { //write data to output file. todo: loop over the data list for ( int i = 1; i <= nBands; ++i ) { partDestProvider->setNoDataValue( i, destNoDataValueList.value( i - 1 ) ); partDestProvider->write( destBlockList[i - 1]->bits( 0 ), i, iterCols, iterRows, 0, 0 ); delete destBlockList[i - 1]; addToVRT( partFileName( fileIndex ), i, iterCols, iterRows, iterLeft, iterTop ); } delete partDestProvider; } } else if ( destProvider ) { //loop over data for ( int i = 1; i <= nBands; ++i ) { destProvider->write( destBlockList[i - 1]->bits( 0 ), i, iterCols, iterRows, iterLeft, iterTop ); delete destBlockList[i - 1]; } } ++fileIndex; } QgsDebugMsg( "Done" ); return NoError; }
QgsRasterFileWriter::WriterError QgsRasterFileWriter::writeImageRaster( QgsRasterIterator* iter, int nCols, int nRows, const QgsRectangle& outputExtent, const QgsCoordinateReferenceSystem& crs, QProgressDialog* progressDialog ) { QgsDebugMsg( "Entered" ); if ( !iter ) { return SourceProviderError; } const QgsRasterInterface* iface = iter->input(); QGis::DataType inputDataType = iface->dataType( 1 ); if ( !iface || ( inputDataType != QGis::ARGB32 && inputDataType != QGis::ARGB32_Premultiplied ) ) { return SourceProviderError; } iter->setMaximumTileWidth( mMaxTileWidth ); iter->setMaximumTileHeight( mMaxTileHeight ); void* redData = qgsMalloc( mMaxTileWidth * mMaxTileHeight ); void* greenData = qgsMalloc( mMaxTileWidth * mMaxTileHeight ); void* blueData = qgsMalloc( mMaxTileWidth * mMaxTileHeight ); void* alphaData = qgsMalloc( mMaxTileWidth * mMaxTileHeight ); QgsRectangle mapRect; int iterLeft = 0, iterTop = 0, iterCols = 0, iterRows = 0; int fileIndex = 0; //create destProvider for whole dataset here QgsRasterDataProvider* destProvider = 0; double pixelSize; double geoTransform[6]; globalOutputParameters( outputExtent, nCols, nRows, geoTransform, pixelSize ); destProvider = initOutput( nCols, nRows, crs, geoTransform, 4, QGis::Byte ); iter->startRasterRead( 1, nCols, nRows, outputExtent ); int nParts = 0; if ( progressDialog ) { int nPartsX = nCols / iter->maximumTileWidth() + 1; int nPartsY = nRows / iter->maximumTileHeight() + 1; nParts = nPartsX * nPartsY; progressDialog->setMaximum( nParts ); progressDialog->show(); progressDialog->setLabelText( QObject::tr( "Reading raster part %1 of %2" ).arg( fileIndex + 1 ).arg( nParts ) ); } QgsRasterBlock *inputBlock = 0; while ( iter->readNextRasterPart( 1, iterCols, iterRows, &inputBlock, iterLeft, iterTop ) ) { if ( !inputBlock ) { continue; } if ( progressDialog && fileIndex < ( nParts - 1 ) ) { progressDialog->setValue( fileIndex + 1 ); progressDialog->setLabelText( QObject::tr( "Reading raster part %1 of %2" ).arg( fileIndex + 2 ).arg( nParts ) ); QCoreApplication::processEvents( QEventLoop::AllEvents, 1000 ); if ( progressDialog->wasCanceled() ) { delete inputBlock; break; } } //fill into red/green/blue/alpha channels qgssize nPixels = ( qgssize )iterCols * iterRows; // TODO: should be char not int? we are then copying 1 byte int red = 0; int green = 0; int blue = 0; int alpha = 255; for ( qgssize i = 0; i < nPixels; ++i ) { QRgb c = inputBlock->color( i ); alpha = qAlpha( c ); red = qRed( c ); green = qGreen( c ); blue = qBlue( c ); if ( inputDataType == QGis::ARGB32_Premultiplied ) { double a = alpha / 255.; QgsDebugMsgLevel( QString( "red = %1 green = %2 blue = %3 alpha = %4 p = %5 a = %6" ).arg( red ).arg( green ).arg( blue ).arg( alpha ).arg(( int )c, 0, 16 ).arg( a ), 5 ); red /= a; green /= a; blue /= a; } memcpy(( char* )redData + i, &red, 1 ); memcpy(( char* )greenData + i, &green, 1 ); memcpy(( char* )blueData + i, &blue, 1 ); memcpy(( char* )alphaData + i, &alpha, 1 ); } delete inputBlock; //create output file if ( mTiledMode ) { //delete destProvider; QgsRasterDataProvider* partDestProvider = createPartProvider( outputExtent, nCols, iterCols, iterRows, iterLeft, iterTop, mOutputUrl, fileIndex, 4, QGis::Byte, crs ); if ( partDestProvider ) { //write data to output file partDestProvider->write( redData, 1, iterCols, iterRows, 0, 0 ); partDestProvider->write( greenData, 2, iterCols, iterRows, 0, 0 ); partDestProvider->write( blueData, 3, iterCols, iterRows, 0, 0 ); partDestProvider->write( alphaData, 4, iterCols, iterRows, 0, 0 ); addToVRT( partFileName( fileIndex ), 1, iterCols, iterRows, iterLeft, iterTop ); addToVRT( partFileName( fileIndex ), 2, iterCols, iterRows, iterLeft, iterTop ); addToVRT( partFileName( fileIndex ), 3, iterCols, iterRows, iterLeft, iterTop ); addToVRT( partFileName( fileIndex ), 4, iterCols, iterRows, iterLeft, iterTop ); delete partDestProvider; } } else if ( destProvider ) { destProvider->write( redData, 1, iterCols, iterRows, iterLeft, iterTop ); destProvider->write( greenData, 2, iterCols, iterRows, iterLeft, iterTop ); destProvider->write( blueData, 3, iterCols, iterRows, iterLeft, iterTop ); destProvider->write( alphaData, 4, iterCols, iterRows, iterLeft, iterTop ); } ++fileIndex; } if ( destProvider ) delete destProvider; qgsFree( redData ); qgsFree( greenData ); qgsFree( blueData ); qgsFree( alphaData ); if ( progressDialog ) { progressDialog->setValue( progressDialog->maximum() ); } if ( mTiledMode ) { QString vrtFilePath( mOutputUrl + "/" + vrtFileName() ); writeVRT( vrtFilePath ); if ( mBuildPyramidsFlag == QgsRaster::PyramidsFlagYes ) { buildPyramids( vrtFilePath ); } } else { if ( mBuildPyramidsFlag == QgsRaster::PyramidsFlagYes ) { buildPyramids( mOutputUrl ); } } return NoError; }
QgsRasterFileWriter::WriterError QgsRasterFileWriter::writeImageRaster( QgsRasterIterator *iter, int nCols, int nRows, const QgsRectangle &outputExtent, const QgsCoordinateReferenceSystem &crs, QgsRasterBlockFeedback *feedback ) { QgsDebugMsgLevel( "Entered", 4 ); if ( !iter ) { return SourceProviderError; } const QgsRasterInterface *iface = iter->input(); if ( !iface ) return SourceProviderError; Qgis::DataType inputDataType = iface->dataType( 1 ); if ( inputDataType != Qgis::ARGB32 && inputDataType != Qgis::ARGB32_Premultiplied ) { return SourceProviderError; } iter->setMaximumTileWidth( mMaxTileWidth ); iter->setMaximumTileHeight( mMaxTileHeight ); void *redData = qgsMalloc( mMaxTileWidth * mMaxTileHeight ); void *greenData = qgsMalloc( mMaxTileWidth * mMaxTileHeight ); void *blueData = qgsMalloc( mMaxTileWidth * mMaxTileHeight ); void *alphaData = qgsMalloc( mMaxTileWidth * mMaxTileHeight ); int iterLeft = 0, iterTop = 0, iterCols = 0, iterRows = 0; int fileIndex = 0; //create destProvider for whole dataset here double pixelSize; double geoTransform[6]; globalOutputParameters( outputExtent, nCols, nRows, geoTransform, pixelSize ); std::unique_ptr< QgsRasterDataProvider > destProvider( initOutput( nCols, nRows, crs, geoTransform, 4, Qgis::Byte ) ); iter->startRasterRead( 1, nCols, nRows, outputExtent, feedback ); int nParts = 0; if ( feedback ) { int nPartsX = nCols / iter->maximumTileWidth() + 1; int nPartsY = nRows / iter->maximumTileHeight() + 1; nParts = nPartsX * nPartsY; } std::unique_ptr< QgsRasterBlock > inputBlock; while ( iter->readNextRasterPart( 1, iterCols, iterRows, inputBlock, iterLeft, iterTop ) ) { if ( !inputBlock ) { continue; } if ( feedback && fileIndex < ( nParts - 1 ) ) { feedback->setProgress( 100.0 * fileIndex / static_cast< double >( nParts ) ); if ( feedback->isCanceled() ) { break; } } //fill into red/green/blue/alpha channels qgssize nPixels = static_cast< qgssize >( iterCols ) * iterRows; // TODO: should be char not int? we are then copying 1 byte int red = 0; int green = 0; int blue = 0; int alpha = 255; for ( qgssize i = 0; i < nPixels; ++i ) { QRgb c = inputBlock->color( i ); alpha = qAlpha( c ); red = qRed( c ); green = qGreen( c ); blue = qBlue( c ); if ( inputDataType == Qgis::ARGB32_Premultiplied ) { double a = alpha / 255.; QgsDebugMsgLevel( QString( "red = %1 green = %2 blue = %3 alpha = %4 p = %5 a = %6" ).arg( red ).arg( green ).arg( blue ).arg( alpha ).arg( static_cast< int >( c ), 0, 16 ).arg( a ), 5 ); red /= a; green /= a; blue /= a; } memcpy( reinterpret_cast< char * >( redData ) + i, &red, 1 ); memcpy( reinterpret_cast< char * >( greenData ) + i, &green, 1 ); memcpy( reinterpret_cast< char * >( blueData ) + i, &blue, 1 ); memcpy( reinterpret_cast< char * >( alphaData ) + i, &alpha, 1 ); } //create output file if ( mTiledMode ) { //delete destProvider; std::unique_ptr< QgsRasterDataProvider > partDestProvider( createPartProvider( outputExtent, nCols, iterCols, iterRows, iterLeft, iterTop, mOutputUrl, fileIndex, 4, Qgis::Byte, crs ) ); if ( partDestProvider ) { //write data to output file partDestProvider->write( redData, 1, iterCols, iterRows, 0, 0 ); partDestProvider->write( greenData, 2, iterCols, iterRows, 0, 0 ); partDestProvider->write( blueData, 3, iterCols, iterRows, 0, 0 ); partDestProvider->write( alphaData, 4, iterCols, iterRows, 0, 0 ); addToVRT( partFileName( fileIndex ), 1, iterCols, iterRows, iterLeft, iterTop ); addToVRT( partFileName( fileIndex ), 2, iterCols, iterRows, iterLeft, iterTop ); addToVRT( partFileName( fileIndex ), 3, iterCols, iterRows, iterLeft, iterTop ); addToVRT( partFileName( fileIndex ), 4, iterCols, iterRows, iterLeft, iterTop ); } } else if ( destProvider ) { destProvider->write( redData, 1, iterCols, iterRows, iterLeft, iterTop ); destProvider->write( greenData, 2, iterCols, iterRows, iterLeft, iterTop ); destProvider->write( blueData, 3, iterCols, iterRows, iterLeft, iterTop ); destProvider->write( alphaData, 4, iterCols, iterRows, iterLeft, iterTop ); } ++fileIndex; } destProvider.reset(); qgsFree( redData ); qgsFree( greenData ); qgsFree( blueData ); qgsFree( alphaData ); if ( feedback ) { feedback->setProgress( 100.0 ); } if ( mTiledMode ) { QString vrtFilePath( mOutputUrl + '/' + vrtFileName() ); writeVRT( vrtFilePath ); if ( mBuildPyramidsFlag == QgsRaster::PyramidsFlagYes ) { buildPyramids( vrtFilePath ); } } else { if ( mBuildPyramidsFlag == QgsRaster::PyramidsFlagYes ) { buildPyramids( mOutputUrl ); } } return ( feedback && feedback->isCanceled() ) ? WriteCanceled : NoError; }