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 ) )
503 if ( progressDialog && fileIndex < ( nParts - 1 ) )
505 progressDialog->
setValue( fileIndex + 1 );
506 progressDialog->setLabelText(
QObject::tr(
"Reading raster part %1 of %2" ).arg( fileIndex + 2 ).arg( nParts ) );
507 QCoreApplication::processEvents( QEventLoop::AllEvents, 1000 );
508 if ( progressDialog->wasCanceled() )
522 for (
qgssize i = 0; i < nPixels; ++i )
524 QRgb c = inputBlock->
color( i );
526 red = qRed( c ); green = qGreen( c ); blue = qBlue( c );
530 double a = alpha / 255.;
531 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 );
536 memcpy((
char* )redData + i, &red, 1 );
537 memcpy((
char* )greenData + i, &green, 1 );
538 memcpy((
char* )blueData + i, &blue, 1 );
539 memcpy((
char* )alphaData + i, &alpha, 1 );
548 nCols, iterCols, iterRows,
552 if ( partDestProvider )
555 partDestProvider->
write( redData, 1, iterCols, iterRows, 0, 0 );
556 partDestProvider->
write( greenData, 2, iterCols, iterRows, 0, 0 );
557 partDestProvider->
write( blueData, 3, iterCols, iterRows, 0, 0 );
558 partDestProvider->
write( alphaData, 4, iterCols, iterRows, 0, 0 );
564 delete partDestProvider;
567 else if ( destProvider )
569 destProvider->
write( redData, 1, iterCols, iterRows, iterLeft, iterTop );
570 destProvider->
write( greenData, 2, iterCols, iterRows, iterLeft, iterTop );
571 destProvider->
write( blueData, 3, iterCols, iterRows, iterLeft, iterTop );
572 destProvider->
write( alphaData, 4, iterCols, iterRows, iterLeft, iterTop );
583 if ( progressDialog )
585 progressDialog->setValue( progressDialog->maximum() );
609 QDomElement bandElem =
mVRTBands.value( band - 1 );
611 QDomElement simpleSourceElem =
mVRTDocument.createElement(
"SimpleSource" );
614 QDomElement sourceFilenameElem =
mVRTDocument.createElement(
"SourceFilename" );
615 sourceFilenameElem.setAttribute(
"relativeToVRT",
"1" );
616 QDomText sourceFilenameText =
mVRTDocument.createTextNode( filename );
617 sourceFilenameElem.appendChild( sourceFilenameText );
618 simpleSourceElem.appendChild( sourceFilenameElem );
621 QDomElement sourceBandElem =
mVRTDocument.createElement(
"SourceBand" );
622 QDomText sourceBandText =
mVRTDocument.createTextNode( QString::number( band ) );
623 sourceBandElem.appendChild( sourceBandText );
624 simpleSourceElem.appendChild( sourceBandElem );
627 QDomElement sourcePropertiesElem =
mVRTDocument.createElement(
"SourceProperties" );
628 sourcePropertiesElem.setAttribute(
"RasterXSize", xSize );
629 sourcePropertiesElem.setAttribute(
"RasterYSize", ySize );
630 sourcePropertiesElem.setAttribute(
"BlockXSize", xSize );
631 sourcePropertiesElem.setAttribute(
"BlockYSize", ySize );
632 sourcePropertiesElem.setAttribute(
"DataType",
"Byte" );
633 simpleSourceElem.appendChild( sourcePropertiesElem );
636 QDomElement srcRectElem =
mVRTDocument.createElement(
"SrcRect" );
637 srcRectElem.setAttribute(
"xOff",
"0" );
638 srcRectElem.setAttribute(
"yOff",
"0" );
639 srcRectElem.setAttribute(
"xSize", xSize );
640 srcRectElem.setAttribute(
"ySize", ySize );
641 simpleSourceElem.appendChild( srcRectElem );
644 QDomElement dstRectElem =
mVRTDocument.createElement(
"DstRect" );
645 dstRectElem.setAttribute(
"xOff", xOffset );
646 dstRectElem.setAttribute(
"yOff", yOffset );
647 dstRectElem.setAttribute(
"xSize", xSize );
648 dstRectElem.setAttribute(
"ySize", ySize );
649 simpleSourceElem.appendChild( dstRectElem );
651 bandElem.appendChild( simpleSourceElem );
657 GDALDatasetH dataSet;
659 dataSet = GDALOpen( filename.toLocal8Bit().data(), GA_Update );
670 overviewList[3] = 16;
671 overviewList[4] = 32;
672 overviewList[5] = 64;
683 GDALBuildOverviews( dataSet,
"AVERAGE", 6, overviewList, 0, 0, 0, 0 );
700 QList< QgsRasterPyramid> myPyramidList;
703 for (
int myCounterInt = 0; myCounterInt < myPyramidList.count(); myCounterInt++ )
705 myPyramidList[myCounterInt].build =
true;
717 QString title, message;
718 if ( res ==
"ERROR_WRITE_ACCESS" )
720 title =
QObject::tr(
"Building pyramids failed - write access denied" );
721 message =
QObject::tr(
"Write access denied. Adjust the file permissions and try again." );
723 else if ( res ==
"ERROR_WRITE_FORMAT" )
725 title =
QObject::tr(
"Building pyramids failed." );
726 message =
QObject::tr(
"The file was not writable. Some formats do not "
727 "support pyramid overviews. Consult the GDAL documentation if in doubt." );
729 else if ( res ==
"FAILED_NOT_SUPPORTED" )
731 title =
QObject::tr(
"Building pyramids failed." );
732 message =
QObject::tr(
"Building pyramid overviews is not supported on this type of raster." );
734 else if ( res ==
"ERROR_JPEG_COMPRESSION" )
736 title =
QObject::tr(
"Building pyramids failed." );
737 message =
QObject::tr(
"Building internal pyramid overviews is not supported on raster layers with JPEG compression and your current libtiff library." );
739 else if ( res ==
"ERROR_VIRTUAL" )
741 title =
QObject::tr(
"Building pyramids failed." );
742 message =
QObject::tr(
"Building pyramid overviews is not supported on this type of raster." );
744 QMessageBox::warning( 0, title, message );
751 int QgsRasterFileWriter::pyramidsProgress(
double dfComplete,
const char *pszMessage,
void* pData )
753 Q_UNUSED( pszMessage );
754 GDALTermProgress( dfComplete, 0, 0 );
755 QProgressDialog* progressDialog =
static_cast<QProgressDialog*
>( pData );
756 if ( pData && progressDialog->wasCanceled() )
763 progressDialog->setRange( 0, 100 );
764 progressDialog->setValue( dfComplete * 100 );
773 QDomElement VRTDatasetElem =
mVRTDocument.createElement(
"VRTDataset" );
776 VRTDatasetElem.setAttribute(
"rasterXSize", xSize );
777 VRTDatasetElem.setAttribute(
"rasterYSize", ySize );
781 QDomElement SRSElem =
mVRTDocument.createElement(
"SRS" );
783 SRSElem.appendChild( crsText );
784 VRTDatasetElem.appendChild( SRSElem );
789 QDomElement geoTransformElem =
mVRTDocument.createElement(
"GeoTransform" );
790 QString geoTransformString = QString::number( geoTransform[0] ) +
", " + QString::number( geoTransform[1] ) +
", " + QString::number( geoTransform[2] ) +
791 ", " + QString::number( geoTransform[3] ) +
", " + QString::number( geoTransform[4] ) +
", " + QString::number( geoTransform[5] );
792 QDomText geoTransformText =
mVRTDocument.createTextNode( geoTransformString );
793 geoTransformElem.appendChild( geoTransformText );
794 VRTDatasetElem.appendChild( geoTransformElem );
807 QStringList colorInterp;
808 colorInterp <<
"Red" <<
"Green" <<
"Blue" <<
"Alpha";
810 QMap<QGis::DataType, QString> dataTypes;
822 for (
int i = 1; i <= nBands; i++ )
824 QDomElement VRTBand =
mVRTDocument.createElement(
"VRTRasterBand" );
826 VRTBand.setAttribute(
"band", QString::number( i ) );
827 QString dataType = dataTypes.value( type );
828 VRTBand.setAttribute(
"dataType", dataType );
832 VRTBand.setAttribute(
"dataType",
"Byte" );
833 QDomElement colorInterpElement =
mVRTDocument.createElement(
"ColorInterp" );
834 QDomText interpText =
mVRTDocument.createTextNode( colorInterp.value( i - 1 ) );
835 colorInterpElement.appendChild( interpText );
836 VRTBand.appendChild( colorInterpElement );
839 if ( !destHasNoDataValueList.isEmpty() && destHasNoDataValueList.value( i - 1 ) )
841 VRTBand.setAttribute(
"NoDataValue", QString::number( destNoDataValueList.value( i - 1 ) ) );
845 VRTDatasetElem.appendChild( VRTBand );
851 QFile outputFile( file );
852 if ( ! outputFile.open( QIODevice::WriteOnly | QIODevice::Truncate ) )
857 QTextStream outStream( &outputFile );
863 int iterRows,
int iterLeft,
int iterTop,
const QString& outputUrl,
int fileIndex,
int nBands,
QGis::DataType type,
866 double mup = extent.
width() / nCols;
867 double mapLeft = extent.
xMinimum() + iterLeft * mup;
868 double mapRight = mapLeft + mup * iterCols;
869 double mapTop = extent.
yMaximum() - iterTop * mup;
870 double mapBottom = mapTop - iterRows * mup;
871 QgsRectangle mapRect( mapLeft, mapBottom, mapRight, mapTop );
873 QString outputFile = outputUrl +
"/" +
partFileName( fileIndex );
876 double geoTransform[6];
877 geoTransform[0] = mapRect.
xMinimum();
878 geoTransform[1] = mup;
879 geoTransform[2] = 0.0;
880 geoTransform[3] = mapRect.
yMaximum();
881 geoTransform[4] = 0.0;
882 geoTransform[5] = -mup;
894 QList<bool> destHasNoDataValueList, QList<double> destNoDataValueList )
898 createVRT( nCols, nRows, crs, geoTransform, type, destHasNoDataValueList, destNoDataValueList );
922 double* geoTransform,
double& pixelSize )
924 pixelSize = extent.
width() / nCols;
929 nRows = ( double )nCols / extent.
width() * extent.
height() + 0.5;
931 geoTransform[0] = extent.
xMinimum();
932 geoTransform[1] = pixelSize;
933 geoTransform[2] = 0.0;
934 geoTransform[3] = extent.
yMaximum();
935 geoTransform[4] = 0.0;
936 geoTransform[5] = -( extent.
height() / nRows );
943 return QString(
"%1.%2.tif" ).arg( outputInfo.fileName() ).arg( fileIndex );
949 return QString(
"%1.vrt" ).arg( outputInfo.fileName() );
QList< QDomElement > mVRTBands
virtual int bandCount() const =0
Get number of bands.
A rectangle specified with double values.
QgsRaster::RasterBuildPyramids mBuildPyramidsFlag
bool mTiledMode
False: Write one file, true: create a directory and add the files numbered.
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.
void startRasterRead(int bandNumber, int nCols, int nRows, const QgsRectangle &extent)
Start reading of raster band.
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)
bool setValue(int row, int column, double value)
Set value on position.
QString mOutputProviderKey
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.
const QgsRasterPipe * mPipe
bool writeVRT(const QString &file)
int maximumTileWidth() const
virtual QgsRasterBandStats bandStatistics(int theBandNo, int theStats=QgsRasterBandStats::All, const QgsRectangle &theExtent=QgsRectangle(), int theSampleSize=0)
Get band statistics.
static QGis::DataType typeWithNoDataValue(QGis::DataType dataType, double *noDataValue)
For given data type returns wider type and sets no data value.
QString partFileName(int fileIndex)
The RasterBandStats struct is a container for statistics about a single raster band.
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 QList< QgsRasterPyramid > buildPyramidList(QList< int > overviewList=QList< int >())
Accessor for ths raster layers pyramid list.
virtual QGis::DataType srcDataType(int bandNo) const =0
Returns source data type for the band specified by number, source data type may be shorter than dataT...
virtual QgsRectangle extent()=0
Get the extent of the data source.
QDomDocument mVRTDocument
static bool typeIsColor(QGis::DataType type)
Returns true if data type is color.
void buildPyramids(const QString &filename)
virtual QGis::DataType dataType(int bandNo) const =0
Returns data type for the band specified by number.
QgsRaster::RasterPyramidsFormat mPyramidsFormat
int maximumTileHeight() const
static int typeSize(int dataType)
QgsRasterProjector * projector() const
QgsCoordinateReferenceSystem destCrs() const
Get destination CRS.
QgsRasterDataProvider * initOutput(int nCols, int nRows, const QgsCoordinateReferenceSystem &crs, double *geoTransform, int nBands, QGis::DataType type, QList< bool > destHasNoDataValueList=QList< bool >(), QList< double > destNoDataValueList=QList< double >())
Init VRT (for tiled mode) or create global output provider (single-file mode)
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...
Base class for processing filters like renderers, reprojector, resampler etc.
WriterError writeDataRaster(const QgsRasterPipe *pipe, QgsRasterIterator *iter, int nCols, int nRows, const QgsRectangle &outputExtent, const QgsCoordinateReferenceSystem &crs, QProgressDialog *progressDialog=0)
const QgsRasterInterface * mInput
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...
QProgressDialog * mProgressDialog
QStringList mCreateOptions
void setOutputNoDataValue(int bandNo, double noData)
Set output no data value.
QString mPyramidsResampling
void setMaximumTileWidth(int w)
WriterError writeImageRaster(QgsRasterIterator *iter, int nCols, int nRows, const QgsRectangle &outputExtent, const QgsCoordinateReferenceSystem &crs, QProgressDialog *progressDialog=0)
void setMaximumTileHeight(int h)
QList< int > mPyramidsList
QgsCoordinateReferenceSystem srcCrs() const
Get source CRS.
QgsRasterRangeList noData(int bandNo) const
virtual bool remove()
Remove dataset.
void createVRT(int xSize, int ySize, const QgsCoordinateReferenceSystem &crs, double *geoTransform, QGis::DataType type, QList< bool > destHasNoDataValueList, QList< double > destNoDataValueList)
Initialize vrt member variables.
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.
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
QRgb color(int row, int column) const
Read a single color.
void globalOutputParameters(const QgsRectangle &extent, int nCols, int &nRows, double *geoTransform, double &pixelSize)
Calculate nRows, geotransform and pixel size for output.
void addToVRT(const QString &filename, int band, int xSize, int ySize, int xOffset, int yOffset)
double width() const
Width of the rectangle.
QgsRasterDataProvider * createPartProvider(const QgsRectangle &extent, int nCols, int iterCols, int iterRows, int iterLeft, int iterTop, const QString &outputUrl, int fileIndex, int nBands, QGis::DataType type, const QgsCoordinateReferenceSystem &crs)
Create provider and datasource for a part image (vrt mode)
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.
QStringList mPyramidsConfigOptions
Base class for raster data providers.