Skip to content

Commit 560523d

Browse files
committed
Implement saving for non-argb types (still needs cleanout of spaghetti code)
1 parent 40e9b4d commit 560523d

File tree

3 files changed

+147
-144
lines changed

3 files changed

+147
-144
lines changed

src/app/qgisapp.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3785,7 +3785,7 @@ void QgisApp::saveAsRasterFile()
37853785

37863786
QProgressDialog pd( 0, tr( "Abort..." ), 0, 0 );
37873787
pd.setWindowModality( Qt::WindowModal );
3788-
QgsRasterIterator iterator( rasterLayer->pipe()->last() );
3788+
QgsRasterIterator iterator( rasterLayer->dataProvider() );
37893789
fileWriter.writeRaster( &iterator, d.nColumns(), d.outputRectangle(), rasterLayer->crs(), &pd );
37903790
}
37913791
}

src/core/raster/qgsrasterfilewriter.cpp

Lines changed: 136 additions & 141 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
#include "qgsrasterfilewriter.h"
22
#include "qgsproviderregistry.h"
3-
#include "qgsrasterdataprovider.h"
43
#include "qgsrasterinterface.h"
54
#include "qgsrasteriterator.h"
65
#include "qgsrasterlayer.h"
@@ -39,129 +38,152 @@ QgsRasterFileWriter::WriterError QgsRasterFileWriter::writeRaster( QgsRasterIter
3938
return SourceProviderError;
4039
}
4140

42-
#if 0
43-
if ( outputExtent.isEmpty() )
44-
{
45-
outputExtent = sourceProvider->extent();
46-
}
47-
#endif //0
48-
4941
mProgressDialog = p;
5042

5143
if ( iface->dataType( 1 ) == QgsRasterInterface::ARGB32 )
5244
{
53-
WriterError e = writeARGBRaster( iter, nCols, outputExtent, crs );
45+
WriterError e = writeImageRaster( iter, nCols, outputExtent, crs );
5446
mProgressDialog = 0;
5547
return e;
5648
}
5749
else
5850
{
59-
//
6051
mProgressDialog = 0;
61-
return NoError;
52+
WriterError e = writeDataRaster( iter, nCols, outputExtent, crs );
53+
return e;
6254
}
6355
}
6456

65-
QgsRasterFileWriter::WriterError QgsRasterFileWriter::writeRasterSingleTile( QgsRasterIterator* iter, int nCols )
57+
QgsRasterFileWriter::WriterError QgsRasterFileWriter::writeDataRaster( QgsRasterIterator* iter, int nCols, const QgsRectangle& outputExtent,
58+
const QgsCoordinateReferenceSystem& crs )
6659
{
67-
#if 0
68-
if ( !sourceProvider || ! sourceProvider->isValid() )
60+
if ( !iter )
6961
{
7062
return SourceProviderError;
7163
}
7264

73-
QgsRasterDataProvider* destProvider = QgsRasterLayer::loadProvider( mOutputProviderKey, mOutputUrl );
74-
if ( !destProvider )
65+
const QgsRasterInterface* iface = iter->input();
66+
if ( !iface )
7567
{
76-
return DestProviderError;
68+
return SourceProviderError;
7769
}
7870

79-
QgsRectangle sourceProviderRect = sourceProvider->extent();
80-
double pixelSize = sourceProviderRect.width() / nCols;
81-
int nRows = ( double )nCols / sourceProviderRect.width() * sourceProviderRect.height() + 0.5;
71+
//create directory for output files
72+
QDir destDir( mOutputUrl );
73+
if ( mTiledMode )
74+
{
75+
destDir.mkdir( mOutputUrl );
76+
}
77+
78+
//Get output map units per pixel
79+
double outputMapUnitsPerPixel = outputExtent.width() / nCols;
80+
int iterLeft, iterTop, iterCols, iterRows;
81+
82+
iter->setMaximumTileWidth( mMaxTileWidth );
83+
iter->setMaximumTileHeight( mMaxTileHeight );
84+
85+
int nBands = iface->bandCount();
86+
if ( nBands < 1 )
87+
{
88+
return SourceProviderError;
89+
}
90+
91+
//create destProvider for whole dataset here
92+
QgsRasterDataProvider* destProvider = 0;
93+
double pixelSize = outputExtent.width() / nCols;
94+
int nRows = ( double )nCols / outputExtent.width() * outputExtent.height() + 0.5;
8295
double geoTransform[6];
83-
geoTransform[0] = sourceProviderRect.xMinimum();
96+
geoTransform[0] = outputExtent.xMinimum();
8497
geoTransform[1] = pixelSize;
8598
geoTransform[2] = 0.0;
86-
geoTransform[3] = sourceProviderRect.yMaximum();
99+
geoTransform[3] = outputExtent.yMaximum();
87100
geoTransform[4] = 0.0;
88101
geoTransform[5] = -pixelSize;
89102

90-
//debug
91-
bool hasARGBType = false;
92-
QgsRasterInterface::DataType outputDataType = ( QgsRasterInterface::DataType )sourceProvider->dataType( 1 );
93-
int nOutputBands = sourceProvider->bandCount();
94-
int nInputBands = sourceProvider->bandCount();
95-
if ( outputDataType == QgsRasterInterface::::ARGBDataType )
103+
//check if all the bands have the same data type size, otherwise we cannot write it to the provider
104+
//(at least not with the current interface)
105+
int dataTypeSize = iface->typeSize( iface->dataType( 1 ) );
106+
for ( int i = 2; i <= nBands; ++i )
96107
{
97-
hasARGBType = true; //needs to be converted to four band 8bit
98-
outputDataType = QgsRasterInterface::Byte;
99-
nOutputBands = 4;
108+
if ( iface->typeSize( iface->dataType( 1 ) ) != dataTypeSize )
109+
{
110+
return DestProviderError;
111+
}
100112
}
101113

102-
if ( !destProvider->create( mOutputFormat, nOutputBands, outputDataType, nCols, nRows, geoTransform,
103-
sourceProvider->crs() ) )
114+
QList<void*> dataList;
115+
for ( int i = 1; i <= nBands; ++i )
104116
{
105-
delete destProvider;
106-
return CreateDatasourceError;
117+
iter->startRasterRead( i, nCols, nRows, outputExtent );
118+
dataList.push_back( VSIMalloc( dataTypeSize * mMaxTileWidth * mMaxTileHeight ) );
107119
}
108120

109-
if ( hasARGBType && nInputBands == 1 )
121+
if ( mTiledMode )
110122
{
111-
//For ARGB data, always use 1 input band and four int8 output bands
112-
int nPixels = nCols * nRows;
113-
int dataSize = destProvider->dataTypeSize( 1 ) * nPixels;
114-
void* data = VSIMalloc( dataSize );
115-
sourceProvider->readBlock( 1, sourceProviderRect, nCols, nRows, data );
116-
117-
//data for output bands
118-
void* redData = VSIMalloc( nPixels );
119-
void* greenData = VSIMalloc( nPixels );
120-
void* blueData = VSIMalloc( nPixels );
121-
void* alphaData = VSIMalloc( nPixels );
123+
createVRT( nCols, nRows, crs, geoTransform );
124+
}
125+
else
126+
{
127+
destProvider = QgsRasterLayer::loadProvider( mOutputProviderKey, mOutputUrl );
128+
if ( !destProvider )
129+
{
130+
return DestProviderError;
131+
}
122132

123-
int red = 0;
124-
int green = 0;
125-
int blue = 0;
126-
int alpha = 255;
127-
uint* p = ( uint* ) data;
128-
for ( int i = 0; i < nPixels; ++i )
133+
if ( !destProvider->create( mOutputFormat, nBands, iface->dataType( 1 ), nCols, nRows, geoTransform,
134+
crs ) )
129135
{
130-
QRgb c( *p++ );
131-
red = qRed( c ); green = qGreen( c ); blue = qBlue( c ); alpha = qAlpha( c );
132-
memcpy(( char* )redData + i, &red, 1 );
133-
memcpy(( char* )greenData + i, &green, 1 );
134-
memcpy(( char* )blueData + i, &blue, 1 );
135-
memcpy(( char* )alphaData + i, &alpha, 1 );
136+
delete destProvider;
137+
return CreateDatasourceError;
136138
}
137-
destProvider->write( redData, 1, nCols, nRows, 0, 0 );
138-
destProvider->write( greenData, 2, nCols, nRows, 0, 0 );
139-
destProvider->write( blueData, 3, nCols, nRows, 0, 0 );
140-
destProvider->write( alphaData, 4, nCols, nRows, 0, 0 );
141139
}
142-
else
140+
141+
int fileIndex = 0;
142+
while ( true )
143143
{
144-
//read/write data for each band
145-
for ( int i = 0; i < sourceProvider->bandCount(); ++i )
144+
for ( int i = 1; i <= nBands; ++i )
146145
{
147-
void* data = VSIMalloc( destProvider->dataTypeSize( i + 1 ) * nCols * nRows );
148-
sourceProvider->readBlock( i + 1, sourceProviderRect, nCols, nRows, data );
149-
bool writeSuccess = destProvider->write( data, i + 1, nCols, nRows, 0, 0 );
150-
CPLFree( data );
151-
if ( !writeSuccess )
146+
if ( !iter->readNextRasterPart( i, iterCols, iterRows, &( dataList[i - 1] ), iterLeft, iterTop ) )
152147
{
153148
delete destProvider;
154-
return WriteError;
149+
if ( mTiledMode )
150+
{
151+
QFileInfo outputInfo( mOutputUrl );
152+
QString vrtFilePath( mOutputUrl + "/" + outputInfo.baseName() + ".vrt" );
153+
writeVRT( vrtFilePath );
154+
buildPyramides( vrtFilePath );
155+
}
156+
157+
return NoError; //reached last tile, bail out
155158
}
156159
}
157-
}
158160

159-
delete destProvider;
160-
#endif //0
161-
return NoError;
161+
if ( mTiledMode ) //write to file
162+
{
163+
delete destProvider;
164+
destProvider = createPartProvider( outputExtent, nCols, iterCols, iterRows,
165+
iterLeft, iterTop, mOutputUrl, fileIndex, nBands, iface->dataType( 1 ), crs );
166+
167+
//write data to output file. todo: loop over the data list
168+
for ( int i = 1; i <= nBands; ++i )
169+
{
170+
destProvider->write( dataList[i - 1], i, iterCols, iterRows, 0, 0 );
171+
addToVRT( QString::number( fileIndex ), i, iterCols, iterRows, iterLeft, iterTop );
172+
}
173+
++fileIndex;
174+
}
175+
else
176+
{
177+
//loop over data
178+
for ( int i = 0; i <= nBands; ++i )
179+
{
180+
destProvider->write( dataList[i - 1], i, iterCols, iterRows, iterLeft, iterTop );
181+
}
182+
}
183+
}
162184
}
163185

164-
QgsRasterFileWriter::WriterError QgsRasterFileWriter::writeARGBRaster( QgsRasterIterator* iter, int nCols, const QgsRectangle& outputExtent,
186+
QgsRasterFileWriter::WriterError QgsRasterFileWriter::writeImageRaster( QgsRasterIterator* iter, int nCols, const QgsRectangle& outputExtent,
165187
const QgsCoordinateReferenceSystem& crs )
166188
{
167189
if ( !iter )
@@ -235,49 +257,13 @@ QgsRasterFileWriter::WriterError QgsRasterFileWriter::writeARGBRaster( QgsRaster
235257
//iter->select( outputExtent, outputMapUnitsPerPixel );
236258
iter->startRasterRead( 1, nCols, nRows, outputExtent );
237259

238-
#if 0
239-
//initialize progress dialog
240-
int nTiles = iter.nTilesX() * iter.nTilesY();
241-
if ( mProgressDialog )
242-
{
243-
mProgressDialog->setWindowTitle( QObject::tr( "Save raster" ) );
244-
mProgressDialog->setMaximum( nTiles );
245-
mProgressDialog->show();
246-
}
247-
#endif //0
248-
249260
while ( iter->readNextRasterPart( 1, iterCols, iterRows, &data, iterLeft, iterTop ) )
250261
{
251262
if ( iterCols <= 5 || iterRows <= 5 ) //some wms servers don't like small values
252263
{
253264
continue;
254265
}
255266

256-
double mup = outputExtent.width() / nCols;
257-
double mapLeft = outputExtent.xMinimum() + iterLeft * mup;
258-
double mapRight = mapLeft + mup * iterCols;
259-
double mapTop = outputExtent.yMaximum() - iterTop * mup;
260-
double mapBottom = mapTop - iterTop * mup;
261-
QgsRectangle mapRect( mapLeft, mapBottom, mapRight, mapTop );
262-
263-
if ( mapRect.width() < 0.000000001 || mapRect.height() < 0.000000001 )
264-
{
265-
continue;
266-
}
267-
268-
#if 0
269-
if ( mProgressDialog )
270-
{
271-
mProgressDialog->setValue( fileIndex + 1 );
272-
mProgressDialog->setLabelText( QObject::tr( "Downloaded raster tile %1 from %2" ).arg( fileIndex + 1 ).arg( nTiles ) );
273-
qApp->processEvents( QEventLoop::AllEvents, 2000 );
274-
if ( mProgressDialog->wasCanceled() )
275-
{
276-
break;
277-
}
278-
}
279-
#endif //0
280-
281267
//fill into red/green/blue/alpha channels
282268
uint* p = ( uint* ) data;
283269
int nPixels = iterCols * iterRows;
@@ -298,28 +284,9 @@ QgsRasterFileWriter::WriterError QgsRasterFileWriter::writeARGBRaster( QgsRaster
298284
//create output file
299285
if ( mTiledMode )
300286
{
301-
QString outputFile = mOutputUrl + "/" + QString::number( fileIndex );
302287
delete destProvider;
303-
destProvider = QgsRasterLayer::loadProvider( mOutputProviderKey, outputFile );
304-
if ( !destProvider )
305-
{
306-
return DestProviderError;
307-
}
308-
309-
//geotransform
310-
double geoTransform[6];
311-
geoTransform[0] = mapRect.xMinimum();
312-
geoTransform[1] = outputMapUnitsPerPixel;
313-
geoTransform[2] = 0.0;
314-
geoTransform[3] = mapRect.yMaximum();
315-
geoTransform[4] = 0.0;
316-
geoTransform[5] = -outputMapUnitsPerPixel;
317-
if ( !destProvider->create( mOutputFormat, 4, QgsRasterInterface::Byte, iterCols, iterRows, geoTransform,
318-
crs ) )
319-
{
320-
delete destProvider;
321-
return CreateDatasourceError;
322-
}
288+
destProvider = createPartProvider( outputExtent, nCols, iterCols, iterRows,
289+
iterLeft, iterTop, mOutputUrl, fileIndex, 4, QgsRasterInterface::Byte, crs );
323290

324291
//write data to output file
325292
destProvider->write( redData, 1, iterCols, iterRows, 0, 0 );
@@ -345,13 +312,6 @@ QgsRasterFileWriter::WriterError QgsRasterFileWriter::writeARGBRaster( QgsRaster
345312
delete destProvider;
346313
CPLFree( data ); CPLFree( redData ); CPLFree( greenData ); CPLFree( blueData ); CPLFree( alphaData );
347314

348-
#if 0
349-
if ( mProgressDialog )
350-
{
351-
mProgressDialog->setValue( nTiles );
352-
}
353-
#endif //0
354-
355315
if ( mTiledMode )
356316
{
357317
QFileInfo outputInfo( mOutputUrl );
@@ -553,6 +513,41 @@ bool QgsRasterFileWriter::writeVRT( const QString& file )
553513
return true;
554514
}
555515

516+
QgsRasterDataProvider* QgsRasterFileWriter::createPartProvider( const QgsRectangle& extent, int nCols, int iterCols,
517+
int iterRows, int iterLeft, int iterTop, const QString& outputUrl, int fileIndex, int nBands, QgsRasterInterface::DataType type,
518+
const QgsCoordinateReferenceSystem& crs )
519+
{
520+
double mup = extent.width() / nCols;
521+
double mapLeft = extent.xMinimum() + iterLeft * mup;
522+
double mapRight = mapLeft + mup * iterCols;
523+
double mapTop = extent.yMaximum() - iterTop * mup;
524+
double mapBottom = mapTop - iterRows * mup;
525+
QgsRectangle mapRect( mapLeft, mapBottom, mapRight, mapTop );
526+
527+
QString outputFile = outputUrl + "/" + QString::number( fileIndex );
528+
QgsRasterDataProvider* destProvider = QgsRasterLayer::loadProvider( mOutputProviderKey, outputFile );
529+
if ( !destProvider )
530+
{
531+
return 0;
532+
}
533+
534+
//geotransform
535+
double geoTransform[6];
536+
geoTransform[0] = mapRect.xMinimum();
537+
geoTransform[1] = mup;
538+
geoTransform[2] = 0.0;
539+
geoTransform[3] = mapRect.yMaximum();
540+
geoTransform[4] = 0.0;
541+
geoTransform[5] = -mup;
542+
if ( !destProvider->create( mOutputFormat, nBands, type, iterCols, iterRows, geoTransform,
543+
crs ) )
544+
{
545+
delete destProvider;
546+
return 0;
547+
}
548+
return destProvider;
549+
}
550+
556551

557552

558553

0 commit comments

Comments
 (0)