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( nullptr ), mPipe( nullptr ), mInput( nullptr )
41 , mOutputProviderKey(
"gdal" )
42 , mOutputFormat(
"GTiff" )
44 , mMaxTileWidth( 500 )
45 , mMaxTileHeight( 500 )
48 , mProgressDialog(
nullptr )
95 mProgressDialog = progressDialog;
114 if ( mMode ==
Image )
116 WriterError e = writeImageRaster( &iter, nCols, nRows, outputExtent, crs, progressDialog );
117 mProgressDialog =
nullptr;
122 mProgressDialog =
nullptr;
123 WriterError e = writeDataRaster( pipe, &iter, nCols, nRows, outputExtent, crs, progressDialog );
163 for (
int i = 2; i <= nBands; ++i )
178 for (
int bandNo = 1; bandNo <= nBands; bandNo++ )
183 bool destHasNoDataValue =
false;
184 double destNoDataValue = std::numeric_limits<double>::quiet_NaN();
188 if ( srcHasNoDataValue )
193 destHasNoDataValue =
true;
198 destNoDataValue = nuller->
noData( bandNo ).
value( 0 ).min();
199 destHasNoDataValue =
true;
206 if ( projector && projector->
destCrs() != projector->
srcCrs() )
209 srcExtent = ct.transformBoundingBox( outputExtent );
222 destNoDataValue = typeMinValue;
226 destNoDataValue = typeMaxValue;
233 destHasNoDataValue =
true;
237 if ( nuller && destHasNoDataValue )
242 QgsDebugMsgLevel(
QString(
"bandNo = %1 destDataType = %2 destHasNoDataValue = %3 destNoDataValue = %4" ).arg( bandNo ).arg( destDataType ).arg( destHasNoDataValue ).arg( destNoDataValue ), 4 );
243 destDataTypeList.
append( destDataType );
244 destHasNoDataValueList.
append( destHasNoDataValue );
245 destNoDataValueList.
append( destNoDataValue );
250 for (
int i = 1; i < nBands; i++ )
252 if ( destDataTypeList.
value( i ) > destDataType )
254 destDataType = destDataTypeList.
value( i );
262 double geoTransform[6];
263 globalOutputParameters( outputExtent, nCols, nRows, geoTransform, pixelSize );
266 destProvider = initOutput( nCols, nRows, crs, geoTransform, nBands, destDataType, destHasNoDataValueList, destNoDataValueList );
268 WriterError error = writeDataRaster( pipe, iter, nCols, nRows, outputExtent, crs, destDataType, destHasNoDataValueList, destNoDataValueList, destProvider, progressDialog );
277 destProvider =
nullptr;
285 for (
int i = 0; i < nBands; i++ )
287 double destNoDataValue;
289 destDataTypeList.
replace( i, destDataType );
290 destNoDataValueList.
replace( i, destNoDataValue );
292 destDataType = destDataTypeList.
value( 0 );
295 destProvider = initOutput( nCols, nRows, crs, geoTransform, nBands, destDataType, destHasNoDataValueList, destNoDataValueList );
296 error = writeDataRaster( pipe, iter, nCols, nRows, outputExtent, crs, destDataType, destHasNoDataValueList, destNoDataValueList, destProvider, progressDialog );
308 int nCols,
int nRows,
318 Q_UNUSED( destHasNoDataValueList );
334 for (
int i = 1; i <= nBands; ++i )
346 if ( progressDialog )
350 nParts = nPartsX * nPartsY;
352 progressDialog->
show();
353 progressDialog->
setLabelText(
QObject::tr(
"Reading raster part %1 of %2" ).arg( fileIndex + 1 ).arg( nParts ) );
360 for (
int i = 1; i <= nBands; ++i )
362 if ( !iter->
readNextRasterPart( i, iterCols, iterRows, &( blockList[i - 1] ), iterLeft, iterTop ) )
367 QString vrtFilePath( mOutputUrl +
'/' + vrtFileName() );
368 writeVRT( vrtFilePath );
371 buildPyramids( vrtFilePath );
378 buildPyramids( mOutputUrl );
388 if ( progressDialog && fileIndex < ( nParts - 1 ) )
390 progressDialog->
setValue( fileIndex + 1 );
391 progressDialog->
setLabelText(
QObject::tr(
"Reading raster part %1 of %2" ).arg( fileIndex + 2 ).arg( nParts ) );
395 for (
int i = 0; i < nBands; ++i )
405 for (
int i = 1; i <= nBands; ++i )
407 if ( srcProvider && srcProvider->
dataType( i ) == destDataType )
409 destBlockList.
push_back( blockList[i-1] );
414 blockList[i-1]->convert( destDataType );
415 destBlockList.
push_back( blockList[i-1] );
417 blockList[i-1] =
nullptr;
423 nCols, iterCols, iterRows,
424 iterLeft, iterTop, mOutputUrl,
425 fileIndex, nBands, destDataType, crs );
427 if ( partDestProvider )
430 for (
int i = 1; i <= nBands; ++i )
433 partDestProvider->
write( destBlockList[i - 1]->bits( 0 ), i, iterCols, iterRows, 0, 0 );
434 delete destBlockList[i - 1];
435 addToVRT( partFileName( fileIndex ), i, iterCols, iterRows, iterLeft, iterTop );
437 delete partDestProvider;
440 else if ( destProvider )
443 for (
int i = 1; i <= nBands; ++i )
445 destProvider->
write( destBlockList[i - 1]->bits( 0 ), i, iterCols, iterRows, iterLeft, iterTop );
446 delete destBlockList[i - 1];
478 void* redData =
qgsMalloc( mMaxTileWidth * mMaxTileHeight );
479 void* greenData =
qgsMalloc( mMaxTileWidth * mMaxTileHeight );
480 void* blueData =
qgsMalloc( mMaxTileWidth * mMaxTileHeight );
481 void* alphaData =
qgsMalloc( mMaxTileWidth * mMaxTileHeight );
483 int iterLeft = 0, iterTop = 0, iterCols = 0, iterRows = 0;
489 double geoTransform[6];
490 globalOutputParameters( outputExtent, nCols, nRows, geoTransform, pixelSize );
492 destProvider = initOutput( nCols, nRows, crs, geoTransform, 4,
QGis::Byte );
497 if ( progressDialog )
501 nParts = nPartsX * nPartsY;
503 progressDialog->
show();
504 progressDialog->
setLabelText(
QObject::tr(
"Reading raster part %1 of %2" ).arg( fileIndex + 1 ).arg( nParts ) );
508 while ( iter->
readNextRasterPart( 1, iterCols, iterRows, &inputBlock, iterLeft, iterTop ) )
515 if ( progressDialog && fileIndex < ( nParts - 1 ) )
517 progressDialog->
setValue( fileIndex + 1 );
518 progressDialog->
setLabelText(
QObject::tr(
"Reading raster part %1 of %2" ).arg( fileIndex + 2 ).arg( nParts ) );
534 for (
qgssize i = 0; i < nPixels; ++i )
536 QRgb c = inputBlock->
color( i );
544 double a = alpha / 255.;
545 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 );
550 memcpy( reinterpret_cast< char* >( redData ) + i, &red, 1 );
551 memcpy( reinterpret_cast< char* >( greenData ) + i, &green, 1 );
552 memcpy( reinterpret_cast< char* >( blueData ) + i, &blue, 1 );
553 memcpy( reinterpret_cast< char* >( alphaData ) + i, &alpha, 1 );
562 nCols, iterCols, iterRows,
563 iterLeft, iterTop, mOutputUrl, fileIndex,
566 if ( partDestProvider )
569 partDestProvider->
write( redData, 1, iterCols, iterRows, 0, 0 );
570 partDestProvider->
write( greenData, 2, iterCols, iterRows, 0, 0 );
571 partDestProvider->
write( blueData, 3, iterCols, iterRows, 0, 0 );
572 partDestProvider->
write( alphaData, 4, iterCols, iterRows, 0, 0 );
574 addToVRT( partFileName( fileIndex ), 1, iterCols, iterRows, iterLeft, iterTop );
575 addToVRT( partFileName( fileIndex ), 2, iterCols, iterRows, iterLeft, iterTop );
576 addToVRT( partFileName( fileIndex ), 3, iterCols, iterRows, iterLeft, iterTop );
577 addToVRT( partFileName( fileIndex ), 4, iterCols, iterRows, iterLeft, iterTop );
578 delete partDestProvider;
581 else if ( destProvider )
583 destProvider->
write( redData, 1, iterCols, iterRows, iterLeft, iterTop );
584 destProvider->
write( greenData, 2, iterCols, iterRows, iterLeft, iterTop );
585 destProvider->
write( blueData, 3, iterCols, iterRows, iterLeft, iterTop );
586 destProvider->
write( alphaData, 4, iterCols, iterRows, iterLeft, iterTop );
600 if ( progressDialog )
607 QString vrtFilePath( mOutputUrl +
'/' + vrtFileName() );
608 writeVRT( vrtFilePath );
611 buildPyramids( vrtFilePath );
618 buildPyramids( mOutputUrl );
624 void QgsRasterFileWriter::addToVRT(
const QString& filename,
int band,
int xSize,
int ySize,
int xOffset,
int yOffset )
632 sourceFilenameElem.
setAttribute(
"relativeToVRT",
"1" );
634 sourceFilenameElem.
appendChild( sourceFilenameText );
635 simpleSourceElem.
appendChild( sourceFilenameElem );
645 sourcePropertiesElem.
setAttribute(
"RasterXSize", xSize );
646 sourcePropertiesElem.
setAttribute(
"RasterYSize", ySize );
647 sourcePropertiesElem.
setAttribute(
"BlockXSize", xSize );
648 sourcePropertiesElem.
setAttribute(
"BlockYSize", ySize );
649 sourcePropertiesElem.
setAttribute(
"DataType",
"Byte" );
650 simpleSourceElem.
appendChild( sourcePropertiesElem );
672 void QgsRasterFileWriter::buildPyramids(
const QString& filename )
687 overviewList[3] = 16;
688 overviewList[4] = 32;
689 overviewList[5] = 64;
692 if ( mProgressDialog )
697 mProgressDialog->
show();
700 GDALBuildOverviews( dataSet,
"AVERAGE", 6, overviewList, 0, 0, 0, 0 );
704 void QgsRasterFileWriter::buildPyramids(
const QString& filename )
718 if ( ! mPyramidsList.
isEmpty() )
720 for (
int myCounterInt = 0; myCounterInt < myPyramidList.
count(); myCounterInt++ )
722 myPyramidList[myCounterInt].build =
true;
725 QgsDebugMsgLevel(
QString(
"building pyramids : %1 pyramids, %2 resampling, %3 format, %4 options" ).arg( myPyramidList.
count() ).arg( mPyramidsResampling ).
arg( mPyramidsFormat ).
arg( mPyramidsConfigOptions.
count() ), 4 );
728 mPyramidsFormat, mPyramidsConfigOptions );
735 if ( res ==
"ERROR_WRITE_ACCESS" )
737 title =
QObject::tr(
"Building pyramids failed - write access denied" );
738 message =
QObject::tr(
"Write access denied. Adjust the file permissions and try again." );
740 else if ( res ==
"ERROR_WRITE_FORMAT" )
742 title =
QObject::tr(
"Building pyramids failed." );
743 message =
QObject::tr(
"The file was not writable. Some formats do not " 744 "support pyramid overviews. Consult the GDAL documentation if in doubt." );
746 else if ( res ==
"FAILED_NOT_SUPPORTED" )
748 title =
QObject::tr(
"Building pyramids failed." );
749 message =
QObject::tr(
"Building pyramid overviews is not supported on this type of raster." );
751 else if ( res ==
"ERROR_JPEG_COMPRESSION" )
753 title =
QObject::tr(
"Building pyramids failed." );
754 message =
QObject::tr(
"Building internal pyramid overviews is not supported on raster layers with JPEG compression and your current libtiff library." );
756 else if ( res ==
"ERROR_VIRTUAL" )
758 title =
QObject::tr(
"Building pyramids failed." );
759 message =
QObject::tr(
"Building pyramid overviews is not supported on this type of raster." );
768 int QgsRasterFileWriter::pyramidsProgress(
double dfComplete,
const char *pszMessage,
void* pData )
770 Q_UNUSED( pszMessage );
771 GDALTermProgress( dfComplete, 0, 0 );
781 progressDialog->
setValue( dfComplete * 100 );
789 mVRTDocument.
clear();
825 colorInterp <<
"Red" <<
"Green" <<
"Blue" <<
"Alpha";
839 for (
int i = 1; i <= nBands; i++ )
847 if ( mMode ==
Image )
856 if ( !destHasNoDataValueList.
isEmpty() && destHasNoDataValueList.
value( i - 1 ) )
861 mVRTBands.
append( VRTBand );
866 bool QgsRasterFileWriter::writeVRT(
const QString& file )
868 QFile outputFile( file );
869 if ( ! outputFile.
open( QIODevice::WriteOnly | QIODevice::Truncate ) )
875 mVRTDocument.
save( outStream, 2 );
880 int iterRows,
int iterLeft,
int iterTop,
const QString& outputUrl,
int fileIndex,
int nBands,
QGis::DataType type,
883 double mup = extent.
width() / nCols;
884 double mapLeft = extent.
xMinimum() + iterLeft * mup;
885 double mapRight = mapLeft + mup * iterCols;
886 double mapTop = extent.
yMaximum() - iterTop * mup;
887 double mapBottom = mapTop - iterRows * mup;
888 QgsRectangle mapRect( mapLeft, mapBottom, mapRight, mapTop );
890 QString outputFile = outputUrl +
'/' + partFileName( fileIndex );
893 double geoTransform[6];
894 geoTransform[0] = mapRect.
xMinimum();
895 geoTransform[1] = mup;
896 geoTransform[2] = 0.0;
897 geoTransform[3] = mapRect.
yMaximum();
898 geoTransform[4] = 0.0;
899 geoTransform[5] = -mup;
915 createVRT( nCols, nRows, crs, geoTransform, type, destHasNoDataValueList, destNoDataValueList );
923 if ( mBuildPyramidsFlag == -4 && mOutputProviderKey ==
"gdal" && mOutputFormat.
toLower() ==
"gtiff" )
924 mCreateOptions <<
"COPY_SRC_OVERVIEWS=YES";
938 void QgsRasterFileWriter::globalOutputParameters(
const QgsRectangle& extent,
int nCols,
int& nRows,
939 double* geoTransform,
double& pixelSize )
941 pixelSize = extent.
width() / nCols;
946 nRows =
static_cast< double >( nCols ) / extent.
width() * extent.
height() + 0.5;
948 geoTransform[0] = extent.
xMinimum();
949 geoTransform[1] = pixelSize;
950 geoTransform[2] = 0.0;
951 geoTransform[3] = extent.
yMaximum();
952 geoTransform[4] = 0.0;
953 geoTransform[5] = -( extent.
height() / nRows );
956 QString QgsRasterFileWriter::partFileName(
int fileIndex )
963 QString QgsRasterFileWriter::vrtFileName()
virtual int bandCount() const =0
Get number of bands.
Eight bit unsigned integer (quint8)
static QgsProviderRegistry * instance(const QString &pluginPath=QString::null)
Means of accessing canonical single instance.
A rectangle specified with double values.
QgsRasterFileWriter(const QString &outputUrl)
Base class for processing modules.
QgsRasterNuller * nuller() const
void * qgsMalloc(size_t size)
Allocates size bytes and returns a pointer to the allocated memory.
Iterator for sequentially processing raster cells.
static QgsRasterDataProvider * create(const QString &providerKey, const QString &uri, const QString &format, int nBands, QGis::DataType type, int width, int height, double *geoTransform, const QgsCoordinateReferenceSystem &crs, const QStringList &createOptions=QStringList())
Creates a new dataset with mDataSourceURI.
QDomNode appendChild(const QDomNode &newChild)
void startRasterRead(int bandNumber, int nCols, int nRows, const QgsRectangle &extent)
Start reading of raster band.
void setMaximum(int maximum)
void push_back(const T &value)
double yMaximum() const
Get the y maximum value (top side of rectangle)
void setLabelText(const QString &text)
bool contains(const QgsRectangle &rect) const
return true when rectangle contains other rectangle
virtual double srcNoDataValue(int bandNo) const
Value representing no data value.
virtual const QgsRasterInterface * srcInput() const
Get source / raw input, the first in pipe, usually provider.
Raster pipe that deals with null values.
QString toWkt() const
Returns a WKT representation of this CRS.
double maximumValue
The maximum cell value in the raster band.
QgsRasterInterface * last() const
Thirty two bit floating point (float)
static double maximumValuePossible(QGis::DataType)
Helper function that returns the maximum possible value for a GDAL data type.
virtual bool setNoDataValue(int bandNo, double noDataValue)
Set no data value on created dataset.
QString tr(const char *sourceText, const char *disambiguation, int n)
int maximumTileWidth() const
virtual QgsRasterBandStats bandStatistics(int theBandNo, int theStats=QgsRasterBandStats::All, const QgsRectangle &theExtent=QgsRectangle(), int theSampleSize=0)
Get band statistics.
void setValue(int progress)
static QGis::DataType typeWithNoDataValue(QGis::DataType dataType, double *noDataValue)
For given data type returns wider type and sets no data value.
QString number(int n, int base)
int count(const T &value) const
The RasterBandStats struct is a container for statistics about a single raster band.
void processEvents(QFlags< QEventLoop::ProcessEventsFlag > flags)
void append(const T &value)
Sixteen bit unsigned integer (quint16)
Sixty four bit floating point (double)
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32_Premultiplied.
QgsDataProvider * provider(const QString &providerKey, const QString &dataSource)
Create an instance of the provider.
#define QgsDebugMsgLevel(str, level)
virtual QGis::DataType srcDataType(int bandNo) const override=0
Returns source data type for the band specified by number, source data type may be shorter than dataT...
virtual QList< QgsRasterPyramid > buildPyramidList(QList< int > overviewList=QList< int >())
Accessor for ths raster layers pyramid list.
void setAttribute(const QString &name, const QString &value)
static bool typeIsColor(QGis::DataType type)
Returns true if data type is color.
Thirty two bit unsigned integer (quint32)
int maximumTileHeight() const
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32.
static int typeSize(int dataType)
QgsRasterProjector * projector() const
QgsCoordinateReferenceSystem destCrs() const
Get destination CRS.
virtual QGis::DataType dataType(int bandNo) const =0
Returns data type for the band specified by number.
bool readNextRasterPart(int bandNumber, int &nCols, int &nRows, QgsRasterBlock **block, int &topLeftCol, int &topLeftRow)
Fetches next part of raster data, caller takes ownership of the block and caller should delete the bl...
void setRange(int minimum, int maximum)
virtual bool open(QFlags< QIODevice::OpenModeFlag > mode)
Base class for processing filters like renderers, reprojector, resampler etc.
Sixteen bit signed integer (qint16)
QDomText createTextNode(const QString &value)
unsigned long long qgssize
Qgssize is used instead of size_t, because size_t is stdlib type, unknown by SIP, and it would be har...
QByteArray toLocal8Bit() const
void setOutputNoDataValue(int bandNo, double noData)
Set output no data value.
virtual QgsRectangle extent() override=0
Get the extent of the data source.
void setMaximumTileWidth(int w)
virtual QGis::DataType dataType(int bandNo) const override=0
Returns data type for the band specified by number.
void setMaximumTileHeight(int h)
void save(QTextStream &str, int indent) const
QgsCoordinateReferenceSystem srcCrs() const
Get source CRS.
QgsRasterRangeList noData(int bandNo) const
QString absolutePath() const
virtual bool remove()
Remove dataset.
bool mkdir(const QString &dirName) const
Class for storing a coordinate reference system (CRS)
DataType
Raster data types.
double minimumValue
The minimum cell value in the raster band.
virtual QString buildPyramids(const QList< QgsRasterPyramid > &thePyramidList, const QString &theResamplingMethod="NEAREST", QgsRaster::RasterPyramidsFormat theFormat=QgsRaster::PyramidsGTiff, const QStringList &theConfigOptions=QStringList())
Create pyramid overviews.
StandardButton warning(QWidget *parent, const QString &title, const QString &text, QFlags< QMessageBox::StandardButton > buttons, StandardButton defaultButton)
iterator insert(const Key &key, const T &value)
virtual bool write(void *data, int band, int width, int height, int xOffset, int yOffset)
Writes into the provider datasource.
virtual bool srcHasNoDataValue(int bandNo) const
Return true if source band has no data value.
QRgb color(int row, int column) const
Read a single color.
QDomElement createElement(const QString &tagName)
double width() const
Width of the rectangle.
WriterError writeRaster(const QgsRasterPipe *pipe, int nCols, int nRows, QgsRectangle outputExtent, const QgsCoordinateReferenceSystem &crs, QProgressDialog *p=nullptr)
Write raster file.
QString arg(qlonglong a, int fieldWidth, int base, const QChar &fillChar) const
double xMinimum() const
Get the x minimum value (left side of rectangle)
void qgsFree(void *ptr)
Frees the memory space pointed to by ptr.
const QgsRasterInterface * input() const
double height() const
Height of the rectangle.
const T value(const Key &key) const
Base class for raster data providers.
void replace(int i, const T &value)