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 )
100 mProgressDialog = progressDialog;
119 if ( mMode ==
Image )
121 WriterError e = writeImageRaster( &iter, nCols, nRows, outputExtent, crs, progressDialog );
128 WriterError e = writeDataRaster( pipe, &iter, nCols, nRows, outputExtent, crs, progressDialog );
168 for (
int i = 2; i <= nBands; ++i )
183 for (
int bandNo = 1; bandNo <= nBands; bandNo++ )
188 bool destHasNoDataValue =
false;
189 double destNoDataValue = std::numeric_limits<double>::quiet_NaN();
193 if ( srcHasNoDataValue )
198 destHasNoDataValue =
true;
200 else if ( nuller && nuller->
noData( bandNo ).
size() > 0 )
203 destNoDataValue = nuller->
noData( bandNo ).
value( 0 ).min();
204 destHasNoDataValue =
true;
211 if ( projector && projector->
destCrs() != projector->
srcCrs() )
214 srcExtent = ct.transformBoundingBox( outputExtent );
227 destNoDataValue = typeMinValue;
231 destNoDataValue = typeMaxValue;
238 destHasNoDataValue =
true;
242 if ( nuller && destHasNoDataValue )
247 QgsDebugMsg(
QString(
"bandNo = %1 destDataType = %2 destHasNoDataValue = %3 destNoDataValue = %4" ).arg( bandNo ).arg( destDataType ).arg( destHasNoDataValue ).arg( destNoDataValue ) );
248 destDataTypeList.
append( destDataType );
249 destHasNoDataValueList.
append( destHasNoDataValue );
250 destNoDataValueList.
append( destNoDataValue );
255 for (
int i = 1; i < nBands; i++ )
257 if ( destDataTypeList.
value( i ) > destDataType )
259 destDataType = destDataTypeList.
value( i );
267 double geoTransform[6];
268 globalOutputParameters( outputExtent, nCols, nRows, geoTransform, pixelSize );
271 destProvider = initOutput( nCols, nRows, crs, geoTransform, nBands, destDataType, destHasNoDataValueList, destNoDataValueList );
273 WriterError error = writeDataRaster( pipe, iter, nCols, nRows, outputExtent, crs, destDataType, destHasNoDataValueList, destNoDataValueList, destProvider, progressDialog );
290 for (
int i = 0; i < nBands; i++ )
292 double destNoDataValue;
294 destDataTypeList.
replace( i, destDataType );
295 destNoDataValueList.
replace( i, destNoDataValue );
297 destDataType = destDataTypeList.
value( 0 );
300 destProvider = initOutput( nCols, nRows, crs, geoTransform, nBands, destDataType, destHasNoDataValueList, destNoDataValueList );
301 error = writeDataRaster( pipe, iter, nCols, nRows, outputExtent, crs, destDataType, destHasNoDataValueList, destNoDataValueList, destProvider, progressDialog );
313 int nCols,
int nRows,
323 Q_UNUSED( destHasNoDataValueList );
339 for (
int i = 1; i <= nBands; ++i )
351 if ( progressDialog )
355 nParts = nPartsX * nPartsY;
357 progressDialog->
show();
358 progressDialog->
setLabelText(
QObject::tr(
"Reading raster part %1 of %2" ).arg( fileIndex + 1 ).arg( nParts ) );
365 for (
int i = 1; i <= nBands; ++i )
367 if ( !iter->
readNextRasterPart( i, iterCols, iterRows, &( blockList[i - 1] ), iterLeft, iterTop ) )
372 QString vrtFilePath( mOutputUrl +
"/" + vrtFileName() );
373 writeVRT( vrtFilePath );
376 buildPyramids( vrtFilePath );
383 buildPyramids( mOutputUrl );
393 if ( progressDialog && fileIndex < ( nParts - 1 ) )
395 progressDialog->
setValue( fileIndex + 1 );
396 progressDialog->
setLabelText(
QObject::tr(
"Reading raster part %1 of %2" ).arg( fileIndex + 2 ).arg( nParts ) );
400 for (
int i = 0; i < nBands; ++i )
410 for (
int i = 1; i <= nBands; ++i )
412 if ( srcProvider && srcProvider->
dataType( i ) == destDataType )
414 destBlockList.
push_back( blockList[i-1] );
419 blockList[i-1]->convert( destDataType );
420 destBlockList.
push_back( blockList[i-1] );
428 nCols, iterCols, iterRows,
429 iterLeft, iterTop, mOutputUrl,
430 fileIndex, nBands, destDataType, crs );
432 if ( partDestProvider )
435 for (
int i = 1; i <= nBands; ++i )
438 partDestProvider->
write( destBlockList[i - 1]->bits( 0 ), i, iterCols, iterRows, 0, 0 );
439 delete destBlockList[i - 1];
440 addToVRT( partFileName( fileIndex ), i, iterCols, iterRows, iterLeft, iterTop );
442 delete partDestProvider;
445 else if ( destProvider )
448 for (
int i = 1; i <= nBands; ++i )
450 destProvider->
write( destBlockList[i - 1]->bits( 0 ), i, iterCols, iterRows, iterLeft, iterTop );
451 delete destBlockList[i - 1];
483 void* redData =
qgsMalloc( mMaxTileWidth * mMaxTileHeight );
484 void* greenData =
qgsMalloc( mMaxTileWidth * mMaxTileHeight );
485 void* blueData =
qgsMalloc( mMaxTileWidth * mMaxTileHeight );
486 void* alphaData =
qgsMalloc( mMaxTileWidth * mMaxTileHeight );
488 int iterLeft = 0, iterTop = 0, iterCols = 0, iterRows = 0;
494 double geoTransform[6];
495 globalOutputParameters( outputExtent, nCols, nRows, geoTransform, pixelSize );
497 destProvider = initOutput( nCols, nRows, crs, geoTransform, 4,
QGis::Byte );
502 if ( progressDialog )
506 nParts = nPartsX * nPartsY;
508 progressDialog->
show();
509 progressDialog->
setLabelText(
QObject::tr(
"Reading raster part %1 of %2" ).arg( fileIndex + 1 ).arg( nParts ) );
513 while ( iter->
readNextRasterPart( 1, iterCols, iterRows, &inputBlock, iterLeft, iterTop ) )
520 if ( progressDialog && fileIndex < ( nParts - 1 ) )
522 progressDialog->
setValue( fileIndex + 1 );
523 progressDialog->
setLabelText(
QObject::tr(
"Reading raster part %1 of %2" ).arg( fileIndex + 2 ).arg( nParts ) );
539 for (
qgssize i = 0; i < nPixels; ++i )
541 QRgb c = inputBlock->
color( i );
543 red = qRed( c ); green = qGreen( c ); blue = qBlue( c );
547 double a = alpha / 255.;
548 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 );
553 memcpy((
char* )redData + i, &red, 1 );
554 memcpy((
char* )greenData + i, &green, 1 );
555 memcpy((
char* )blueData + i, &blue, 1 );
556 memcpy((
char* )alphaData + i, &alpha, 1 );
565 nCols, iterCols, iterRows,
566 iterLeft, iterTop, mOutputUrl, fileIndex,
569 if ( partDestProvider )
572 partDestProvider->
write( redData, 1, iterCols, iterRows, 0, 0 );
573 partDestProvider->
write( greenData, 2, iterCols, iterRows, 0, 0 );
574 partDestProvider->
write( blueData, 3, iterCols, iterRows, 0, 0 );
575 partDestProvider->
write( alphaData, 4, iterCols, iterRows, 0, 0 );
577 addToVRT( partFileName( fileIndex ), 1, iterCols, iterRows, iterLeft, iterTop );
578 addToVRT( partFileName( fileIndex ), 2, iterCols, iterRows, iterLeft, iterTop );
579 addToVRT( partFileName( fileIndex ), 3, iterCols, iterRows, iterLeft, iterTop );
580 addToVRT( partFileName( fileIndex ), 4, iterCols, iterRows, iterLeft, iterTop );
581 delete partDestProvider;
584 else if ( destProvider )
586 destProvider->
write( redData, 1, iterCols, iterRows, iterLeft, iterTop );
587 destProvider->
write( greenData, 2, iterCols, iterRows, iterLeft, iterTop );
588 destProvider->
write( blueData, 3, iterCols, iterRows, iterLeft, iterTop );
589 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 QgsDebugMsg(
QString(
"building pyramids : %1 pyramids, %2 resampling, %3 format, %4 options" ).arg( myPyramidList.
count() ).arg( mPyramidsResampling ).
arg( mPyramidsFormat ).
arg( mPyramidsConfigOptions.
count() ) );
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 = ( 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 )
960 return QString(
"%1.%2.tif" ).
arg( outputInfo.fileName() ).arg( fileIndex );
963 QString QgsRasterFileWriter::vrtFileName()
966 return QString(
"%1.vrt" ).
arg( outputInfo.fileName() );
virtual int bandCount() const =0
Get number of bands.
Sixty four bit floating point (double)
Sixteen bit signed integer (qint16)
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)
Eight bit unsigned integer (quint8)
double yMaximum() const
Get the y maximum value (top side of rectangle)
Sixteen bit unsigned integer (quint16)
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
A helper to get an wkt representation of this srs.
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.
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)
Thirty two bit floating point (float)
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)
DataType
Raster data types.
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)
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)
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32.
double width() const
Width of the rectangle.
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32_Premultiplied.
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
Thirty two bit unsigned integer (quint32)
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)