Skip to content

Commit 0c0e30b

Browse files
committedSep 22, 2018
QgsRasterFilWriter: fix crash when building overviews (fixes #19679)
1 parent 9dd1406 commit 0c0e30b

File tree

4 files changed

+70
-66
lines changed

4 files changed

+70
-66
lines changed
 

‎src/core/raster/qgsrasterfilewriter.cpp

Lines changed: 11 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -58,15 +58,11 @@ QgsRasterDataProvider *QgsRasterFileWriter::createMultiBandRaster( Qgis::DataTyp
5858

5959
QgsRasterFileWriter::QgsRasterFileWriter( const QString &outputUrl )
6060
: mOutputUrl( outputUrl )
61-
, mOutputProviderKey( QStringLiteral( "gdal" ) )
62-
, mOutputFormat( QStringLiteral( "GTiff" ) )
6361
{
6462

6563
}
6664

6765
QgsRasterFileWriter::QgsRasterFileWriter()
68-
: mOutputProviderKey( QStringLiteral( "gdal" ) )
69-
, mOutputFormat( QStringLiteral( "GTiff" ) )
7066
{
7167

7268
}
@@ -400,7 +396,7 @@ QgsRasterFileWriter::WriterError QgsRasterFileWriter::writeDataRaster( const Qgs
400396
{
401397
if ( mBuildPyramidsFlag == QgsRaster::PyramidsFlagYes )
402398
{
403-
buildPyramids( mOutputUrl );
399+
buildPyramids( mOutputUrl, destProvider );
404400
}
405401
}
406402

@@ -682,48 +678,20 @@ void QgsRasterFileWriter::addToVRT( const QString &filename, int band, int xSize
682678
bandElem.appendChild( simpleSourceElem );
683679
}
684680

685-
#if 0
686-
void QgsRasterFileWriter::buildPyramids( const QString &filename )
687-
{
688-
GDALDatasetH dataSet;
689-
GDALAllRegister();
690-
dataSet = GDALOpen( filename.toLocal8Bit().data(), GA_Update );
691-
if ( !dataSet )
692-
{
693-
return;
694-
}
695-
696-
//2,4,8,16,32,64
697-
int overviewList[6];
698-
overviewList[0] = 2;
699-
overviewList[1] = 4;
700-
overviewList[2] = 8;
701-
overviewList[3] = 16;
702-
overviewList[4] = 32;
703-
overviewList[5] = 64;
704-
705-
#if 0
706-
if ( mProgressDialog )
707-
{
708-
mProgressDialog->setLabelText( QObject::tr( "Building Pyramids..." ) );
709-
mProgressDialog->setValue( 0 );
710-
mProgressDialog->setWindowModality( Qt::WindowModal );
711-
mProgressDialog->show();
712-
}
713-
#endif
714-
GDALBuildOverviews( dataSet, "AVERAGE", 6, overviewList, 0, 0, /*pyramidsProgress*/ 0, /*mProgressDialog*/ 0 );
715-
}
716-
#endif
717-
718-
void QgsRasterFileWriter::buildPyramids( const QString &filename )
681+
void QgsRasterFileWriter::buildPyramids( const QString &filename, QgsRasterDataProvider *destProviderIn )
719682
{
720683
QgsDebugMsgLevel( "filename = " + filename, 4 );
721684
// open new dataProvider so we can build pyramids with it
722685
QgsDataProvider::ProviderOptions providerOptions;
723-
QgsRasterDataProvider *destProvider = dynamic_cast< QgsRasterDataProvider * >( QgsProviderRegistry::instance()->createProvider( mOutputProviderKey, filename, providerOptions ) );
686+
QgsRasterDataProvider *destProvider = destProviderIn;
724687
if ( !destProvider )
725688
{
726-
return;
689+
destProvider = dynamic_cast< QgsRasterDataProvider * >( QgsProviderRegistry::instance()->createProvider( mOutputProviderKey, filename, providerOptions ) );
690+
if ( !destProvider || !destProvider->isValid() )
691+
{
692+
delete destProvider;
693+
return;
694+
}
727695
}
728696

729697
// TODO progress report
@@ -763,11 +731,6 @@ void QgsRasterFileWriter::buildPyramids( const QString &filename )
763731
title = QObject::tr( "Building Pyramids" );
764732
message = QObject::tr( "Building pyramid overviews is not supported on this type of raster." );
765733
}
766-
else if ( res == QLatin1String( "ERROR_JPEG_COMPRESSION" ) )
767-
{
768-
title = QObject::tr( "Building Pyramids" );
769-
message = QObject::tr( "Building internal pyramid overviews is not supported on raster layers with JPEG compression and your current libtiff library." );
770-
}
771734
else if ( res == QLatin1String( "ERROR_VIRTUAL" ) )
772735
{
773736
title = QObject::tr( "Building Pyramids" );
@@ -776,7 +739,8 @@ void QgsRasterFileWriter::buildPyramids( const QString &filename )
776739
QMessageBox::warning( nullptr, title, message );
777740
QgsDebugMsgLevel( res + " - " + message, 4 );
778741
}
779-
delete destProvider;
742+
if ( !destProviderIn )
743+
delete destProvider;
780744
}
781745

782746
#if 0

‎src/core/raster/qgsrasterfilewriter.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ class CORE_EXPORT QgsRasterFileWriter
243243
bool writeVRT( const QString &file );
244244
//add file entry to vrt
245245
void addToVRT( const QString &filename, int band, int xSize, int ySize, int xOffset, int yOffset );
246-
void buildPyramids( const QString &filename );
246+
void buildPyramids( const QString &filename, QgsRasterDataProvider *destProviderIn = nullptr );
247247

248248
//! Create provider and datasource for a part image (vrt mode)
249249
QgsRasterDataProvider *createPartProvider( const QgsRectangle &extent, int nCols, int iterCols, int iterRows,
@@ -275,8 +275,8 @@ class CORE_EXPORT QgsRasterFileWriter
275275

276276
Mode mMode = Raw;
277277
QString mOutputUrl;
278-
QString mOutputProviderKey;
279-
QString mOutputFormat;
278+
QString mOutputProviderKey = QStringLiteral( "gdal" );
279+
QString mOutputFormat = QStringLiteral( "GTiff" );
280280
QStringList mCreateOptions;
281281
QgsCoordinateReferenceSystem mOutputCRS;
282282

@@ -286,7 +286,7 @@ class CORE_EXPORT QgsRasterFileWriter
286286
double mMaxTileHeight = 500;
287287

288288
QList< int > mPyramidsList;
289-
QString mPyramidsResampling;
289+
QString mPyramidsResampling = QStringLiteral( "AVERAGE" );
290290
QgsRaster::RasterBuildPyramids mBuildPyramidsFlag = QgsRaster::PyramidsFlagNo;
291291
QgsRaster::RasterPyramidsFormat mPyramidsFormat = QgsRaster::PyramidsGTiff;
292292
QStringList mPyramidsConfigOptions;

‎src/providers/gdal/qgsgdalprovider.cpp

Lines changed: 7 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1618,20 +1618,6 @@ QString QgsGdalProvider::buildPyramids( const QList<QgsRasterPyramid> &rasterPyr
16181618
return QStringLiteral( "ERROR_WRITE_ACCESS" );
16191619
}
16201620

1621-
// libtiff < 4.0 has a bug that prevents safe building of overviews on JPEG compressed files
1622-
// we detect libtiff < 4.0 by checking that BIGTIFF is not in the creation options of the GTiff driver
1623-
// see https://trac.osgeo.org/qgis/ticket/1357
1624-
const char *pszGTiffCreationOptions =
1625-
GDALGetMetadataItem( GDALGetDriverByName( "GTiff" ), GDAL_DMD_CREATIONOPTIONLIST, "" );
1626-
if ( !strstr( pszGTiffCreationOptions, "BIGTIFF" ) )
1627-
{
1628-
QString myCompressionType = QString( GDALGetMetadataItem( mGdalDataset, "COMPRESSION", "IMAGE_STRUCTURE" ) );
1629-
if ( "JPEG" == myCompressionType )
1630-
{
1631-
return QStringLiteral( "ERROR_JPEG_COMPRESSION" );
1632-
}
1633-
}
1634-
16351621
// if needed close the gdal dataset and reopen it in read / write mode
16361622
// TODO this doesn't seem to work anymore... must fix it before 2.0!!!
16371623
// no errors are reported, but pyramids are not present in file.
@@ -1657,10 +1643,17 @@ QString QgsGdalProvider::buildPyramids( const QList<QgsRasterPyramid> &rasterPyr
16571643
// are we using Erdas Imagine external overviews?
16581644
QgsStringMap myConfigOptionsOld;
16591645
myConfigOptionsOld[ QStringLiteral( "USE_RRD" )] = CPLGetConfigOption( "USE_RRD", "NO" );
1646+
myConfigOptionsOld[ QStringLiteral( "TIFF_USE_OVR" )] = CPLGetConfigOption( "TIFF_USE_OVR", "NO" );
16601647
if ( format == QgsRaster::PyramidsErdas )
16611648
CPLSetConfigOption( "USE_RRD", "YES" );
16621649
else
1650+
{
16631651
CPLSetConfigOption( "USE_RRD", "NO" );
1652+
if ( format == QgsRaster::PyramidsGTiff )
1653+
{
1654+
CPLSetConfigOption( "TIFF_USE_OVR", "YES" );
1655+
}
1656+
}
16641657

16651658
// add any driver-specific configuration options, save values to be restored later
16661659
if ( format != QgsRaster::PyramidsErdas && ! configOptions.isEmpty() )

‎tests/src/python/test_qgsrasterfilewriter.py

Lines changed: 48 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,8 @@
2020

2121
from osgeo import gdal
2222
from qgis.PyQt.QtCore import QTemporaryFile, QDir
23-
from qgis.core import (QgsRasterLayer,
23+
from qgis.core import (QgsRaster,
24+
QgsRasterLayer,
2425
QgsRasterChecker,
2526
QgsRasterPipe,
2627
QgsRasterFileWriter,
@@ -178,6 +179,52 @@ def testImportIntoGpkg(self):
178179
# remove result file
179180
os.unlink(test_gpkg)
180181

182+
def _testGeneratePyramids(self, pyramidFormat):
183+
tmpName = tempfile.mktemp(suffix='.tif')
184+
source = QgsRasterLayer(os.path.join(self.testDataDir, 'raster', 'byte.tif'), 'my', 'gdal')
185+
self.assertTrue(source.isValid())
186+
provider = source.dataProvider()
187+
fw = QgsRasterFileWriter(tmpName)
188+
189+
fw.setBuildPyramidsFlag(QgsRaster.PyramidsFlagYes)
190+
fw.setPyramidsFormat(pyramidFormat)
191+
fw.setPyramidsList([2])
192+
193+
pipe = QgsRasterPipe()
194+
self.assertTrue(pipe.set(provider.clone()))
195+
196+
projector = QgsRasterProjector()
197+
projector.setCrs(provider.crs(), provider.crs())
198+
self.assertTrue(pipe.insert(2, projector))
199+
200+
self.assertEqual(fw.writeRaster(pipe,
201+
provider.xSize(),
202+
provider.ySize(),
203+
provider.extent(),
204+
provider.crs()), 0)
205+
del fw
206+
ds = gdal.Open(tmpName)
207+
self.assertEqual(ds.GetRasterBand(1).GetOverviewCount(), 1)
208+
fl = ds.GetFileList()
209+
if pyramidFormat == QgsRaster.PyramidsGTiff:
210+
self.assertEqual(len(fl), 2, fl)
211+
self.assertIn('.ovr', fl[1])
212+
elif pyramidFormat == QgsRaster.PyramidsInternal:
213+
self.assertEqual(len(fl), 1, fl)
214+
elif pyramidFormat == QgsRaster.PyramidsErdas:
215+
self.assertEqual(len(fl), 2, fl)
216+
self.assertIn('.aux', fl[1])
217+
os.unlink(tmpName)
218+
219+
def testGeneratePyramidsExternal(self):
220+
return self._testGeneratePyramids(QgsRaster.PyramidsGTiff)
221+
222+
def testGeneratePyramidsInternal(self):
223+
return self._testGeneratePyramids(QgsRaster.PyramidsInternal)
224+
225+
def testGeneratePyramidsErdas(self):
226+
return self._testGeneratePyramids(QgsRaster.PyramidsErdas)
227+
181228

182229
if __name__ == '__main__':
183230
unittest.main()

0 commit comments

Comments
 (0)
Please sign in to comment.