24 #include <QCoreApplication>
25 #include <QProgressDialog>
26 #include <QTextStream>
27 #include <QMessageBox>
30 mMode( Raw ), mOutputUrl( outputUrl ), mOutputProviderKey(
"gdal" ), mOutputFormat(
"GTiff" ),
31 mTiledMode( false ), mMaxTileWidth( 500 ), mMaxTileHeight( 500 ),
32 mBuildPyramidsFlag(
QgsRaster::PyramidsFlagNo ),
33 mPyramidsFormat(
QgsRaster::PyramidsGTiff ),
34 mProgressDialog( 0 ), mPipe( 0 ), mInput( 0 )
77 QgsDebugMsg( QString(
"reading from %1" ).arg(
typeid( *iface ).name() ) );
94 if ( !fileInfo.exists() )
96 QDir dir = fileInfo.dir();
97 if ( !dir.mkdir( fileInfo.fileName() ) )
99 QgsDebugMsg(
"Cannot create output VRT directory " + fileInfo.fileName() +
" in " + dir.absolutePath() );
154 for (
int i = 2; i <= nBands; ++i )
166 QList<bool> destHasNoDataValueList;
167 QList<double> destNoDataValueList;
168 QList<QGis::DataType> destDataTypeList;
169 for (
int bandNo = 1; bandNo <= nBands; bandNo++ )
174 bool destHasNoDataValue =
false;
175 double destNoDataValue = std::numeric_limits<double>::quiet_NaN();
178 QgsDebugMsg( QString(
"srcHasNoDataValue = %1 srcNoDataValue = %2" ).arg( srcHasNoDataValue ).arg( srcProvider->
srcNoDataValue( bandNo ) ) );
179 if ( srcHasNoDataValue )
184 destHasNoDataValue =
true;
186 else if ( nuller && nuller->
noData( bandNo ).size() > 0 )
189 destNoDataValue = nuller->
noData( bandNo ).value( 0 ).min();
190 destHasNoDataValue =
true;
197 if ( projector && projector->
destCrs() != projector->
srcCrs() )
200 srcExtent = ct.transformBoundingBox( outputExtent );
213 destNoDataValue = typeMinValue;
217 destNoDataValue = typeMaxValue;
224 destHasNoDataValue =
true;
228 if ( nuller && destHasNoDataValue )
233 QgsDebugMsg( QString(
"bandNo = %1 destDataType = %2 destHasNoDataValue = %3 destNoDataValue = %4" ).arg( bandNo ).arg( destDataType ).arg( destHasNoDataValue ).arg( destNoDataValue ) );
234 destDataTypeList.append( destDataType );
235 destHasNoDataValueList.append( destHasNoDataValue );
236 destNoDataValueList.append( destNoDataValue );
241 for (
int i = 1; i < nBands; i++ )
243 if ( destDataTypeList.value( i ) > destDataType )
245 destDataType = destDataTypeList.value( i );
253 double geoTransform[6];
257 destProvider =
initOutput( nCols, nRows, crs, geoTransform, nBands, destDataType, destHasNoDataValueList, destNoDataValueList );
259 WriterError error =
writeDataRaster( pipe, iter, nCols, nRows, outputExtent, crs, destDataType, destHasNoDataValueList, destNoDataValueList, destProvider, progressDialog );
276 for (
int i = 0; i < nBands; i++ )
278 double destNoDataValue;
280 destDataTypeList.replace( i, destDataType );
281 destNoDataValueList.replace( i, destNoDataValue );
283 destDataType = destDataTypeList.value( 0 );
286 destProvider =
initOutput( nCols, nRows, crs, geoTransform, nBands, destDataType , destHasNoDataValueList, destNoDataValueList );
287 error =
writeDataRaster( pipe, iter, nCols, nRows, outputExtent, crs, destDataType, destHasNoDataValueList, destNoDataValueList, destProvider, progressDialog );
299 int nCols,
int nRows,
303 QList<bool> destHasNoDataValueList,
304 QList<double> destNoDataValueList,
306 QProgressDialog* progressDialog )
309 Q_UNUSED( destHasNoDataValueList );
315 QgsDebugMsg( QString(
"nBands = %1" ).arg( nBands ) );
323 QList<QgsRasterBlock*> blockList;
324 for (
int i = 1; i <= nBands; ++i )
327 blockList.push_back( 0 );
330 destProvider->
setNoDataValue( i, destNoDataValueList.value( i - 1 ) );
336 if ( progressDialog )
340 nParts = nPartsX * nPartsY;
341 progressDialog->setMaximum( nParts );
342 progressDialog->show();
343 progressDialog->setLabelText(
QObject::tr(
"Reading raster part %1 of %2" ).arg( fileIndex + 1 ).arg( nParts ) );
350 for (
int i = 1; i <= nBands; ++i )
352 if ( !iter->
readNextRasterPart( i, iterCols, iterRows, &( blockList[i - 1] ), iterLeft, iterTop ) )
378 if ( progressDialog && fileIndex < ( nParts - 1 ) )
380 progressDialog->setValue( fileIndex + 1 );
381 progressDialog->setLabelText(
QObject::tr(
"Reading raster part %1 of %2" ).arg( fileIndex + 2 ).arg( nParts ) );
382 QCoreApplication::processEvents( QEventLoop::AllEvents, 1000 );
383 if ( progressDialog->wasCanceled() )
385 for (
int i = 0; i < nBands; ++i )
394 QList<QgsRasterBlock*> destBlockList;
395 for (
int i = 1; i <= nBands; ++i )
397 if ( srcProvider->
dataType( i ) == destDataType )
399 destBlockList.push_back( blockList[i-1] );
404 blockList[i-1]->convert( destDataType );
405 destBlockList.push_back( blockList[i-1] );
413 nCols, iterCols, iterRows,
415 fileIndex, nBands, destDataType, crs );
417 if ( partDestProvider )
420 for (
int i = 1; i <= nBands; ++i )
422 partDestProvider->
setNoDataValue( i, destNoDataValueList.value( i - 1 ) );
423 partDestProvider->
write( destBlockList[i - 1]->bits( 0 ), i, iterCols, iterRows, 0, 0 );
424 delete destBlockList[i - 1];
427 delete partDestProvider;
430 else if ( destProvider )
433 for (
int i = 1; i <= nBands; ++i )
435 destProvider->
write( destBlockList[i - 1]->bits( 0 ), i, iterCols, iterRows, iterLeft, iterTop );
436 delete destBlockList[i - 1];
471 int iterLeft = 0, iterTop = 0, iterCols = 0, iterRows = 0;
477 double geoTransform[6];
485 if ( progressDialog )
489 nParts = nPartsX * nPartsY;
490 progressDialog->setMaximum( nParts );
491 progressDialog->show();
492 progressDialog->setLabelText(
QObject::tr(
"Reading raster part %1 of %2" ).arg( fileIndex + 1 ).arg( nParts ) );
496 while ( iter->
readNextRasterPart( 1, iterCols, iterRows, &inputBlock, iterLeft, iterTop ) )
498 if ( iterCols <= 5 || iterRows <= 5 )
504 if ( progressDialog && fileIndex < ( nParts - 1 ) )
506 progressDialog->
setValue( fileIndex + 1 );
507 progressDialog->setLabelText(
QObject::tr(
"Reading raster part %1 of %2" ).arg( fileIndex + 2 ).arg( nParts ) );
508 QCoreApplication::processEvents( QEventLoop::AllEvents, 1000 );
509 if ( progressDialog->wasCanceled() )
517 size_t nPixels = ( size_t )iterCols * iterRows;
523 for (
size_t i = 0; i < nPixels; ++i )
525 QRgb c = inputBlock->
color( i );
527 red = qRed( c ); green = qGreen( c ); blue = qBlue( c );
531 double a = alpha / 255.;
532 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 );
537 memcpy((
char* )redData + i, &red, 1 );
538 memcpy((
char* )greenData + i, &green, 1 );
539 memcpy((
char* )blueData + i, &blue, 1 );
540 memcpy((
char* )alphaData + i, &alpha, 1 );
549 nCols, iterCols, iterRows,
553 if ( partDestProvider )
556 partDestProvider->
write( redData, 1, iterCols, iterRows, 0, 0 );
557 partDestProvider->
write( greenData, 2, iterCols, iterRows, 0, 0 );
558 partDestProvider->
write( blueData, 3, iterCols, iterRows, 0, 0 );
559 partDestProvider->
write( alphaData, 4, iterCols, iterRows, 0, 0 );
565 delete partDestProvider;
568 else if ( destProvider )
570 destProvider->
write( redData, 1, iterCols, iterRows, iterLeft, iterTop );
571 destProvider->
write( greenData, 2, iterCols, iterRows, iterLeft, iterTop );
572 destProvider->
write( blueData, 3, iterCols, iterRows, iterLeft, iterTop );
573 destProvider->
write( alphaData, 4, iterCols, iterRows, iterLeft, iterTop );
584 if ( progressDialog )
586 progressDialog->setValue( progressDialog->maximum() );
610 QDomElement bandElem =
mVRTBands.value( band - 1 );
612 QDomElement simpleSourceElem =
mVRTDocument.createElement(
"SimpleSource" );
615 QDomElement sourceFilenameElem =
mVRTDocument.createElement(
"SourceFilename" );
616 sourceFilenameElem.setAttribute(
"relativeToVRT",
"1" );
617 QDomText sourceFilenameText =
mVRTDocument.createTextNode( filename );
618 sourceFilenameElem.appendChild( sourceFilenameText );
619 simpleSourceElem.appendChild( sourceFilenameElem );
622 QDomElement sourceBandElem =
mVRTDocument.createElement(
"SourceBand" );
623 QDomText sourceBandText =
mVRTDocument.createTextNode( QString::number( band ) );
624 sourceBandElem.appendChild( sourceBandText );
625 simpleSourceElem.appendChild( sourceBandElem );
628 QDomElement sourcePropertiesElem =
mVRTDocument.createElement(
"SourceProperties" );
629 sourcePropertiesElem.setAttribute(
"RasterXSize", xSize );
630 sourcePropertiesElem.setAttribute(
"RasterYSize", ySize );
631 sourcePropertiesElem.setAttribute(
"BlockXSize", xSize );
632 sourcePropertiesElem.setAttribute(
"BlockYSize", ySize );
633 sourcePropertiesElem.setAttribute(
"DataType",
"Byte" );
634 simpleSourceElem.appendChild( sourcePropertiesElem );
637 QDomElement srcRectElem =
mVRTDocument.createElement(
"SrcRect" );
638 srcRectElem.setAttribute(
"xOff",
"0" );
639 srcRectElem.setAttribute(
"yOff",
"0" );
640 srcRectElem.setAttribute(
"xSize", xSize );
641 srcRectElem.setAttribute(
"ySize", ySize );
642 simpleSourceElem.appendChild( srcRectElem );
645 QDomElement dstRectElem =
mVRTDocument.createElement(
"DstRect" );
646 dstRectElem.setAttribute(
"xOff", xOffset );
647 dstRectElem.setAttribute(
"yOff", yOffset );
648 dstRectElem.setAttribute(
"xSize", xSize );
649 dstRectElem.setAttribute(
"ySize", ySize );
650 simpleSourceElem.appendChild( dstRectElem );
652 bandElem.appendChild( simpleSourceElem );
658 GDALDatasetH dataSet;
660 dataSet = GDALOpen( filename.toLocal8Bit().data(), GA_Update );
671 overviewList[3] = 16;
672 overviewList[4] = 32;
673 overviewList[5] = 64;
684 GDALBuildOverviews( dataSet,
"AVERAGE", 6, overviewList, 0, 0, 0, 0 );
701 QList< QgsRasterPyramid> myPyramidList;
704 for (
int myCounterInt = 0; myCounterInt < myPyramidList.count(); myCounterInt++ )
706 myPyramidList[myCounterInt].build =
true;
718 QString title, message;
719 if ( res ==
"ERROR_WRITE_ACCESS" )
721 title =
QObject::tr(
"Building pyramids failed - write access denied" );
722 message =
QObject::tr(
"Write access denied. Adjust the file permissions and try again." );
724 else if ( res ==
"ERROR_WRITE_FORMAT" )
726 title =
QObject::tr(
"Building pyramids failed." );
727 message =
QObject::tr(
"The file was not writable. Some formats do not "
728 "support pyramid overviews. Consult the GDAL documentation if in doubt." );
730 else if ( res ==
"FAILED_NOT_SUPPORTED" )
732 title =
QObject::tr(
"Building pyramids failed." );
733 message =
QObject::tr(
"Building pyramid overviews is not supported on this type of raster." );
735 else if ( res ==
"ERROR_JPEG_COMPRESSION" )
737 title =
QObject::tr(
"Building pyramids failed." );
738 message =
QObject::tr(
"Building internal pyramid overviews is not supported on raster layers with JPEG compression and your current libtiff library." );
740 else if ( res ==
"ERROR_VIRTUAL" )
742 title =
QObject::tr(
"Building pyramids failed." );
743 message =
QObject::tr(
"Building pyramid overviews is not supported on this type of raster." );
745 QMessageBox::warning( 0, title, message );
752 int QgsRasterFileWriter::pyramidsProgress(
double dfComplete,
const char *pszMessage,
void* pData )
754 Q_UNUSED( pszMessage );
755 GDALTermProgress( dfComplete, 0, 0 );
756 QProgressDialog* progressDialog =
static_cast<QProgressDialog*
>( pData );
757 if ( pData && progressDialog->wasCanceled() )
764 progressDialog->setRange( 0, 100 );
765 progressDialog->setValue( dfComplete * 100 );
774 QDomElement VRTDatasetElem =
mVRTDocument.createElement(
"VRTDataset" );
777 VRTDatasetElem.setAttribute(
"rasterXSize", xSize );
778 VRTDatasetElem.setAttribute(
"rasterYSize", ySize );
782 QDomElement SRSElem =
mVRTDocument.createElement(
"SRS" );
784 SRSElem.appendChild( crsText );
785 VRTDatasetElem.appendChild( SRSElem );
790 QDomElement geoTransformElem =
mVRTDocument.createElement(
"GeoTransform" );
791 QString geoTransformString = QString::number( geoTransform[0] ) +
", " + QString::number( geoTransform[1] ) +
", " + QString::number( geoTransform[2] ) +
792 ", " + QString::number( geoTransform[3] ) +
", " + QString::number( geoTransform[4] ) +
", " + QString::number( geoTransform[5] );
793 QDomText geoTransformText =
mVRTDocument.createTextNode( geoTransformString );
794 geoTransformElem.appendChild( geoTransformText );
795 VRTDatasetElem.appendChild( geoTransformElem );
808 QStringList colorInterp;
809 colorInterp <<
"Red" <<
"Green" <<
"Blue" <<
"Alpha";
811 QMap<QGis::DataType, QString> dataTypes;
823 for (
int i = 1; i <= nBands; i++ )
825 QDomElement VRTBand =
mVRTDocument.createElement(
"VRTRasterBand" );
827 VRTBand.setAttribute(
"band", QString::number( i ) );
828 QString dataType = dataTypes.value( type );
829 VRTBand.setAttribute(
"dataType", dataType );
833 VRTBand.setAttribute(
"dataType",
"Byte" );
834 QDomElement colorInterpElement =
mVRTDocument.createElement(
"ColorInterp" );
835 QDomText interpText =
mVRTDocument.createTextNode( colorInterp.value( i - 1 ) );
836 colorInterpElement.appendChild( interpText );
837 VRTBand.appendChild( colorInterpElement );
840 if ( !destHasNoDataValueList.isEmpty() && destHasNoDataValueList.value( i - 1 ) )
842 VRTBand.setAttribute(
"NoDataValue", QString::number( destNoDataValueList.value( i - 1 ) ) );
846 VRTDatasetElem.appendChild( VRTBand );
852 QFile outputFile( file );
853 if ( ! outputFile.open( QIODevice::WriteOnly | QIODevice::Truncate ) )
858 QTextStream outStream( &outputFile );
864 int iterRows,
int iterLeft,
int iterTop,
const QString& outputUrl,
int fileIndex,
int nBands,
QGis::DataType type,
867 double mup = extent.
width() / nCols;
868 double mapLeft = extent.
xMinimum() + iterLeft * mup;
869 double mapRight = mapLeft + mup * iterCols;
870 double mapTop = extent.
yMaximum() - iterTop * mup;
871 double mapBottom = mapTop - iterRows * mup;
872 QgsRectangle mapRect( mapLeft, mapBottom, mapRight, mapTop );
874 QString outputFile = outputUrl +
"/" +
partFileName( fileIndex );
877 double geoTransform[6];
878 geoTransform[0] = mapRect.
xMinimum();
879 geoTransform[1] = mup;
880 geoTransform[2] = 0.0;
881 geoTransform[3] = mapRect.
yMaximum();
882 geoTransform[4] = 0.0;
883 geoTransform[5] = -mup;
895 QList<bool> destHasNoDataValueList, QList<double> destNoDataValueList )
899 createVRT( nCols, nRows, crs, geoTransform, type, destHasNoDataValueList, destNoDataValueList );
923 double* geoTransform,
double& pixelSize )
925 pixelSize = extent.
width() / nCols;
930 nRows = ( double )nCols / extent.
width() * extent.
height() + 0.5;
932 geoTransform[0] = extent.
xMinimum();
933 geoTransform[1] = pixelSize;
934 geoTransform[2] = 0.0;
935 geoTransform[3] = extent.
yMaximum();
936 geoTransform[4] = 0.0;
937 geoTransform[5] = -( extent.
height() / nRows );
944 return QString(
"%1.%2.tif" ).arg( outputInfo.fileName() ).arg( fileIndex );
950 return QString(
"%1.vrt" ).arg( outputInfo.fileName() );