mirror of
https://github.com/qgis/QGIS.git
synced 2025-04-15 00:04:00 -04:00
[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.
This commit is contained in:
parent
d0566f7792
commit
7eb63d99dc
@ -39,6 +39,7 @@ class QgsPalettedRasterRenderer : QgsRasterRenderer
|
|||||||
static QgsPalettedRasterRenderer::ClassData colorTableToClassData( const QList<QgsColorRampShader::ColorRampItem> &table );
|
static QgsPalettedRasterRenderer::ClassData colorTableToClassData( const QList<QgsColorRampShader::ColorRampItem> &table );
|
||||||
static QgsPalettedRasterRenderer::ClassData classDataFromString( const QString &string );
|
static QgsPalettedRasterRenderer::ClassData classDataFromString( const QString &string );
|
||||||
static QgsPalettedRasterRenderer::ClassData classDataFromFile( const QString &path );
|
static QgsPalettedRasterRenderer::ClassData classDataFromFile( const QString &path );
|
||||||
|
static QString classDataToString( const QgsPalettedRasterRenderer::ClassData &classes );
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
@ -326,9 +326,11 @@ QgsPalettedRasterRenderer::ClassData QgsPalettedRasterRenderer::classDataFromStr
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 4:
|
default:
|
||||||
case 5:
|
|
||||||
{
|
{
|
||||||
|
if ( lineParts.count() < 4 )
|
||||||
|
continue;
|
||||||
|
|
||||||
int value = lineParts.at( 0 ).toInt( &ok );
|
int value = lineParts.at( 0 ).toInt( &ok );
|
||||||
if ( !ok )
|
if ( !ok )
|
||||||
continue;
|
continue;
|
||||||
@ -346,14 +348,20 @@ QgsPalettedRasterRenderer::ClassData QgsPalettedRasterRenderer::classDataFromStr
|
|||||||
c = QColor( r, g, b );
|
c = QColor( r, g, b );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( lineParts.count() == 5 )
|
if ( lineParts.count() >= 5 )
|
||||||
{
|
{
|
||||||
double alpha = lineParts.at( 4 ).toDouble( &ok );
|
double alpha = lineParts.at( 4 ).toDouble( &ok );
|
||||||
if ( ok )
|
if ( ok )
|
||||||
c.setAlpha( alpha );
|
c.setAlpha( alpha );
|
||||||
}
|
}
|
||||||
|
|
||||||
classes << Class( value, c );
|
QString label;
|
||||||
|
if ( lineParts.count() > 5 )
|
||||||
|
{
|
||||||
|
label = lineParts.mid( 5 ).join( ' ' );
|
||||||
|
}
|
||||||
|
|
||||||
|
classes << Class( value, c, label );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -375,6 +383,24 @@ QgsPalettedRasterRenderer::ClassData QgsPalettedRasterRenderer::classDataFromFil
|
|||||||
return classDataFromString( input );
|
return classDataFromString( input );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString QgsPalettedRasterRenderer::classDataToString( const QgsPalettedRasterRenderer::ClassData &classes )
|
||||||
|
{
|
||||||
|
QStringList out;
|
||||||
|
// must be sorted
|
||||||
|
QgsPalettedRasterRenderer::ClassData cd = classes;
|
||||||
|
std::sort( cd.begin(), cd.end(), []( const Class & a, const Class & b ) -> bool
|
||||||
|
{
|
||||||
|
return a.value < b.value;
|
||||||
|
} );
|
||||||
|
|
||||||
|
Q_FOREACH ( const Class &c, cd )
|
||||||
|
{
|
||||||
|
out << QString( "%1 %2 %3 %4 %5 %6" ).arg( c.value ).arg( c.color.red() )
|
||||||
|
.arg( c.color.green() ).arg( c.color.blue() ).arg( c.color.alpha() ).arg( c.label );
|
||||||
|
}
|
||||||
|
return out.join( '\n' );
|
||||||
|
}
|
||||||
|
|
||||||
void QgsPalettedRasterRenderer::updateArrays()
|
void QgsPalettedRasterRenderer::updateArrays()
|
||||||
{
|
{
|
||||||
// find maximum color index
|
// find maximum color index
|
||||||
|
@ -117,6 +117,7 @@ class CORE_EXPORT QgsPalettedRasterRenderer: public QgsRasterRenderer
|
|||||||
* Converts a \a string containing a color table or class data to to paletted renderer class data.
|
* Converts a \a string containing a color table or class data to to paletted renderer class data.
|
||||||
* @note added in QGIS 3.0
|
* @note added in QGIS 3.0
|
||||||
* @see classDataFromFile()
|
* @see classDataFromFile()
|
||||||
|
* @see classDataToString()
|
||||||
*/
|
*/
|
||||||
static QgsPalettedRasterRenderer::ClassData classDataFromString( const QString &string );
|
static QgsPalettedRasterRenderer::ClassData classDataFromString( const QString &string );
|
||||||
|
|
||||||
@ -127,6 +128,13 @@ class CORE_EXPORT QgsPalettedRasterRenderer: public QgsRasterRenderer
|
|||||||
*/
|
*/
|
||||||
static QgsPalettedRasterRenderer::ClassData classDataFromFile( const QString &path );
|
static QgsPalettedRasterRenderer::ClassData classDataFromFile( const QString &path );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Converts classes to a string representation, using the .clr/gdal color table file format.
|
||||||
|
* @note added in QGIS 3.0
|
||||||
|
* @see classDataFromString()
|
||||||
|
*/
|
||||||
|
static QString classDataToString( const QgsPalettedRasterRenderer::ClassData &classes );
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
int mBand;
|
int mBand;
|
||||||
|
@ -92,6 +92,7 @@ QgsPalettedRendererWidget::QgsPalettedRendererWidget( QgsRasterLayer *layer, con
|
|||||||
connect( mDeleteEntryButton, &QPushButton::clicked, this, &QgsPalettedRendererWidget::deleteEntry );
|
connect( mDeleteEntryButton, &QPushButton::clicked, this, &QgsPalettedRendererWidget::deleteEntry );
|
||||||
connect( mAddEntryButton, &QPushButton::clicked, this, &QgsPalettedRendererWidget::addEntry );
|
connect( mAddEntryButton, &QPushButton::clicked, this, &QgsPalettedRendererWidget::addEntry );
|
||||||
connect( mLoadFromFileButton, &QPushButton::clicked, this, &QgsPalettedRendererWidget::loadColorTable );
|
connect( mLoadFromFileButton, &QPushButton::clicked, this, &QgsPalettedRendererWidget::loadColorTable );
|
||||||
|
connect( mExportToFileButton, &QPushButton::clicked, this, &QgsPalettedRendererWidget::saveColorTable );
|
||||||
}
|
}
|
||||||
|
|
||||||
QgsRasterRenderer *QgsPalettedRendererWidget::renderer()
|
QgsRasterRenderer *QgsPalettedRendererWidget::renderer()
|
||||||
@ -336,6 +337,36 @@ void QgsPalettedRendererWidget::loadColorTable()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QgsPalettedRendererWidget::saveColorTable()
|
||||||
|
{
|
||||||
|
QgsSettings settings;
|
||||||
|
QString lastDir = settings.value( QStringLiteral( "lastColorMapDir" ), QDir::homePath() ).toString();
|
||||||
|
QString fileName = QFileDialog::getSaveFileName( this, tr( "Save file" ), lastDir, tr( "Text (*.clr)" ) );
|
||||||
|
if ( !fileName.isEmpty() )
|
||||||
|
{
|
||||||
|
if ( !fileName.endsWith( QLatin1String( ".clr" ), Qt::CaseInsensitive ) )
|
||||||
|
{
|
||||||
|
fileName = fileName + ".clr";
|
||||||
|
}
|
||||||
|
|
||||||
|
QFile outputFile( fileName );
|
||||||
|
if ( outputFile.open( QFile::WriteOnly | QIODevice::Truncate ) )
|
||||||
|
{
|
||||||
|
QTextStream outputStream( &outputFile );
|
||||||
|
outputStream << QgsPalettedRasterRenderer::classDataToString( mModel->classData() );
|
||||||
|
outputStream.flush();
|
||||||
|
outputFile.close();
|
||||||
|
|
||||||
|
QFileInfo fileInfo( fileName );
|
||||||
|
settings.setValue( QStringLiteral( "lastColorMapDir" ), fileInfo.absoluteDir().absolutePath() );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
QMessageBox::warning( this, tr( "Write access denied" ), tr( "Write access denied. Adjust the file permissions and try again.\n\n" ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// QgsPalettedRendererModel
|
// QgsPalettedRendererModel
|
||||||
//
|
//
|
||||||
|
@ -108,6 +108,8 @@ class GUI_EXPORT QgsPalettedRendererWidget: public QgsRasterRendererWidget, priv
|
|||||||
void changeLabel();
|
void changeLabel();
|
||||||
void applyColorRamp();
|
void applyColorRamp();
|
||||||
void loadColorTable();
|
void loadColorTable();
|
||||||
|
void saveColorTable();
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // QGSPALETTEDRENDERERWIDGET_H
|
#endif // QGSPALETTEDRENDERERWIDGET_H
|
||||||
|
@ -480,6 +480,19 @@ class TestQgsRasterLayer(unittest.TestCase):
|
|||||||
self.assertEqual(classes[4].color.name(), '#0000ff')
|
self.assertEqual(classes[4].color.name(), '#0000ff')
|
||||||
self.assertEqual(classes[4].color.alpha(), 255)
|
self.assertEqual(classes[4].color.alpha(), 255)
|
||||||
|
|
||||||
|
# qgis style, with labels
|
||||||
|
qgis = '3 255 0 0 255 class 1\n4 0 255 0 200 class 2'
|
||||||
|
classes = QgsPalettedRasterRenderer.classDataFromString(qgis)
|
||||||
|
self.assertEqual(len(classes), 2)
|
||||||
|
self.assertEqual(classes[0].value, 3)
|
||||||
|
self.assertEqual(classes[0].color.name(), '#ff0000')
|
||||||
|
self.assertEqual(classes[0].color.alpha(), 255)
|
||||||
|
self.assertEqual(classes[0].label, 'class 1')
|
||||||
|
self.assertEqual(classes[1].value, 4)
|
||||||
|
self.assertEqual(classes[1].color.name(), '#00ff00')
|
||||||
|
self.assertEqual(classes[1].color.alpha(), 200)
|
||||||
|
self.assertEqual(classes[1].label, 'class 2')
|
||||||
|
|
||||||
# some bad inputs
|
# some bad inputs
|
||||||
bad = ''
|
bad = ''
|
||||||
classes = QgsPalettedRasterRenderer.classDataFromString(bad)
|
classes = QgsPalettedRasterRenderer.classDataFromString(bad)
|
||||||
@ -496,9 +509,6 @@ class TestQgsRasterLayer(unittest.TestCase):
|
|||||||
bad = '1 255 a 0'
|
bad = '1 255 a 0'
|
||||||
classes = QgsPalettedRasterRenderer.classDataFromString(bad)
|
classes = QgsPalettedRasterRenderer.classDataFromString(bad)
|
||||||
self.assertEqual(len(classes), 1)
|
self.assertEqual(len(classes), 1)
|
||||||
bad = '1 255 255 0 0 0 0 0 0 0'
|
|
||||||
classes = QgsPalettedRasterRenderer.classDataFromString(bad)
|
|
||||||
self.assertEqual(len(classes), 0)
|
|
||||||
|
|
||||||
def testLoadPalettedClassDataFromFile(self):
|
def testLoadPalettedClassDataFromFile(self):
|
||||||
# bad file
|
# bad file
|
||||||
@ -533,5 +543,16 @@ class TestQgsRasterLayer(unittest.TestCase):
|
|||||||
self.assertEqual(classes[9].value, 10)
|
self.assertEqual(classes[9].value, 10)
|
||||||
self.assertEqual(classes[9].color.name(), '#ffb600')
|
self.assertEqual(classes[9].color.name(), '#ffb600')
|
||||||
|
|
||||||
|
def testPalettedClassDataToString(self):
|
||||||
|
classes = [QgsPalettedRasterRenderer.Class(1, QColor(0, 255, 0), 'class 2'),
|
||||||
|
QgsPalettedRasterRenderer.Class(3, QColor(255, 0, 0), 'class 1')]
|
||||||
|
self.assertEqual(QgsPalettedRasterRenderer.classDataToString(classes), '1 0 255 0 255 class 2\n3 255 0 0 255 class 1')
|
||||||
|
# must be sorted by value to work OK in ArcMap
|
||||||
|
classes = [QgsPalettedRasterRenderer.Class(4, QColor(0, 255, 0), 'class 2'),
|
||||||
|
QgsPalettedRasterRenderer.Class(3, QColor(255, 0, 0), 'class 1')]
|
||||||
|
self.assertEqual(QgsPalettedRasterRenderer.classDataToString(classes),
|
||||||
|
'3 255 0 0 255 class 1\n4 0 255 0 255 class 2')
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
10
tests/testdata/raster/test.clr
vendored
Normal file
10
tests/testdata/raster/test.clr
vendored
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
1 0 0 0
|
||||||
|
2 200 200 200
|
||||||
|
3 0 110 0
|
||||||
|
4 110 65 0
|
||||||
|
5 0 0 255
|
||||||
|
6 0 89 255
|
||||||
|
7 0 174 255
|
||||||
|
8 0 255 246
|
||||||
|
9 238 255 0
|
||||||
|
10 255 182 0
|
Loading…
x
Reference in New Issue
Block a user