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 )
39 QgsRasterFileWriter::QgsRasterFileWriter()
41 , mOutputProviderKey(
"gdal" )
42 , mOutputFormat(
"GTiff" )
44 , mMaxTileWidth( 500 )
45 , mMaxTileHeight( 500 )
46 , mBuildPyramidsFlag(
QgsRaster::PyramidsFlagNo )
47 , mPyramidsFormat(
QgsRaster::PyramidsGTiff )
48 , mProgressDialog( 0 )
97 mProgressDialog = progressDialog;
116 if ( mMode ==
Image )
118 WriterError e = writeImageRaster( &iter, nCols, nRows, outputExtent, crs, progressDialog );
125 WriterError e = writeDataRaster( pipe, &iter, nCols, nRows, outputExtent, crs, progressDialog );
165 for (
int i = 2; i <= nBands; ++i )
180 for (
int bandNo = 1; bandNo <= nBands; bandNo++ )
185 bool destHasNoDataValue =
false;
186 double destNoDataValue = std::numeric_limits<double>::quiet_NaN();
190 if ( srcHasNoDataValue )
195 destHasNoDataValue =
true;
197 else if ( nuller && nuller->
noData( bandNo ).
size() > 0 )
200 destNoDataValue = nuller->
noData( bandNo ).
value( 0 ).min();
201 destHasNoDataValue =
true;
208 if ( projector && projector->
destCrs() != projector->
srcCrs() )
211 srcExtent = ct.transformBoundingBox( outputExtent );
224 destNoDataValue = typeMinValue;
228 destNoDataValue = typeMaxValue;
235 destHasNoDataValue =
true;
239 if ( nuller && destHasNoDataValue )
244 QgsDebugMsg(
QString(
"bandNo = %1 destDataType = %2 destHasNoDataValue = %3 destNoDataValue = %4" ).arg( bandNo ).arg( destDataType ).arg( destHasNoDataValue ).arg( destNoDataValue ) );
245 destDataTypeList.
append( destDataType );
246 destHasNoDataValueList.
append( destHasNoDataValue );
247 destNoDataValueList.
append( destNoDataValue );
252 for (
int i = 1; i < nBands; i++ )
254 if ( destDataTypeList.
value( i ) > destDataType )
256 destDataType = destDataTypeList.
value( i );
264 double geoTransform[6];
265 globalOutputParameters( outputExtent, nCols, nRows, geoTransform, pixelSize );
268 destProvider = initOutput( nCols, nRows, crs, geoTransform, nBands, destDataType, destHasNoDataValueList, destNoDataValueList );
270 WriterError error = writeDataRaster( pipe, iter, nCols, nRows, outputExtent, crs, destDataType, destHasNoDataValueList, destNoDataValueList, destProvider, progressDialog );
287 for (
int i = 0; i < nBands; i++ )
289 double destNoDataValue;
291 destDataTypeList.
replace( i, destDataType );
292 destNoDataValueList.
replace( i, destNoDataValue );
294 destDataType = destDataTypeList.
value( 0 );
297 destProvider = initOutput( nCols, nRows, crs, geoTransform, nBands, destDataType, destHasNoDataValueList, destNoDataValueList );
298 error = writeDataRaster( pipe, iter, nCols, nRows, outputExtent, crs, destDataType, destHasNoDataValueList, destNoDataValueList, destProvider, progressDialog );
310 int nCols,
int nRows,
320 Q_UNUSED( destHasNoDataValueList );
335 for (
int i = 1; i <= nBands; ++i )
347 if ( progressDialog )
351 nParts = nPartsX * nPartsY;
353 progressDialog->
show();
354 progressDialog->
setLabelText(
QObject::tr(
"Reading raster part %1 of %2" ).arg( fileIndex + 1 ).arg( nParts ) );
361 for (
int i = 1; i <= nBands; ++i )
363 if ( !iter->
readNextRasterPart( i, iterCols, iterRows, &( blockList[i - 1] ), iterLeft, iterTop ) )
368 QString vrtFilePath( mOutputUrl +
"/" + vrtFileName() );
369 writeVRT( vrtFilePath );
372 buildPyramids( vrtFilePath );
379 buildPyramids( mOutputUrl );
389 if ( progressDialog && fileIndex < ( nParts - 1 ) )
391 progressDialog->
setValue( fileIndex + 1 );
392 progressDialog->
setLabelText(
QObject::tr(
"Reading raster part %1 of %2" ).arg( fileIndex + 2 ).arg( nParts ) );
396 for (
int i = 0; i < nBands; ++i )
406 for (
int i = 1; i <= nBands; ++i )
408 if ( srcProvider && srcProvider->
dataType( i ) == destDataType )
410 destBlockList.
push_back( blockList[i-1] );
415 blockList[i-1]->convert( destDataType );
416 destBlockList.
push_back( blockList[i-1] );
424 nCols, iterCols, iterRows,
425 iterLeft, iterTop, mOutputUrl,
426 fileIndex, nBands, destDataType, crs );
428 if ( partDestProvider )
431 for (
int i = 1; i <= nBands; ++i )
434 partDestProvider->
write( destBlockList[i - 1]->bits( 0 ), i, iterCols, iterRows, 0, 0 );
435 delete destBlockList[i - 1];
436 addToVRT( partFileName( fileIndex ), i, iterCols, iterRows, iterLeft, iterTop );
438 delete partDestProvider;
441 else if ( destProvider )
444 for (
int i = 1; i <= nBands; ++i )
446 destProvider->
write( destBlockList[i - 1]->bits( 0 ), i, iterCols, iterRows, iterLeft, iterTop );
447 delete destBlockList[i - 1];
479 void* redData =
qgsMalloc( mMaxTileWidth * mMaxTileHeight );
480 void* greenData =
qgsMalloc( mMaxTileWidth * mMaxTileHeight );
481 void* blueData =
qgsMalloc( mMaxTileWidth * mMaxTileHeight );
482 void* alphaData =
qgsMalloc( mMaxTileWidth * mMaxTileHeight );
484 int iterLeft = 0, iterTop = 0, iterCols = 0, iterRows = 0;
490 double geoTransform[6];
491 globalOutputParameters( outputExtent, nCols, nRows, geoTransform, pixelSize );
493 destProvider = initOutput( nCols, nRows, crs, geoTransform, 4,
QGis::Byte );
498 if ( progressDialog )
502 nParts = nPartsX * nPartsY;
504 progressDialog->
show();
505 progressDialog->
setLabelText(
QObject::tr(
"Reading raster part %1 of %2" ).arg( fileIndex + 1 ).arg( nParts ) );
509 while ( iter->
readNextRasterPart( 1, iterCols, iterRows, &inputBlock, iterLeft, iterTop ) )
516 if ( progressDialog && fileIndex < ( nParts - 1 ) )
518 progressDialog->
setValue( fileIndex + 1 );
519 progressDialog->
setLabelText(
QObject::tr(
"Reading raster part %1 of %2" ).arg( fileIndex + 2 ).arg( nParts ) );
535 for (
qgssize i = 0; i < nPixels; ++i )
537 QRgb c = inputBlock->
color( i );
539 red = qRed( c ); green = qGreen( c ); blue = qBlue( c );
543 double a = alpha / 255.;
544 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 );
549 memcpy((
char* )redData + i, &red, 1 );
550 memcpy((
char* )greenData + i, &green, 1 );
551 memcpy((
char* )blueData + i, &blue, 1 );
552 memcpy((
char* )alphaData + i, &alpha, 1 );
561 nCols, iterCols, iterRows,
562 iterLeft, iterTop, mOutputUrl, fileIndex,
565 if ( partDestProvider )
568 partDestProvider->
write( redData, 1, iterCols, iterRows, 0, 0 );
569 partDestProvider->
write( greenData, 2, iterCols, iterRows, 0, 0 );
570 partDestProvider->
write( blueData, 3, iterCols, iterRows, 0, 0 );
571 partDestProvider->
write( alphaData, 4, iterCols, iterRows, 0, 0 );
573 addToVRT( partFileName( fileIndex ), 1, iterCols, iterRows, iterLeft, iterTop );
574 addToVRT( partFileName( fileIndex ), 2, iterCols, iterRows, iterLeft, iterTop );
575 addToVRT( partFileName( fileIndex ), 3, iterCols, iterRows, iterLeft, iterTop );
576 addToVRT( partFileName( fileIndex ), 4, iterCols, iterRows, iterLeft, iterTop );
577 delete partDestProvider;
580 else if ( destProvider )
582 destProvider->
write( redData, 1, iterCols, iterRows, iterLeft, iterTop );
583 destProvider->
write( greenData, 2, iterCols, iterRows, iterLeft, iterTop );
584 destProvider->
write( blueData, 3, iterCols, iterRows, iterLeft, iterTop );
585 destProvider->
write( alphaData, 4, iterCols, iterRows, iterLeft, iterTop );
596 if ( progressDialog )
603 QString vrtFilePath( mOutputUrl +
"/" + vrtFileName() );
604 writeVRT( vrtFilePath );
607 buildPyramids( vrtFilePath );
614 buildPyramids( mOutputUrl );
620 void QgsRasterFileWriter::addToVRT(
const QString& filename,
int band,
int xSize,
int ySize,
int xOffset,
int yOffset )
628 sourceFilenameElem.
setAttribute(
"relativeToVRT",
"1" );
630 sourceFilenameElem.
appendChild( sourceFilenameText );
631 simpleSourceElem.
appendChild( sourceFilenameElem );
641 sourcePropertiesElem.
setAttribute(
"RasterXSize", xSize );
642 sourcePropertiesElem.
setAttribute(
"RasterYSize", ySize );
643 sourcePropertiesElem.
setAttribute(
"BlockXSize", xSize );
644 sourcePropertiesElem.
setAttribute(
"BlockYSize", ySize );
645 sourcePropertiesElem.
setAttribute(
"DataType",
"Byte" );
646 simpleSourceElem.
appendChild( sourcePropertiesElem );
668 void QgsRasterFileWriter::buildPyramids(
const QString& filename )
670 GDALDatasetH dataSet;
683 overviewList[3] = 16;
684 overviewList[4] = 32;
685 overviewList[5] = 64;
688 if ( mProgressDialog )
693 mProgressDialog->
show();
696 GDALBuildOverviews( dataSet,
"AVERAGE", 6, overviewList, 0, 0, 0, 0 );
700 void QgsRasterFileWriter::buildPyramids(
const QString& filename )
714 if ( ! mPyramidsList.
isEmpty() )
716 for (
int myCounterInt = 0; myCounterInt < myPyramidList.
count(); myCounterInt++ )
718 myPyramidList[myCounterInt].build =
true;
721 QgsDebugMsg(
QString(
"building pyramids : %1 pyramids, %2 resampling, %3 format, %4 options" ).arg( myPyramidList.
count() ).arg( mPyramidsResampling ).
arg( mPyramidsFormat ).
arg( mPyramidsConfigOptions.
count() ) );
724 mPyramidsFormat, mPyramidsConfigOptions );
731 if ( res ==
"ERROR_WRITE_ACCESS" )
733 title =
QObject::tr(
"Building pyramids failed - write access denied" );
734 message =
QObject::tr(
"Write access denied. Adjust the file permissions and try again." );
736 else if ( res ==
"ERROR_WRITE_FORMAT" )
738 title =
QObject::tr(
"Building pyramids failed." );
739 message =
QObject::tr(
"The file was not writable. Some formats do not "
740 "support pyramid overviews. Consult the GDAL documentation if in doubt." );
742 else if ( res ==
"FAILED_NOT_SUPPORTED" )
744 title =
QObject::tr(
"Building pyramids failed." );
745 message =
QObject::tr(
"Building pyramid overviews is not supported on this type of raster." );
747 else if ( res ==
"ERROR_JPEG_COMPRESSION" )
749 title =
QObject::tr(
"Building pyramids failed." );
750 message =
QObject::tr(
"Building internal pyramid overviews is not supported on raster layers with JPEG compression and your current libtiff library." );
752 else if ( res ==
"ERROR_VIRTUAL" )
754 title =
QObject::tr(
"Building pyramids failed." );
755 message =
QObject::tr(
"Building pyramid overviews is not supported on this type of raster." );
764 int QgsRasterFileWriter::pyramidsProgress(
double dfComplete,
const char *pszMessage,
void* pData )
766 Q_UNUSED( pszMessage );
767 GDALTermProgress( dfComplete, 0, 0 );
777 progressDialog->
setValue( dfComplete * 100 );
785 mVRTDocument.
clear();
821 colorInterp <<
"Red" <<
"Green" <<
"Blue" <<
"Alpha";
835 for (
int i = 1; i <= nBands; i++ )
843 if ( mMode ==
Image )
852 if ( !destHasNoDataValueList.
isEmpty() && destHasNoDataValueList.
value( i - 1 ) )
857 mVRTBands.
append( VRTBand );
862 bool QgsRasterFileWriter::writeVRT(
const QString& file )
864 QFile outputFile( file );
865 if ( ! outputFile.open( QIODevice::WriteOnly | QIODevice::Truncate ) )
871 mVRTDocument.
save( outStream, 2 );
876 int iterRows,
int iterLeft,
int iterTop,
const QString& outputUrl,
int fileIndex,
int nBands,
QGis::DataType type,
879 double mup = extent.
width() / nCols;
880 double mapLeft = extent.
xMinimum() + iterLeft * mup;
881 double mapRight = mapLeft + mup * iterCols;
882 double mapTop = extent.
yMaximum() - iterTop * mup;
883 double mapBottom = mapTop - iterRows * mup;
884 QgsRectangle mapRect( mapLeft, mapBottom, mapRight, mapTop );
886 QString outputFile = outputUrl +
"/" + partFileName( fileIndex );
889 double geoTransform[6];
890 geoTransform[0] = mapRect.
xMinimum();
891 geoTransform[1] = mup;
892 geoTransform[2] = 0.0;
893 geoTransform[3] = mapRect.
yMaximum();
894 geoTransform[4] = 0.0;
895 geoTransform[5] = -mup;
911 createVRT( nCols, nRows, crs, geoTransform, type, destHasNoDataValueList, destNoDataValueList );
919 if ( mBuildPyramidsFlag == -4 && mOutputProviderKey ==
"gdal" && mOutputFormat.
toLower() ==
"gtiff" )
920 mCreateOptions <<
"COPY_SRC_OVERVIEWS=YES";
934 void QgsRasterFileWriter::globalOutputParameters(
const QgsRectangle& extent,
int nCols,
int& nRows,
935 double* geoTransform,
double& pixelSize )
937 pixelSize = extent.
width() / nCols;
942 nRows = ( double )nCols / extent.
width() * extent.
height() + 0.5;
944 geoTransform[0] = extent.
xMinimum();
945 geoTransform[1] = pixelSize;
946 geoTransform[2] = 0.0;
947 geoTransform[3] = extent.
yMaximum();
948 geoTransform[4] = 0.0;
949 geoTransform[5] = -( extent.
height() / nRows );
952 QString QgsRasterFileWriter::partFileName(
int fileIndex )
956 return QString(
"%1.%2.tif" ).
arg( outputInfo.fileName() ).arg( fileIndex );
959 QString QgsRasterFileWriter::vrtFileName()
962 return QString(
"%1.vrt" ).
arg( outputInfo.fileName() );
virtual int bandCount() const =0
Get number of bands.
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.
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)
static QgsProviderRegistry * instance(QString pluginPath=QString::null)
means of accessing canonical single instance
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.
double maximumValue
The maximum cell value in the raster band.
QgsRasterInterface * last() const
static double maximumValuePossible(QGis::DataType)
Helper function that returns the maximum possible value for a GDAL data type.
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, QStringList createOptions=QStringList())
Creates a new dataset with mDataSourceURI.
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)
WriterError writeRaster(const QgsRasterPipe *pipe, int nCols, int nRows, QgsRectangle outputExtent, const QgsCoordinateReferenceSystem &crs, QProgressDialog *p=0)
Write raster file.
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.
int maximumTileHeight() const
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)
Base class for processing filters like renderers, reprojector, resampler etc.
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.
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)