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 ) )
498 if ( iterCols <= 5 || iterRows <= 5 )
504 if ( progressDialog && fileIndex < ( nParts - 1 ) )
506 progressDialog->
setValue( fileIndex + 1 );
507 progressDialog->setLabelText(
QObject::tr(
"Reading raster part %1 of %2" ).arg( fileIndex + 2 ).arg( nParts ) );
508 QCoreApplication::processEvents( QEventLoop::AllEvents, 1000 );
509 if ( progressDialog->wasCanceled() )
517 size_t nPixels = ( size_t )iterCols * iterRows;
523 for (
size_t i = 0; i < nPixels; ++i )
525 QRgb c = inputBlock->
color( i );
527 red = qRed( c ); green = qGreen( c ); blue = qBlue( c );
531 double a = alpha / 255.;
532 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 );
537 memcpy((
char* )redData + i, &red, 1 );
538 memcpy((
char* )greenData + i, &green, 1 );
539 memcpy((
char* )blueData + i, &blue, 1 );
540 memcpy((
char* )alphaData + i, &alpha, 1 );
549 nCols, iterCols, iterRows,
553 if ( partDestProvider )
556 partDestProvider->
write( redData, 1, iterCols, iterRows, 0, 0 );
557 partDestProvider->
write( greenData, 2, iterCols, iterRows, 0, 0 );
558 partDestProvider->
write( blueData, 3, iterCols, iterRows, 0, 0 );
559 partDestProvider->
write( alphaData, 4, iterCols, iterRows, 0, 0 );
565 delete partDestProvider;
568 else if ( destProvider )
570 destProvider->
write( redData, 1, iterCols, iterRows, iterLeft, iterTop );
571 destProvider->
write( greenData, 2, iterCols, iterRows, iterLeft, iterTop );
572 destProvider->
write( blueData, 3, iterCols, iterRows, iterLeft, iterTop );
573 destProvider->
write( alphaData, 4, iterCols, iterRows, iterLeft, iterTop );
584 if ( progressDialog )
586 progressDialog->setValue( progressDialog->maximum() );
610 QDomElement bandElem =
mVRTBands.value( band - 1 );
612 QDomElement simpleSourceElem =
mVRTDocument.createElement(
"SimpleSource" );
615 QDomElement sourceFilenameElem =
mVRTDocument.createElement(
"SourceFilename" );
616 sourceFilenameElem.setAttribute(
"relativeToVRT",
"1" );
617 QDomText sourceFilenameText =
mVRTDocument.createTextNode( filename );
618 sourceFilenameElem.appendChild( sourceFilenameText );
619 simpleSourceElem.appendChild( sourceFilenameElem );
622 QDomElement sourceBandElem =
mVRTDocument.createElement(
"SourceBand" );
623 QDomText sourceBandText =
mVRTDocument.createTextNode( QString::number( band ) );
624 sourceBandElem.appendChild( sourceBandText );
625 simpleSourceElem.appendChild( sourceBandElem );
628 QDomElement sourcePropertiesElem =
mVRTDocument.createElement(
"SourceProperties" );
629 sourcePropertiesElem.setAttribute(
"RasterXSize", xSize );
630 sourcePropertiesElem.setAttribute(
"RasterYSize", ySize );
631 sourcePropertiesElem.setAttribute(
"BlockXSize", xSize );
632 sourcePropertiesElem.setAttribute(
"BlockYSize", ySize );
633 sourcePropertiesElem.setAttribute(
"DataType",
"Byte" );
634 simpleSourceElem.appendChild( sourcePropertiesElem );
637 QDomElement srcRectElem =
mVRTDocument.createElement(
"SrcRect" );
638 srcRectElem.setAttribute(
"xOff",
"0" );
639 srcRectElem.setAttribute(
"yOff",
"0" );
640 srcRectElem.setAttribute(
"xSize", xSize );
641 srcRectElem.setAttribute(
"ySize", ySize );
642 simpleSourceElem.appendChild( srcRectElem );
645 QDomElement dstRectElem =
mVRTDocument.createElement(
"DstRect" );
646 dstRectElem.setAttribute(
"xOff", xOffset );
647 dstRectElem.setAttribute(
"yOff", yOffset );
648 dstRectElem.setAttribute(
"xSize", xSize );
649 dstRectElem.setAttribute(
"ySize", ySize );
650 simpleSourceElem.appendChild( dstRectElem );
652 bandElem.appendChild( simpleSourceElem );
658 GDALDatasetH dataSet;
660 dataSet = GDALOpen( filename.toLocal8Bit().data(), GA_Update );
671 overviewList[3] = 16;
672 overviewList[4] = 32;
673 overviewList[5] = 64;
684 GDALBuildOverviews( dataSet,
"AVERAGE", 6, overviewList, 0, 0, 0, 0 );
701 QList< QgsRasterPyramid> myPyramidList;
704 for (
int myCounterInt = 0; myCounterInt < myPyramidList.count(); myCounterInt++ )
706 myPyramidList[myCounterInt].build =
true;
718 QString title, message;
719 if ( res ==
"ERROR_WRITE_ACCESS" )
721 title =
QObject::tr(
"Building pyramids failed - write access denied" );
722 message =
QObject::tr(
"Write access denied. Adjust the file permissions and try again." );
724 else if ( res ==
"ERROR_WRITE_FORMAT" )
726 title =
QObject::tr(
"Building pyramids failed." );
727 message =
QObject::tr(
"The file was not writable. Some formats do not "
728 "support pyramid overviews. Consult the GDAL documentation if in doubt." );
730 else if ( res ==
"FAILED_NOT_SUPPORTED" )
732 title =
QObject::tr(
"Building pyramids failed." );
733 message =
QObject::tr(
"Building pyramid overviews is not supported on this type of raster." );
735 else if ( res ==
"ERROR_JPEG_COMPRESSION" )
737 title =
QObject::tr(
"Building pyramids failed." );
738 message =
QObject::tr(
"Building internal pyramid overviews is not supported on raster layers with JPEG compression and your current libtiff library." );
740 else if ( res ==
"ERROR_VIRTUAL" )
742 title =
QObject::tr(
"Building pyramids failed." );
743 message =
QObject::tr(
"Building pyramid overviews is not supported on this type of raster." );
745 QMessageBox::warning( 0, title, message );
752 int QgsRasterFileWriter::pyramidsProgress(
double dfComplete,
const char *pszMessage,
void* pData )
754 Q_UNUSED( pszMessage );
755 GDALTermProgress( dfComplete, 0, 0 );
756 QProgressDialog* progressDialog =
static_cast<QProgressDialog*
>( pData );
757 if ( pData && progressDialog->wasCanceled() )
764 progressDialog->setRange( 0, 100 );
765 progressDialog->setValue( dfComplete * 100 );
774 QDomElement VRTDatasetElem =
mVRTDocument.createElement(
"VRTDataset" );
777 VRTDatasetElem.setAttribute(
"rasterXSize", xSize );
778 VRTDatasetElem.setAttribute(
"rasterYSize", ySize );
782 QDomElement SRSElem =
mVRTDocument.createElement(
"SRS" );
784 SRSElem.appendChild( crsText );
785 VRTDatasetElem.appendChild( SRSElem );
790 QDomElement geoTransformElem =
mVRTDocument.createElement(
"GeoTransform" );
791 QString geoTransformString = QString::number( geoTransform[0] ) +
", " + QString::number( geoTransform[1] ) +
", " + QString::number( geoTransform[2] ) +
792 ", " + QString::number( geoTransform[3] ) +
", " + QString::number( geoTransform[4] ) +
", " + QString::number( geoTransform[5] );
793 QDomText geoTransformText =
mVRTDocument.createTextNode( geoTransformString );
794 geoTransformElem.appendChild( geoTransformText );
795 VRTDatasetElem.appendChild( geoTransformElem );
808 QStringList colorInterp;
809 colorInterp <<
"Red" <<
"Green" <<
"Blue" <<
"Alpha";
811 QMap<QGis::DataType, QString> dataTypes;
823 for (
int i = 1; i <= nBands; i++ )
825 QDomElement VRTBand =
mVRTDocument.createElement(
"VRTRasterBand" );
827 VRTBand.setAttribute(
"band", QString::number( i ) );
828 QString dataType = dataTypes.value( type );
829 VRTBand.setAttribute(
"dataType", dataType );
833 VRTBand.setAttribute(
"dataType",
"Byte" );
834 QDomElement colorInterpElement =
mVRTDocument.createElement(
"ColorInterp" );
835 QDomText interpText =
mVRTDocument.createTextNode( colorInterp.value( i - 1 ) );
836 colorInterpElement.appendChild( interpText );
837 VRTBand.appendChild( colorInterpElement );
840 if ( !destHasNoDataValueList.isEmpty() && destHasNoDataValueList.value( i - 1 ) )
842 VRTBand.setAttribute(
"NoDataValue", QString::number( destNoDataValueList.value( i - 1 ) ) );
846 VRTDatasetElem.appendChild( VRTBand );
852 QFile outputFile( file );
853 if ( ! outputFile.open( QIODevice::WriteOnly | QIODevice::Truncate ) )
858 QTextStream outStream( &outputFile );
864 int iterRows,
int iterLeft,
int iterTop,
const QString& outputUrl,
int fileIndex,
int nBands,
QGis::DataType type,
867 double mup = extent.
width() / nCols;
868 double mapLeft = extent.
xMinimum() + iterLeft * mup;
869 double mapRight = mapLeft + mup * iterCols;
870 double mapTop = extent.
yMaximum() - iterTop * mup;
871 double mapBottom = mapTop - iterRows * mup;
872 QgsRectangle mapRect( mapLeft, mapBottom, mapRight, mapTop );
874 QString outputFile = outputUrl +
"/" +
partFileName( fileIndex );
877 double geoTransform[6];
878 geoTransform[0] = mapRect.
xMinimum();
879 geoTransform[1] = mup;
880 geoTransform[2] = 0.0;
881 geoTransform[3] = mapRect.
yMaximum();
882 geoTransform[4] = 0.0;
883 geoTransform[5] = -mup;
895 QList<bool> destHasNoDataValueList, QList<double> destNoDataValueList )
899 createVRT( nCols, nRows, crs, geoTransform, type, destHasNoDataValueList, destNoDataValueList );
923 double* geoTransform,
double& pixelSize )
925 pixelSize = extent.
width() / nCols;
930 nRows = ( double )nCols / extent.
width() * extent.
height() + 0.5;
932 geoTransform[0] = extent.
xMinimum();
933 geoTransform[1] = pixelSize;
934 geoTransform[2] = 0.0;
935 geoTransform[3] = extent.
yMaximum();
936 geoTransform[4] = 0.0;
937 geoTransform[5] = -( extent.
height() / nRows );
944 return QString(
"%1.%2.tif" ).arg( outputInfo.fileName() ).arg( fileIndex );
950 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
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()
Returns the formats supported by create()
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.