24 #include <QCoreApplication> 25 #include <QProgressDialog> 26 #include <QTextStream> 27 #include <QMessageBox> 31 , mOutputUrl( outputUrl )
32 , mOutputProviderKey(
"gdal" )
33 , mOutputFormat(
"GTiff" )
35 , mMaxTileWidth( 500 )
36 , mMaxTileHeight( 500 )
37 , mBuildPyramidsFlag(
QgsRaster::PyramidsFlagNo )
38 , mPyramidsFormat(
QgsRaster::PyramidsGTiff )
39 , mProgressDialog( nullptr )
48 , mOutputProviderKey(
"gdal" )
49 , mOutputFormat(
"GTiff" )
51 , mMaxTileWidth( 500 )
52 , mMaxTileHeight( 500 )
55 , mProgressDialog(
nullptr )
102 mProgressDialog = progressDialog;
121 if ( mMode ==
Image )
123 WriterError e = writeImageRaster( &iter, nCols, nRows, outputExtent, crs, progressDialog );
124 mProgressDialog =
nullptr;
129 mProgressDialog =
nullptr;
130 WriterError e = writeDataRaster( pipe, &iter, nCols, nRows, outputExtent, crs, progressDialog );
170 for (
int i = 2; i <= nBands; ++i )
185 for (
int bandNo = 1; bandNo <= nBands; bandNo++ )
190 bool destHasNoDataValue =
false;
191 double destNoDataValue = std::numeric_limits<double>::quiet_NaN();
195 if ( srcHasNoDataValue )
200 destHasNoDataValue =
true;
205 destNoDataValue = nuller->
noData( bandNo ).
value( 0 ).min();
206 destHasNoDataValue =
true;
213 if ( projector && projector->
destCrs() != projector->
srcCrs() )
216 srcExtent = ct.transformBoundingBox( outputExtent );
229 destNoDataValue = typeMinValue;
233 destNoDataValue = typeMaxValue;
240 destHasNoDataValue =
true;
244 if ( nuller && destHasNoDataValue )
249 QgsDebugMsgLevel(
QString(
"bandNo = %1 destDataType = %2 destHasNoDataValue = %3 destNoDataValue = %4" ).arg( bandNo ).arg( destDataType ).arg( destHasNoDataValue ).arg( destNoDataValue ), 4 );
250 destDataTypeList.
append( destDataType );
251 destHasNoDataValueList.
append( destHasNoDataValue );
252 destNoDataValueList.
append( destNoDataValue );
257 for (
int i = 1; i < nBands; i++ )
259 if ( destDataTypeList.
value( i ) > destDataType )
261 destDataType = destDataTypeList.
value( i );
269 double geoTransform[6];
270 globalOutputParameters( outputExtent, nCols, nRows, geoTransform, pixelSize );
273 destProvider = initOutput( nCols, nRows, crs, geoTransform, nBands, destDataType, destHasNoDataValueList, destNoDataValueList );
275 WriterError error = writeDataRaster( pipe, iter, nCols, nRows, outputExtent, crs, destDataType, destHasNoDataValueList, destNoDataValueList, destProvider, progressDialog );
284 destProvider =
nullptr;
292 for (
int i = 0; i < nBands; i++ )
294 double destNoDataValue;
296 destDataTypeList.
replace( i, destDataType );
297 destNoDataValueList.
replace( i, destNoDataValue );
299 destDataType = destDataTypeList.
value( 0 );
302 destProvider = initOutput( nCols, nRows, crs, geoTransform, nBands, destDataType, destHasNoDataValueList, destNoDataValueList );
303 error = writeDataRaster( pipe, iter, nCols, nRows, outputExtent, crs, destDataType, destHasNoDataValueList, destNoDataValueList, destProvider, progressDialog );
315 int nCols,
int nRows,
325 Q_UNUSED( destHasNoDataValueList );
341 for (
int i = 1; i <= nBands; ++i )
345 if ( destProvider && destHasNoDataValueList.
value( i - 1 ) )
353 if ( progressDialog )
357 nParts = nPartsX * nPartsY;
359 progressDialog->
show();
360 progressDialog->
setLabelText(
QObject::tr(
"Reading raster part %1 of %2" ).arg( fileIndex + 1 ).arg( nParts ) );
367 for (
int i = 1; i <= nBands; ++i )
369 if ( !iter->
readNextRasterPart( i, iterCols, iterRows, &( blockList[i - 1] ), iterLeft, iterTop ) )
374 QString vrtFilePath( mOutputUrl +
'/' + vrtFileName() );
375 writeVRT( vrtFilePath );
378 buildPyramids( vrtFilePath );
385 buildPyramids( mOutputUrl );
395 if ( progressDialog && fileIndex < ( nParts - 1 ) )
397 progressDialog->
setValue( fileIndex + 1 );
398 progressDialog->
setLabelText(
QObject::tr(
"Reading raster part %1 of %2" ).arg( fileIndex + 2 ).arg( nParts ) );
402 for (
int i = 0; i < nBands; ++i )
412 for (
int i = 1; i <= nBands; ++i )
414 if ( srcProvider && srcProvider->
dataType( i ) == destDataType )
416 destBlockList.
push_back( blockList[i-1] );
421 blockList[i-1]->convert( destDataType );
422 destBlockList.
push_back( blockList[i-1] );
424 blockList[i-1] =
nullptr;
430 nCols, iterCols, iterRows,
431 iterLeft, iterTop, mOutputUrl,
432 fileIndex, nBands, destDataType, crs );
434 if ( partDestProvider )
437 for (
int i = 1; i <= nBands; ++i )
439 if ( destHasNoDataValueList.
value( i - 1 ) )
443 partDestProvider->
write( destBlockList[i - 1]->bits( 0 ), i, iterCols, iterRows, 0, 0 );
444 delete destBlockList[i - 1];
445 addToVRT( partFileName( fileIndex ), i, iterCols, iterRows, iterLeft, iterTop );
447 delete partDestProvider;
450 else if ( destProvider )
453 for (
int i = 1; i <= nBands; ++i )
455 destProvider->
write( destBlockList[i - 1]->bits( 0 ), i, iterCols, iterRows, iterLeft, iterTop );
456 delete destBlockList[i - 1];
488 void* redData =
qgsMalloc( mMaxTileWidth * mMaxTileHeight );
489 void* greenData =
qgsMalloc( mMaxTileWidth * mMaxTileHeight );
490 void* blueData =
qgsMalloc( mMaxTileWidth * mMaxTileHeight );
491 void* alphaData =
qgsMalloc( mMaxTileWidth * mMaxTileHeight );
493 int iterLeft = 0, iterTop = 0, iterCols = 0, iterRows = 0;
499 double geoTransform[6];
500 globalOutputParameters( outputExtent, nCols, nRows, geoTransform, pixelSize );
502 destProvider = initOutput( nCols, nRows, crs, geoTransform, 4,
QGis::Byte );
507 if ( progressDialog )
511 nParts = nPartsX * nPartsY;
513 progressDialog->
show();
514 progressDialog->
setLabelText(
QObject::tr(
"Reading raster part %1 of %2" ).arg( fileIndex + 1 ).arg( nParts ) );
518 while ( iter->
readNextRasterPart( 1, iterCols, iterRows, &inputBlock, iterLeft, iterTop ) )
525 if ( progressDialog && fileIndex < ( nParts - 1 ) )
527 progressDialog->
setValue( fileIndex + 1 );
528 progressDialog->
setLabelText(
QObject::tr(
"Reading raster part %1 of %2" ).arg( fileIndex + 2 ).arg( nParts ) );
544 for (
qgssize i = 0; i < nPixels; ++i )
546 QRgb c = inputBlock->
color( i );
554 double a = alpha / 255.;
555 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 );
560 memcpy( reinterpret_cast< char* >( redData ) + i, &red, 1 );
561 memcpy( reinterpret_cast< char* >( greenData ) + i, &green, 1 );
562 memcpy( reinterpret_cast< char* >( blueData ) + i, &blue, 1 );
563 memcpy( reinterpret_cast< char* >( alphaData ) + i, &alpha, 1 );
572 nCols, iterCols, iterRows,
573 iterLeft, iterTop, mOutputUrl, fileIndex,
576 if ( partDestProvider )
579 partDestProvider->
write( redData, 1, iterCols, iterRows, 0, 0 );
580 partDestProvider->
write( greenData, 2, iterCols, iterRows, 0, 0 );
581 partDestProvider->
write( blueData, 3, iterCols, iterRows, 0, 0 );
582 partDestProvider->
write( alphaData, 4, iterCols, iterRows, 0, 0 );
584 addToVRT( partFileName( fileIndex ), 1, iterCols, iterRows, iterLeft, iterTop );
585 addToVRT( partFileName( fileIndex ), 2, iterCols, iterRows, iterLeft, iterTop );
586 addToVRT( partFileName( fileIndex ), 3, iterCols, iterRows, iterLeft, iterTop );
587 addToVRT( partFileName( fileIndex ), 4, iterCols, iterRows, iterLeft, iterTop );
588 delete partDestProvider;
591 else if ( destProvider )
593 destProvider->
write( redData, 1, iterCols, iterRows, iterLeft, iterTop );
594 destProvider->
write( greenData, 2, iterCols, iterRows, iterLeft, iterTop );
595 destProvider->
write( blueData, 3, iterCols, iterRows, iterLeft, iterTop );
596 destProvider->
write( alphaData, 4, iterCols, iterRows, iterLeft, iterTop );
610 if ( progressDialog )
617 QString vrtFilePath( mOutputUrl +
'/' + vrtFileName() );
618 writeVRT( vrtFilePath );
621 buildPyramids( vrtFilePath );
628 buildPyramids( mOutputUrl );
634 void QgsRasterFileWriter::addToVRT(
const QString& filename,
int band,
int xSize,
int ySize,
int xOffset,
int yOffset )
642 sourceFilenameElem.
setAttribute(
"relativeToVRT",
"1" );
644 sourceFilenameElem.
appendChild( sourceFilenameText );
645 simpleSourceElem.
appendChild( sourceFilenameElem );
655 sourcePropertiesElem.
setAttribute(
"RasterXSize", xSize );
656 sourcePropertiesElem.
setAttribute(
"RasterYSize", ySize );
657 sourcePropertiesElem.
setAttribute(
"BlockXSize", xSize );
658 sourcePropertiesElem.
setAttribute(
"BlockYSize", ySize );
659 sourcePropertiesElem.
setAttribute(
"DataType",
"Byte" );
660 simpleSourceElem.
appendChild( sourcePropertiesElem );
682 void QgsRasterFileWriter::buildPyramids(
const QString& filename )
697 overviewList[3] = 16;
698 overviewList[4] = 32;
699 overviewList[5] = 64;
702 if ( mProgressDialog )
707 mProgressDialog->
show();
710 GDALBuildOverviews( dataSet,
"AVERAGE", 6, overviewList, 0, 0, 0, 0 );
714 void QgsRasterFileWriter::buildPyramids(
const QString& filename )
728 if ( ! mPyramidsList.
isEmpty() )
730 for (
int myCounterInt = 0; myCounterInt < myPyramidList.
count(); myCounterInt++ )
732 myPyramidList[myCounterInt].build =
true;
735 QgsDebugMsgLevel(
QString(
"building pyramids : %1 pyramids, %2 resampling, %3 format, %4 options" ).arg( myPyramidList.
count() ).arg( mPyramidsResampling ).
arg( mPyramidsFormat ).
arg( mPyramidsConfigOptions.
count() ), 4 );
738 mPyramidsFormat, mPyramidsConfigOptions );
745 if ( res ==
"ERROR_WRITE_ACCESS" )
747 title =
QObject::tr(
"Building pyramids failed - write access denied" );
748 message =
QObject::tr(
"Write access denied. Adjust the file permissions and try again." );
750 else if ( res ==
"ERROR_WRITE_FORMAT" )
752 title =
QObject::tr(
"Building pyramids failed." );
753 message =
QObject::tr(
"The file was not writable. Some formats do not " 754 "support pyramid overviews. Consult the GDAL documentation if in doubt." );
756 else if ( res ==
"FAILED_NOT_SUPPORTED" )
758 title =
QObject::tr(
"Building pyramids failed." );
759 message =
QObject::tr(
"Building pyramid overviews is not supported on this type of raster." );
761 else if ( res ==
"ERROR_JPEG_COMPRESSION" )
763 title =
QObject::tr(
"Building pyramids failed." );
764 message =
QObject::tr(
"Building internal pyramid overviews is not supported on raster layers with JPEG compression and your current libtiff library." );
766 else if ( res ==
"ERROR_VIRTUAL" )
768 title =
QObject::tr(
"Building pyramids failed." );
769 message =
QObject::tr(
"Building pyramid overviews is not supported on this type of raster." );
778 int QgsRasterFileWriter::pyramidsProgress(
double dfComplete,
const char *pszMessage,
void* pData )
780 Q_UNUSED( pszMessage );
781 GDALTermProgress( dfComplete, 0, 0 );
791 progressDialog->
setValue( dfComplete * 100 );
799 mVRTDocument.
clear();
835 colorInterp <<
"Red" <<
"Green" <<
"Blue" <<
"Alpha";
849 for (
int i = 1; i <= nBands; i++ )
857 if ( mMode ==
Image )
866 if ( !destHasNoDataValueList.
isEmpty() && destHasNoDataValueList.
value( i - 1 ) )
871 mVRTBands.
append( VRTBand );
876 bool QgsRasterFileWriter::writeVRT(
const QString& file )
878 QFile outputFile( file );
879 if ( ! outputFile.
open( QIODevice::WriteOnly | QIODevice::Truncate ) )
885 mVRTDocument.
save( outStream, 2 );
890 int iterRows,
int iterLeft,
int iterTop,
const QString& outputUrl,
int fileIndex,
int nBands,
QGis::DataType type,
893 double mup = extent.
width() / nCols;
894 double mapLeft = extent.
xMinimum() + iterLeft * mup;
895 double mapRight = mapLeft + mup * iterCols;
896 double mapTop = extent.
yMaximum() - iterTop * mup;
897 double mapBottom = mapTop - iterRows * mup;
898 QgsRectangle mapRect( mapLeft, mapBottom, mapRight, mapTop );
900 QString outputFile = outputUrl +
'/' + partFileName( fileIndex );
903 double geoTransform[6];
904 geoTransform[0] = mapRect.
xMinimum();
905 geoTransform[1] = mup;
906 geoTransform[2] = 0.0;
907 geoTransform[3] = mapRect.
yMaximum();
908 geoTransform[4] = 0.0;
909 geoTransform[5] = -mup;
925 createVRT( nCols, nRows, crs, geoTransform, type, destHasNoDataValueList, destNoDataValueList );
933 if ( mBuildPyramidsFlag == -4 && mOutputProviderKey ==
"gdal" && mOutputFormat.
toLower() ==
"gtiff" )
934 mCreateOptions <<
"COPY_SRC_OVERVIEWS=YES";
948 void QgsRasterFileWriter::globalOutputParameters(
const QgsRectangle& extent,
int nCols,
int& nRows,
949 double* geoTransform,
double& pixelSize )
951 pixelSize = extent.
width() / nCols;
956 nRows =
static_cast< double >( nCols ) / extent.
width() * extent.
height() + 0.5;
958 geoTransform[0] = extent.
xMinimum();
959 geoTransform[1] = pixelSize;
960 geoTransform[2] = 0.0;
961 geoTransform[3] = extent.
yMaximum();
962 geoTransform[4] = 0.0;
963 geoTransform[5] = -( extent.
height() / nRows );
966 QString QgsRasterFileWriter::partFileName(
int fileIndex )
973 QString QgsRasterFileWriter::vrtFileName()
virtual int bandCount() const =0
Get number of bands.
Eight bit unsigned integer (quint8)
bool contains(const QgsRectangle &rect) const
return true when rectangle contains other rectangle
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.
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 setMaximum(int maximum)
void push_back(const T &value)
void setLabelText(const QString &text)
QgsRasterProjector * projector() const
Raster pipe that deals with null values.
QgsRasterInterface * last() const
double maximumValue
The maximum cell value in the raster band.
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.
QgsCoordinateReferenceSystem srcCrs() const
Get source CRS.
QString tr(const char *sourceText, const char *disambiguation, int n)
QgsCoordinateReferenceSystem destCrs() const
Get destination CRS.
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)
double width() const
Width of the rectangle.
static bool typeIsColor(QGis::DataType type)
Returns true if data type is color.
Thirty two bit unsigned integer (quint32)
QRgb color(int row, int column) const
Read a single color.
Color, alpha, red, green, blue, 4 bytes the same as QImage::Format_ARGB32.
static int typeSize(int dataType)
QgsRasterRangeList noData(int bandNo) const
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.
QgsRasterProjector implements approximate projection support for it calculates grid of points in sour...
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
const QgsRasterInterface * input() const
int maximumTileHeight() const
QString absolutePath() const
virtual bool remove()
Remove dataset.
bool mkdir(const QString &dirName) const
Class for storing a coordinate reference system (CRS)
QString toWkt() const
Returns a WKT representation of this CRS.
DataType
Raster data types.
double xMinimum() const
Get the x minimum value (left side of rectangle)
virtual const QgsRasterInterface * srcInput() const
Get source / raw input, the first in pipe, usually provider.
double minimumValue
The minimum cell value in the raster band.
QgsRasterNuller * nuller() const
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)
double yMaximum() const
Get the y maximum value (top side of rectangle)
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.
QDomElement createElement(const QString &tagName)
virtual double srcNoDataValue(int bandNo) const
Value representing no data value.
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
void qgsFree(void *ptr)
Frees the memory space pointed to by ptr.
void startRasterRead(int bandNumber, int nCols, int nRows, const QgsRectangle &extent, QgsRasterBlockFeedback *feedback=nullptr)
Start reading of raster band.
int maximumTileWidth() 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)