30 #include <QCoreApplication>
31 #include <QProgressDialog>
32 #include <QTextStream>
33 #include <QMessageBox>
34 #include <QRegularExpression>
39 #include <cpl_string.h>
48 double geoTransform[6];
49 globalOutputParameters( extent, width, height, geoTransform, pixelSize );
51 return initOutput( width, height,
crs, geoTransform, 1, dataType, QList<bool>(), QList<double>() );
60 double geoTransform[6];
61 globalOutputParameters( extent, width, height, geoTransform, pixelSize );
63 return initOutput( width, height,
crs, geoTransform, nBands, dataType, QList<bool>(), QList<double>() );
67 : mOutputUrl( outputUrl )
72 QgsRasterFileWriter::QgsRasterFileWriter()
114 QgsDebugMsgLevel( QStringLiteral(
"reading from %1" ).arg(
typeid( *iface ).name() ), 4 );
118 QgsDebugMsg( QStringLiteral(
"iface->srcInput() == 0" ) );
123 QgsDebugMsgLevel( QStringLiteral(
"srcInput = %1" ).arg(
typeid( srcInput ).name() ), 4 );
126 mFeedback = feedback;
133 const QFileInfo fileInfo( mOutputUrl );
134 if ( !fileInfo.exists() )
136 const QDir dir = fileInfo.dir();
137 if ( !dir.mkdir( fileInfo.fileName() ) )
139 QgsDebugMsg(
"Cannot create output VRT directory " + fileInfo.fileName() +
" in " + dir.absolutePath() );
146 QFile pyramidFile( mOutputUrl + ( mTiledMode ?
".vrt.ovr" :
".ovr" ) );
147 if ( pyramidFile.exists() )
148 pyramidFile.remove();
149 pyramidFile.setFileName( mOutputUrl + ( mTiledMode ?
".vrt.rrd" :
".rrd" ) );
150 if ( pyramidFile.exists() )
151 pyramidFile.remove();
153 if ( mMode ==
Image )
155 const WriterError e = writeImageRaster( &iter, nCols, nRows, outputExtent,
crs, feedback );
160 const WriterError e = writeDataRaster( pipe, &iter, nCols, nRows, outputExtent,
crs, transformContext, feedback );
183 QgsDebugMsg( QStringLiteral(
"Cannot get source data provider" ) );
200 for (
int i = 2; i <= nBands; ++i )
212 QList<bool> destHasNoDataValueList;
213 QList<double> destNoDataValueList;
214 QList<Qgis::DataType> destDataTypeList;
215 destDataTypeList.reserve( nBands );
216 destHasNoDataValueList.reserve( nBands );
217 destNoDataValueList.reserve( nBands );
219 const bool isGpkgOutput = mOutputProviderKey ==
"gdal" &&
220 mOutputFormat.compare( QLatin1String(
"gpkg" ), Qt::CaseInsensitive ) == 0;
222 double geoTransform[6];
223 globalOutputParameters( outputExtent, nCols, nRows, geoTransform, pixelSize );
224 const auto srcProviderExtent( srcProvider->
extent() );
226 for (
int bandNo = 1; bandNo <= nBands; bandNo++ )
231 bool destHasNoDataValue =
false;
232 double destNoDataValue = std::numeric_limits<double>::quiet_NaN();
237 if ( srcHasNoDataValue )
242 destHasNoDataValue =
true;
244 else if ( nuller && !nuller->
noData( bandNo ).isEmpty() )
247 destNoDataValue = nuller->
noData( bandNo ).value( 0 ).min();
248 destHasNoDataValue =
true;
261 ct.setBallparkTransformsAreAppropriate(
true );
262 outputExtentInSrcCrs = ct.transformBoundingBox( outputExtent );
264 if ( !srcProviderExtent.contains( outputExtentInSrcCrs ) &&
265 ( std::fabs( srcProviderExtent.xMinimum() - outputExtentInSrcCrs.
xMinimum() ) > geoTransform[1] / 2 ||
266 std::fabs( srcProviderExtent.xMaximum() - outputExtentInSrcCrs.
xMaximum() ) > geoTransform[1] / 2 ||
267 std::fabs( srcProviderExtent.yMinimum() - outputExtentInSrcCrs.
yMinimum() ) > std::fabs( geoTransform[5] ) / 2 ||
268 std::fabs( srcProviderExtent.yMaximum() - outputExtentInSrcCrs.
yMaximum() ) > std::fabs( geoTransform[5] ) / 2 ) )
279 destNoDataValue = typeMinValue;
283 destNoDataValue = typeMaxValue;
290 destHasNoDataValue =
true;
294 if ( nuller && destHasNoDataValue )
299 QgsDebugMsgLevel( QStringLiteral(
"bandNo = %1 destDataType = %2 destHasNoDataValue = %3 destNoDataValue = %4" ).arg( bandNo ).arg(
qgsEnumValueToKey( destDataType ) ).arg( destHasNoDataValue ).arg( destNoDataValue ), 4 );
300 destDataTypeList.append( destDataType );
301 destHasNoDataValueList.append( destHasNoDataValue );
302 destNoDataValueList.append( destNoDataValue );
307 for (
int i = 1; i < nBands; i++ )
309 if ( destDataTypeList.value( i ) > destDataType )
311 destDataType = destDataTypeList.value( i );
317 for (
int attempt = 0; attempt < 2; attempt ++ )
321 std::unique_ptr<QgsRasterDataProvider> destProvider(
322 initOutput( nCols, nRows,
crs, geoTransform, nBands, destDataType, destHasNoDataValueList, destNoDataValueList ) );
329 if ( !destProvider->isValid() )
331 if ( feedback && !destProvider->error().isEmpty() )
333 feedback->
appendError( destProvider->error().summary() );
337 if ( nCols != destProvider->xSize() || nRows != destProvider->ySize() )
339 QgsDebugMsg( QStringLiteral(
"Created raster does not have requested dimensions" ) );
342 feedback->
appendError( QObject::tr(
"Created raster does not have requested dimensions" ) );
346 if ( nBands != destProvider->bandCount() )
348 QgsDebugMsg( QStringLiteral(
"Created raster does not have requested band count" ) );
351 feedback->
appendError( QObject::tr(
"Created raster does not have requested band count" ) );
359 destDataType = destProvider->dataType( 1 );
363 error = writeDataRaster( pipe, iter, nCols, nRows, outputExtent,
crs, destDataType, destHasNoDataValueList, destNoDataValueList, destProvider.get(), feedback );
370 destProvider->remove();
371 destProvider.reset();
379 for (
int i = 0; i < nBands; i++ )
381 double destNoDataValue;
383 destDataTypeList.replace( i, destDataType );
384 destNoDataValueList.replace( i, destNoDataValue );
386 destDataType = destDataTypeList.value( 0 );
399 static int qgsDivRoundUp(
int a,
int b )
401 return a / b + ( ( ( a % b ) != 0 ) ? 1 : 0 );
406 int nCols,
int nRows,
410 const QList<bool> &destHasNoDataValueList,
411 const QList<double> &destNoDataValueList,
416 Q_UNUSED( destHasNoDataValueList )
430 std::vector< std::unique_ptr<QgsRasterBlock> > blockList;
431 std::vector< std::unique_ptr<QgsRasterBlock> > destBlockList;
433 blockList.resize( nBands );
434 destBlockList.resize( nBands );
436 for (
int i = 1; i <= nBands; ++i )
439 if ( destProvider && destHasNoDataValueList.value( i - 1 ) )
441 destProvider->
setNoDataValue( i, destNoDataValueList.value( i - 1 ) );
451 nParts = nPartsX * nPartsY;
458 for (
int i = 1; i <= nBands; ++i )
466 const QString vrtFilePath( mOutputUrl +
'/' + vrtFileName() );
467 writeVRT( vrtFilePath );
470 buildPyramids( vrtFilePath );
477 buildPyramids( mOutputUrl, destProvider );
484 blockList[i - 1].reset( block );
488 if ( feedback && fileIndex < ( nParts - 1 ) )
490 feedback->
setProgress( 100.0 * fileIndex /
static_cast< double >( nParts ) );
498 for (
int i = 1; i <= nBands; ++i )
500 if ( srcProvider && srcProvider->
dataType( i ) == destDataType )
507 blockList[i - 1]->convert( destDataType );
509 destBlockList[i - 1] = std::move( blockList[i - 1] );
514 std::unique_ptr< QgsRasterDataProvider > partDestProvider( createPartProvider( outputExtent,
515 nCols, iterCols, iterRows,
516 iterLeft, iterTop, mOutputUrl,
517 fileIndex, nBands, destDataType,
crs ) );
519 if ( !partDestProvider || !partDestProvider->isValid() )
525 for (
int i = 1; i <= nBands; ++i )
527 if ( destHasNoDataValueList.value( i - 1 ) )
529 partDestProvider->setNoDataValue( i, destNoDataValueList.value( i - 1 ) );
531 if ( destBlockList[ i - 1 ]->isEmpty() )
534 if ( !partDestProvider->write( destBlockList[i - 1]->bits( 0 ), i, iterCols, iterRows, 0, 0 ) )
538 addToVRT( partFileName( fileIndex ), i, iterCols, iterRows, iterLeft, iterTop );
542 else if ( destProvider )
545 for (
int i = 1; i <= nBands; ++i )
547 if ( destBlockList[ i - 1 ]->isEmpty() )
550 if ( !destProvider->
write( destBlockList[i - 1]->bits( 0 ), i, iterCols, iterRows, iterLeft, iterTop ) )
586 const size_t nMaxPixels =
static_cast<size_t>( mMaxTileWidth ) * mMaxTileHeight;
587 std::vector<unsigned char> redData( nMaxPixels );
588 std::vector<unsigned char> greenData( nMaxPixels );
589 std::vector<unsigned char> blueData( nMaxPixels );
590 std::vector<unsigned char> alphaData( nMaxPixels );
591 int iterLeft = 0, iterTop = 0, iterCols = 0, iterRows = 0;
596 double geoTransform[6];
597 globalOutputParameters( outputExtent, nCols, nRows, geoTransform, pixelSize );
599 const int nOutputBands = 4;
600 std::unique_ptr< QgsRasterDataProvider > destProvider( initOutput( nCols, nRows,
crs, geoTransform, nOutputBands,
Qgis::DataType::Byte ) );
607 if ( !destProvider->
isValid() )
615 if ( nCols != destProvider->
xSize() || nRows != destProvider->
ySize() )
617 QgsDebugMsg( QStringLiteral(
"Created raster does not have requested dimensions" ) );
620 feedback->
appendError( QObject::tr(
"Created raster does not have requested dimensions" ) );
624 if ( nOutputBands != destProvider->
bandCount() )
626 QgsDebugMsg( QStringLiteral(
"Created raster does not have requested band count" ) );
629 feedback->
appendError( QObject::tr(
"Created raster does not have requested band count" ) );
635 QgsDebugMsg( QStringLiteral(
"Created raster does not have requested data type" ) );
638 feedback->
appendError( QObject::tr(
"Created raster does not have requested data type" ) );
651 nParts = nPartsX * nPartsY;
654 std::unique_ptr< QgsRasterBlock > inputBlock;
655 while ( iter->
readNextRasterPart( 1, iterCols, iterRows, inputBlock, iterLeft, iterTop ) )
657 if ( !inputBlock || inputBlock->isEmpty() )
662 if ( feedback && fileIndex < ( nParts - 1 ) )
664 feedback->
setProgress( 100.0 * fileIndex /
static_cast< double >( nParts ) );
672 const qgssize nPixels =
static_cast< qgssize >( iterCols ) * iterRows;
673 for (
qgssize i = 0; i < nPixels; ++i )
675 QRgb
c = inputBlock->color( i );
676 if ( isPremultiplied )
678 c = qUnpremultiply(
c );
680 redData[i] =
static_cast<unsigned char>( qRed(
c ) );
681 greenData[i] =
static_cast<unsigned char>( qGreen(
c ) );
682 blueData[i] =
static_cast<unsigned char>( qBlue(
c ) );
683 alphaData[i] =
static_cast<unsigned char>( qAlpha(
c ) );
689 std::unique_ptr< QgsRasterDataProvider > partDestProvider( createPartProvider( outputExtent,
690 nCols, iterCols, iterRows,
691 iterLeft, iterTop, mOutputUrl, fileIndex,
694 if ( !partDestProvider || partDestProvider->isValid() )
700 if ( !partDestProvider->write( &redData[0], 1, iterCols, iterRows, 0, 0 ) ||
701 !partDestProvider->write( &greenData[0], 2, iterCols, iterRows, 0, 0 ) ||
702 !partDestProvider->write( &blueData[0], 3, iterCols, iterRows, 0, 0 ) ||
703 !partDestProvider->write( &alphaData[0], 4, iterCols, iterRows, 0, 0 ) )
708 addToVRT( partFileName( fileIndex ), 1, iterCols, iterRows, iterLeft, iterTop );
709 addToVRT( partFileName( fileIndex ), 2, iterCols, iterRows, iterLeft, iterTop );
710 addToVRT( partFileName( fileIndex ), 3, iterCols, iterRows, iterLeft, iterTop );
711 addToVRT( partFileName( fileIndex ), 4, iterCols, iterRows, iterLeft, iterTop );
713 else if ( destProvider )
715 if ( !destProvider->
write( &redData[0], 1, iterCols, iterRows, iterLeft, iterTop ) ||
716 !destProvider->
write( &greenData[0], 2, iterCols, iterRows, iterLeft, iterTop ) ||
717 !destProvider->
write( &blueData[0], 3, iterCols, iterRows, iterLeft, iterTop ) ||
718 !destProvider->
write( &alphaData[0], 4, iterCols, iterRows, iterLeft, iterTop ) )
726 destProvider.reset();
735 const QString vrtFilePath( mOutputUrl +
'/' + vrtFileName() );
736 writeVRT( vrtFilePath );
739 buildPyramids( vrtFilePath );
746 buildPyramids( mOutputUrl );
752 void QgsRasterFileWriter::addToVRT(
const QString &filename,
int band,
int xSize,
int ySize,
int xOffset,
int yOffset )
754 QDomElement bandElem = mVRTBands.value( band - 1 );
756 QDomElement simpleSourceElem = mVRTDocument.createElement( QStringLiteral(
"SimpleSource" ) );
759 QDomElement sourceFilenameElem = mVRTDocument.createElement( QStringLiteral(
"SourceFilename" ) );
760 sourceFilenameElem.setAttribute( QStringLiteral(
"relativeToVRT" ), QStringLiteral(
"1" ) );
761 const QDomText sourceFilenameText = mVRTDocument.createTextNode( filename );
762 sourceFilenameElem.appendChild( sourceFilenameText );
763 simpleSourceElem.appendChild( sourceFilenameElem );
766 QDomElement sourceBandElem = mVRTDocument.createElement( QStringLiteral(
"SourceBand" ) );
767 const QDomText sourceBandText = mVRTDocument.createTextNode( QString::number( band ) );
768 sourceBandElem.appendChild( sourceBandText );
769 simpleSourceElem.appendChild( sourceBandElem );
772 QDomElement sourcePropertiesElem = mVRTDocument.createElement( QStringLiteral(
"SourceProperties" ) );
773 sourcePropertiesElem.setAttribute( QStringLiteral(
"RasterXSize" ), xSize );
774 sourcePropertiesElem.setAttribute( QStringLiteral(
"RasterYSize" ), ySize );
775 sourcePropertiesElem.setAttribute( QStringLiteral(
"BlockXSize" ), xSize );
776 sourcePropertiesElem.setAttribute( QStringLiteral(
"BlockYSize" ), ySize );
777 sourcePropertiesElem.setAttribute( QStringLiteral(
"DataType" ), QStringLiteral(
"Byte" ) );
778 simpleSourceElem.appendChild( sourcePropertiesElem );
781 QDomElement srcRectElem = mVRTDocument.createElement( QStringLiteral(
"SrcRect" ) );
782 srcRectElem.setAttribute( QStringLiteral(
"xOff" ), QStringLiteral(
"0" ) );
783 srcRectElem.setAttribute( QStringLiteral(
"yOff" ), QStringLiteral(
"0" ) );
784 srcRectElem.setAttribute( QStringLiteral(
"xSize" ), xSize );
785 srcRectElem.setAttribute( QStringLiteral(
"ySize" ), ySize );
786 simpleSourceElem.appendChild( srcRectElem );
789 QDomElement dstRectElem = mVRTDocument.createElement( QStringLiteral(
"DstRect" ) );
790 dstRectElem.setAttribute( QStringLiteral(
"xOff" ), xOffset );
791 dstRectElem.setAttribute( QStringLiteral(
"yOff" ), yOffset );
792 dstRectElem.setAttribute( QStringLiteral(
"xSize" ), xSize );
793 dstRectElem.setAttribute( QStringLiteral(
"ySize" ), ySize );
794 simpleSourceElem.appendChild( dstRectElem );
796 bandElem.appendChild( simpleSourceElem );
799 void QgsRasterFileWriter::buildPyramids(
const QString &filename,
QgsRasterDataProvider *destProviderIn )
807 destProvider = qobject_cast< QgsRasterDataProvider * >(
QgsProviderRegistry::instance()->createProvider( mOutputProviderKey, filename, providerOptions ) );
808 if ( !destProvider || !destProvider->
isValid() )
818 QList< QgsRasterPyramid> myPyramidList;
819 if ( ! mPyramidsList.isEmpty() )
821 for (
int myCounterInt = 0; myCounterInt < myPyramidList.count(); myCounterInt++ )
823 myPyramidList[myCounterInt].setBuild(
true );
826 QgsDebugMsgLevel( QStringLiteral(
"building pyramids : %1 pyramids, %2 resampling, %3 format, %4 options" ).arg( myPyramidList.count() ).arg( mPyramidsResampling ).arg( mPyramidsFormat ).arg( mPyramidsConfigOptions.count() ), 4 );
828 const QString res = destProvider->
buildPyramids( myPyramidList, mPyramidsResampling,
829 mPyramidsFormat, mPyramidsConfigOptions );
835 QString title, message;
836 if ( res == QLatin1String(
"ERROR_WRITE_ACCESS" ) )
838 title = QObject::tr(
"Building Pyramids" );
839 message = QObject::tr(
"Write access denied. Adjust the file permissions and try again." );
841 else if ( res == QLatin1String(
"ERROR_WRITE_FORMAT" ) )
843 title = QObject::tr(
"Building Pyramids" );
844 message = QObject::tr(
"The file was not writable. Some formats do not "
845 "support pyramid overviews. Consult the GDAL documentation if in doubt." );
847 else if ( res == QLatin1String(
"FAILED_NOT_SUPPORTED" ) )
849 title = QObject::tr(
"Building Pyramids" );
850 message = QObject::tr(
"Building pyramid overviews is not supported on this type of raster." );
852 else if ( res == QLatin1String(
"ERROR_VIRTUAL" ) )
854 title = QObject::tr(
"Building Pyramids" );
855 message = QObject::tr(
"Building pyramid overviews is not supported on this type of raster." );
857 QMessageBox::warning(
nullptr, title, message );
860 if ( !destProviderIn )
865 int QgsRasterFileWriter::pyramidsProgress(
double dfComplete,
const char *pszMessage,
void *pData )
867 Q_UNUSED( pszMessage )
868 GDALTermProgress( dfComplete, 0, 0 );
869 QProgressDialog *progressDialog =
static_cast<QProgressDialog *
>( pData );
870 if ( pData && progressDialog->wasCanceled() )
877 progressDialog->setRange( 0, 100 );
878 progressDialog->setValue( dfComplete * 100 );
884 void QgsRasterFileWriter::createVRT(
int xSize,
int ySize,
const QgsCoordinateReferenceSystem &
crs,
double *geoTransform,
Qgis::DataType type,
const QList<bool> &destHasNoDataValueList,
const QList<double> &destNoDataValueList )
886 mVRTDocument.clear();
887 QDomElement VRTDatasetElem = mVRTDocument.createElement( QStringLiteral(
"VRTDataset" ) );
890 VRTDatasetElem.setAttribute( QStringLiteral(
"rasterXSize" ), xSize );
891 VRTDatasetElem.setAttribute( QStringLiteral(
"rasterYSize" ), ySize );
892 mVRTDocument.appendChild( VRTDatasetElem );
895 QDomElement SRSElem = mVRTDocument.createElement( QStringLiteral(
"SRS" ) );
896 const QDomText crsText = mVRTDocument.createTextNode(
crs.
toWkt() );
897 SRSElem.appendChild( crsText );
898 VRTDatasetElem.appendChild( SRSElem );
903 QDomElement geoTransformElem = mVRTDocument.createElement( QStringLiteral(
"GeoTransform" ) );
904 const QString geoTransformString = QString::number( geoTransform[0],
'f', 6 ) +
", " + QString::number( geoTransform[1] ) +
", " + QString::number( geoTransform[2] ) +
905 ", " + QString::number( geoTransform[3],
'f', 6 ) +
", " + QString::number( geoTransform[4] ) +
", " + QString::number( geoTransform[5] );
906 const QDomText geoTransformText = mVRTDocument.createTextNode( geoTransformString );
907 geoTransformElem.appendChild( geoTransformText );
908 VRTDatasetElem.appendChild( geoTransformElem );
921 QStringList colorInterp;
922 colorInterp << QStringLiteral(
"Red" ) << QStringLiteral(
"Green" ) << QStringLiteral(
"Blue" ) << QStringLiteral(
"Alpha" );
924 QMap<Qgis::DataType, QString> dataTypes;
936 for (
int i = 1; i <= nBands; i++ )
938 QDomElement VRTBand = mVRTDocument.createElement( QStringLiteral(
"VRTRasterBand" ) );
940 VRTBand.setAttribute( QStringLiteral(
"band" ), QString::number( i ) );
941 const QString dataType = dataTypes.value( type );
942 VRTBand.setAttribute( QStringLiteral(
"dataType" ), dataType );
944 if ( mMode ==
Image )
946 VRTBand.setAttribute( QStringLiteral(
"dataType" ), QStringLiteral(
"Byte" ) );
947 QDomElement colorInterpElement = mVRTDocument.createElement( QStringLiteral(
"ColorInterp" ) );
948 const QDomText interpText = mVRTDocument.createTextNode( colorInterp.value( i - 1 ) );
949 colorInterpElement.appendChild( interpText );
950 VRTBand.appendChild( colorInterpElement );
953 if ( !destHasNoDataValueList.isEmpty() && destHasNoDataValueList.value( i - 1 ) )
955 VRTBand.setAttribute( QStringLiteral(
"NoDataValue" ), QString::number( destNoDataValueList.value( i - 1 ) ) );
958 mVRTBands.append( VRTBand );
959 VRTDatasetElem.appendChild( VRTBand );
963 bool QgsRasterFileWriter::writeVRT(
const QString &file )
965 QFile outputFile( file );
966 if ( ! outputFile.open( QIODevice::WriteOnly | QIODevice::Truncate ) )
971 QTextStream outStream( &outputFile );
972 mVRTDocument.save( outStream, 2 );
977 int iterRows,
int iterLeft,
int iterTop,
const QString &outputUrl,
int fileIndex,
int nBands,
Qgis::DataType type,
980 const double mup = extent.
width() / nCols;
981 const double mapLeft = extent.
xMinimum() + iterLeft * mup;
982 const double mapRight = mapLeft + mup * iterCols;
983 const double mapTop = extent.
yMaximum() - iterTop * mup;
984 const double mapBottom = mapTop - iterRows * mup;
985 const QgsRectangle mapRect( mapLeft, mapBottom, mapRight, mapTop );
987 const QString outputFile =
outputUrl +
'/' + partFileName( fileIndex );
990 double geoTransform[6];
991 geoTransform[0] = mapRect.xMinimum();
992 geoTransform[1] = mup;
993 geoTransform[2] = 0.0;
994 geoTransform[3] = mapRect.yMaximum();
995 geoTransform[4] = 0.0;
996 geoTransform[5] = -mup;
1003 return destProvider;
1008 const QList<bool> &destHasNoDataValueList,
const QList<double> &destNoDataValueList )
1012 createVRT( nCols, nRows,
crs, geoTransform, type, destHasNoDataValueList, destNoDataValueList );
1020 if ( mBuildPyramidsFlag == -4 && mOutputProviderKey ==
"gdal" && mOutputFormat.compare( QLatin1String(
"gtiff" ), Qt::CaseInsensitive ) == 0 )
1021 mCreateOptions <<
"COPY_SRC_OVERVIEWS=YES";
1026 if ( !destProvider )
1028 QgsDebugMsg( QStringLiteral(
"No provider created" ) );
1031 return destProvider;
1035 void QgsRasterFileWriter::globalOutputParameters(
const QgsRectangle &extent,
int nCols,
int &nRows,
1036 double *geoTransform,
double &pixelSize )
1038 pixelSize = extent.
width() / nCols;
1043 nRows =
static_cast< double >( nCols ) / extent.
width() * extent.
height() + 0.5;
1045 geoTransform[0] = extent.
xMinimum();
1046 geoTransform[1] = pixelSize;
1047 geoTransform[2] = 0.0;
1048 geoTransform[3] = extent.
yMaximum();
1049 geoTransform[4] = 0.0;
1050 geoTransform[5] = -( extent.
height() / nRows );
1053 QString QgsRasterFileWriter::partFileName(
int fileIndex )
1056 const QFileInfo outputInfo( mOutputUrl );
1057 return QStringLiteral(
"%1.%2.tif" ).arg( outputInfo.fileName() ).arg( fileIndex );
1060 QString QgsRasterFileWriter::vrtFileName()
1062 const QFileInfo outputInfo( mOutputUrl );
1063 return QStringLiteral(
"%1.vrt" ).arg( outputInfo.fileName() );
1068 QString ext = extension.trimmed();
1069 if ( ext.isEmpty() )
1072 if ( ext.startsWith(
'.' ) )
1076 int const drvCount = GDALGetDriverCount();
1078 for (
int i = 0; i < drvCount; ++i )
1080 GDALDriverH drv = GDALGetDriver( i );
1083 char **driverMetadata = GDALGetMetadata( drv,
nullptr );
1084 if ( CSLFetchBoolean( driverMetadata, GDAL_DCAP_RASTER,
false ) )
1086 QString drvName = GDALGetDriverShortName( drv );
1087 const QStringList driverExtensions = QString( GDALGetMetadataItem( drv, GDAL_DMD_EXTENSIONS,
nullptr ) ).split(
' ' );
1089 const auto constDriverExtensions = driverExtensions;
1090 for (
const QString &driver : constDriverExtensions )
1092 if ( driver.compare( ext, Qt::CaseInsensitive ) == 0 )
1103 GDALDriverH drv = GDALGetDriverByName( format.toLocal8Bit().data() );
1106 char **driverMetadata = GDALGetMetadata( drv,
nullptr );
1107 if ( CSLFetchBoolean( driverMetadata, GDAL_DCAP_RASTER,
false ) )
1109 return QString( GDALGetMetadataItem( drv, GDAL_DMD_EXTENSIONS,
nullptr ) ).split(
' ' );
1112 return QStringList();
1117 GDALDriverH drv = GDALGetDriverByName( driverName.toLocal8Bit().data() );
1120 const QString drvName = GDALGetDriverLongName( drv );
1121 const QString extensionsString = QString( GDALGetMetadataItem( drv, GDAL_DMD_EXTENSIONS,
nullptr ) );
1122 if ( extensionsString.isEmpty() )
1126 const QStringList extensions = extensionsString.split(
' ' );
1127 QString filter = drvName +
" (";
1128 for (
const QString &ext : extensions )
1130 filter.append( QStringLiteral(
"*.%1 *.%2 " ).arg( ext.toLower(), ext.toUpper() ) );
1132 filter = filter.trimmed().append( QStringLiteral(
")" ) );
1141 static QReadWriteLock sFilterLock;
1142 static QMap< RasterFormatOptions, QList< QgsRasterFileWriter::FilterFormatDetails > > sFilters;
1146 const auto it = sFilters.constFind( options );
1147 if ( it != sFilters.constEnd() )
1151 int const drvCount = GDALGetDriverCount();
1154 QList< QgsRasterFileWriter::FilterFormatDetails > results;
1158 for (
int i = 0; i < drvCount; ++i )
1160 GDALDriverH drv = GDALGetDriver( i );
1165 const QString drvName = GDALGetDriverShortName( drv );
1167 if ( filterString.isEmpty() )
1176 if ( drvName == QLatin1String(
"GTiff" ) )
1178 tifFormat = details;
1190 return a.driverName < b.driverName;
1197 results.insert( 0, tifFormat );
1201 sFilters.insert( options, results );
1209 QStringList extensions;
1211 const QRegularExpression rx( QStringLiteral(
"\\*\\.([a-zA-Z0-9]*)" ) );
1215 const QString ext = format.filterString;
1216 const QRegularExpressionMatch match = rx.match( ext );
1217 if ( !match.hasMatch() )
1220 const QString matched = match.captured( 1 );
1221 extensions << matched;