Skip to content

Commit 7eb63d9

Browse files
committedApr 3, 2017
[FEATURE] Implement saving paletted raster renderer color tables
Use the .clr/gdal file format, but add the labels on the ends of the lines. Seems other importers like ArcMap just ignore these.
1 parent d0566f7 commit 7eb63d9

File tree

7 files changed

+106
-7
lines changed

7 files changed

+106
-7
lines changed
 

‎python/core/raster/qgspalettedrasterrenderer.sip

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ class QgsPalettedRasterRenderer : QgsRasterRenderer
3939
static QgsPalettedRasterRenderer::ClassData colorTableToClassData( const QList<QgsColorRampShader::ColorRampItem> &table );
4040
static QgsPalettedRasterRenderer::ClassData classDataFromString( const QString &string );
4141
static QgsPalettedRasterRenderer::ClassData classDataFromFile( const QString &path );
42+
static QString classDataToString( const QgsPalettedRasterRenderer::ClassData &classes );
4243

4344
private:
4445

‎src/core/raster/qgspalettedrasterrenderer.cpp

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -326,9 +326,11 @@ QgsPalettedRasterRenderer::ClassData QgsPalettedRasterRenderer::classDataFromStr
326326
break;
327327
}
328328

329-
case 4:
330-
case 5:
329+
default:
331330
{
331+
if ( lineParts.count() < 4 )
332+
continue;
333+
332334
int value = lineParts.at( 0 ).toInt( &ok );
333335
if ( !ok )
334336
continue;
@@ -346,14 +348,20 @@ QgsPalettedRasterRenderer::ClassData QgsPalettedRasterRenderer::classDataFromStr
346348
c = QColor( r, g, b );
347349
}
348350

349-
if ( lineParts.count() == 5 )
351+
if ( lineParts.count() >= 5 )
350352
{
351353
double alpha = lineParts.at( 4 ).toDouble( &ok );
352354
if ( ok )
353355
c.setAlpha( alpha );
354356
}
355357

356-
classes << Class( value, c );
358+
QString label;
359+
if ( lineParts.count() > 5 )
360+
{
361+
label = lineParts.mid( 5 ).join( ' ' );
Code has comments. Press enter to view.
362+
}
363+
364+
classes << Class( value, c, label );
357365
break;
358366
}
359367
}
@@ -375,6 +383,24 @@ QgsPalettedRasterRenderer::ClassData QgsPalettedRasterRenderer::classDataFromFil
375383
return classDataFromString( input );
376384
}
377385

386+
QString QgsPalettedRasterRenderer::classDataToString( const QgsPalettedRasterRenderer::ClassData &classes )
387+
{
388+
QStringList out;
389+
// must be sorted
390+
QgsPalettedRasterRenderer::ClassData cd = classes;
391+
std::sort( cd.begin(), cd.end(), []( const Class & a, const Class & b ) -> bool
392+
{
393+
return a.value < b.value;
394+
} );
395+
396+
Q_FOREACH ( const Class &c, cd )
397+
{
398+
out << QString( "%1 %2 %3 %4 %5 %6" ).arg( c.value ).arg( c.color.red() )
399+
.arg( c.color.green() ).arg( c.color.blue() ).arg( c.color.alpha() ).arg( c.label );
400+
}
401+
return out.join( '\n' );
402+
}
403+
378404
void QgsPalettedRasterRenderer::updateArrays()
379405
{
380406
// find maximum color index

‎src/core/raster/qgspalettedrasterrenderer.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@ class CORE_EXPORT QgsPalettedRasterRenderer: public QgsRasterRenderer
117117
* Converts a \a string containing a color table or class data to to paletted renderer class data.
118118
* @note added in QGIS 3.0
119119
* @see classDataFromFile()
120+
* @see classDataToString()
120121
*/
121122
static QgsPalettedRasterRenderer::ClassData classDataFromString( const QString &string );
122123

@@ -127,6 +128,13 @@ class CORE_EXPORT QgsPalettedRasterRenderer: public QgsRasterRenderer
127128
*/
128129
static QgsPalettedRasterRenderer::ClassData classDataFromFile( const QString &path );
129130

131+
/**
132+
* Converts classes to a string representation, using the .clr/gdal color table file format.
133+
* @note added in QGIS 3.0
134+
* @see classDataFromString()
135+
*/
136+
static QString classDataToString( const QgsPalettedRasterRenderer::ClassData &classes );
137+
130138
private:
131139

132140
int mBand;

‎src/gui/raster/qgspalettedrendererwidget.cpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ QgsPalettedRendererWidget::QgsPalettedRendererWidget( QgsRasterLayer *layer, con
9292
connect( mDeleteEntryButton, &QPushButton::clicked, this, &QgsPalettedRendererWidget::deleteEntry );
9393
connect( mAddEntryButton, &QPushButton::clicked, this, &QgsPalettedRendererWidget::addEntry );
9494
connect( mLoadFromFileButton, &QPushButton::clicked, this, &QgsPalettedRendererWidget::loadColorTable );
95+
connect( mExportToFileButton, &QPushButton::clicked, this, &QgsPalettedRendererWidget::saveColorTable );
9596
}
9697

9798
QgsRasterRenderer *QgsPalettedRendererWidget::renderer()
@@ -336,6 +337,36 @@ void QgsPalettedRendererWidget::loadColorTable()
336337
}
337338
}
338339

340+
void QgsPalettedRendererWidget::saveColorTable()
341+
{
342+
QgsSettings settings;
343+
QString lastDir = settings.value( QStringLiteral( "lastColorMapDir" ), QDir::homePath() ).toString();
344+
QString fileName = QFileDialog::getSaveFileName( this, tr( "Save file" ), lastDir, tr( "Text (*.clr)" ) );
345+
if ( !fileName.isEmpty() )
346+
{
347+
if ( !fileName.endsWith( QLatin1String( ".clr" ), Qt::CaseInsensitive ) )
348+
{
349+
fileName = fileName + ".clr";
350+
}
351+
352+
QFile outputFile( fileName );
353+
if ( outputFile.open( QFile::WriteOnly | QIODevice::Truncate ) )
354+
{
355+
QTextStream outputStream( &outputFile );
356+
outputStream << QgsPalettedRasterRenderer::classDataToString( mModel->classData() );
357+
outputStream.flush();
358+
outputFile.close();
359+
360+
QFileInfo fileInfo( fileName );
361+
settings.setValue( QStringLiteral( "lastColorMapDir" ), fileInfo.absoluteDir().absolutePath() );
362+
}
363+
else
364+
{
365+
QMessageBox::warning( this, tr( "Write access denied" ), tr( "Write access denied. Adjust the file permissions and try again.\n\n" ) );
366+
}
367+
}
368+
}
369+
339370
//
340371
// QgsPalettedRendererModel
341372
//

‎src/gui/raster/qgspalettedrendererwidget.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,8 @@ class GUI_EXPORT QgsPalettedRendererWidget: public QgsRasterRendererWidget, priv
108108
void changeLabel();
109109
void applyColorRamp();
110110
void loadColorTable();
111+
void saveColorTable();
112+
111113
};
112114

113115
#endif // QGSPALETTEDRENDERERWIDGET_H

‎tests/src/python/test_qgsrasterlayer.py

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -480,6 +480,19 @@ def testLoadPalettedColorDataFromString(self):
480480
self.assertEqual(classes[4].color.name(), '#0000ff')
481481
self.assertEqual(classes[4].color.alpha(), 255)
482482

483+
# qgis style, with labels
484+
qgis = '3 255 0 0 255 class 1\n4 0 255 0 200 class 2'
485+
classes = QgsPalettedRasterRenderer.classDataFromString(qgis)
486+
self.assertEqual(len(classes), 2)
487+
self.assertEqual(classes[0].value, 3)
488+
self.assertEqual(classes[0].color.name(), '#ff0000')
489+
self.assertEqual(classes[0].color.alpha(), 255)
490+
self.assertEqual(classes[0].label, 'class 1')
491+
self.assertEqual(classes[1].value, 4)
492+
self.assertEqual(classes[1].color.name(), '#00ff00')
493+
self.assertEqual(classes[1].color.alpha(), 200)
494+
self.assertEqual(classes[1].label, 'class 2')
495+
483496
# some bad inputs
484497
bad = ''
485498
classes = QgsPalettedRasterRenderer.classDataFromString(bad)
@@ -496,9 +509,6 @@ def testLoadPalettedColorDataFromString(self):
496509
bad = '1 255 a 0'
497510
classes = QgsPalettedRasterRenderer.classDataFromString(bad)
498511
self.assertEqual(len(classes), 1)
499-
bad = '1 255 255 0 0 0 0 0 0 0'
500-
classes = QgsPalettedRasterRenderer.classDataFromString(bad)
501-
self.assertEqual(len(classes), 0)
502512

503513
def testLoadPalettedClassDataFromFile(self):
504514
# bad file
@@ -533,5 +543,16 @@ def testLoadPalettedClassDataFromFile(self):
533543
self.assertEqual(classes[9].value, 10)
534544
self.assertEqual(classes[9].color.name(), '#ffb600')
535545

546+
def testPalettedClassDataToString(self):
547+
classes = [QgsPalettedRasterRenderer.Class(1, QColor(0, 255, 0), 'class 2'),
548+
QgsPalettedRasterRenderer.Class(3, QColor(255, 0, 0), 'class 1')]
549+
self.assertEqual(QgsPalettedRasterRenderer.classDataToString(classes), '1 0 255 0 255 class 2\n3 255 0 0 255 class 1')
550+
# must be sorted by value to work OK in ArcMap
551+
classes = [QgsPalettedRasterRenderer.Class(4, QColor(0, 255, 0), 'class 2'),
552+
QgsPalettedRasterRenderer.Class(3, QColor(255, 0, 0), 'class 1')]
553+
self.assertEqual(QgsPalettedRasterRenderer.classDataToString(classes),
554+
'3 255 0 0 255 class 1\n4 0 255 0 255 class 2')
555+
556+
536557
if __name__ == '__main__':
537558
unittest.main()

‎tests/testdata/raster/test.clr

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
1 0 0 0
2+
2 200 200 200
3+
3 0 110 0
4+
4 110 65 0
5+
5 0 0 255
6+
6 0 89 255
7+
7 0 174 255
8+
8 0 255 246
9+
9 238 255 0
10+
10 255 182 0

0 commit comments

Comments
 (0)
Please sign in to comment.