From 693bd1420a539582c8a92004d06e4a05d046ef84 Mon Sep 17 00:00:00 2001 From: ersts Date: Mon, 25 Aug 2008 23:47:18 +0000 Subject: [PATCH] -Added ability to export and load color map to/from a simple text file -Closes ticket #805 -Updaded color interpretation option Linearly to Linear -Fix problem displaying (pseudo and color map) paletted images git-svn-id: http://svn.osgeo.org/qgis/trunk/qgis@9170 c8812cc2-4d05-0410-92ff-de0c093fc19c --- src/app/qgsrasterlayerproperties.cpp | 173 ++++++++++++++++++++++-- src/app/qgsrasterlayerproperties.h | 4 + src/core/raster/qgscolorrampshader.cpp | 29 ++++- src/core/raster/qgscolorrampshader.h | 2 + src/core/raster/qgsrasterlayer.cpp | 26 +--- src/ui/qgsrasterlayerpropertiesbase.ui | 174 +++++++++++++------------ 6 files changed, 292 insertions(+), 116 deletions(-) diff --git a/src/app/qgsrasterlayerproperties.cpp b/src/app/qgsrasterlayerproperties.cpp index fca629978020..14ecdae8180b 100644 --- a/src/app/qgsrasterlayerproperties.cpp +++ b/src/app/qgsrasterlayerproperties.cpp @@ -134,9 +134,10 @@ QgsRasterLayerProperties::QgsRasterLayerProperties( QgsMapLayer *lyr, QWidget *p //setup custom colormap tab cboxColorInterpolation->addItem( tr( "Discrete" ) ); - cboxColorInterpolation->addItem( tr( "Linearly" ) ); + cboxColorInterpolation->addItem( tr( "Linear" ) ); + cboxColorInterpolation->addItem( tr( "Exact") ); cboxClassificationMode->addItem( tr( "Equal interval" ) ); - cboxClassificationMode->addItem( tr( "Quantiles" ) ); + //cboxClassificationMode->addItem( tr( "Quantiles" ) ); QStringList headerLabels; headerLabels << "Value"; @@ -291,6 +292,9 @@ QgsRasterLayerProperties::QgsRasterLayerProperties( QgsMapLayer *lyr, QWidget *p pbtnMakeBandCombinationDefault->setIcon( QgisApp::getThemeIcon( "/mActionFileSave.png" ) ); pbtnMakeContrastEnhancementAlgorithmDefault->setIcon( QgisApp::getThemeIcon( "/mActionFileSave.png" ) ); + pbtnExportColorMapToFile->setIcon( QgisApp::getThemeIcon( "/mActionFileSave.png" ) ); + pbtnLoadColorMapFromFile->setIcon( QgisApp::getThemeIcon( "/mActionFileOpen.png" ) ); + // Only do pyramids if dealing directly with GDAL. if ( mRasterLayerIsGdal ) { @@ -886,13 +890,17 @@ void QgsRasterLayerProperties::syncColormapTab() sboxNumberOfEntries->setValue( myColorRampList.size() ); //restor state of 'color interpolation' combo box - if ( QgsColorRampShader::DISCRETE == myRasterShaderFunction->getColorRampType() ) + if ( QgsColorRampShader::INTERPOLATED == myRasterShaderFunction->getColorRampType() ) + { + cboxColorInterpolation->setCurrentIndex( cboxColorInterpolation->findText( tr( "Linear" ) ) ); + } + else if ( QgsColorRampShader::DISCRETE == myRasterShaderFunction->getColorRampType() ) { cboxColorInterpolation->setCurrentIndex( cboxColorInterpolation->findText( tr( "Discrete" ) ) ); } else { - cboxColorInterpolation->setCurrentIndex( cboxColorInterpolation->findText( tr( "Linearly" ) ) ); + cboxColorInterpolation->setCurrentIndex( cboxColorInterpolation->findText( tr( "Exact" ) ) ); } } @@ -1397,13 +1405,17 @@ void QgsRasterLayerProperties::apply() } myRasterShaderFunction->setColorRampItemList( mColorRampItems ); - if ( cboxColorInterpolation->currentText() == tr( "Discrete" ) ) + if ( cboxColorInterpolation->currentText() == tr( "Linear" ) ) + { + myRasterShaderFunction->setColorRampType( QgsColorRampShader::INTERPOLATED ); + } + else if ( cboxColorInterpolation->currentText() == tr( "Discrete" ) ) { myRasterShaderFunction->setColorRampType( QgsColorRampShader::DISCRETE ); } else { - myRasterShaderFunction->setColorRampType( QgsColorRampShader::INTERPOLATED ); + myRasterShaderFunction->setColorRampType( QgsColorRampShader::EXACT ); } } else @@ -2575,10 +2587,10 @@ void QgsRasterLayerProperties::on_mClassifyButton_clicked() currentValue += intervalDiff; } } - else if ( cboxClassificationMode->currentText() == tr( "Quantiles" ) ) - { + //else if ( cboxClassificationMode->currentText() == tr( "Quantiles" ) ) + //{ //todo - } + //} //hard code color range from blue -> red for now. Allow choice of ramps in future int colorDiff = 0; @@ -2637,6 +2649,149 @@ void QgsRasterLayerProperties::handleColormapTreeWidgetDoubleClick( QTreeWidgetI } } +void QgsRasterLayerProperties::on_pbtnExportColorMapToFile_clicked() +{ + QString myFileName = QFileDialog::getSaveFileName( this, tr( "Save file" ), "/", tr( "Textfile (*.txt)" ) ); + if ( !myFileName.isEmpty() ) + { + if ( !myFileName.endsWith( ".txt", Qt::CaseInsensitive ) ) + { + myFileName = myFileName + ".txt"; + } + + QFile myOutputFile( myFileName ); + if ( myOutputFile.open( QFile::WriteOnly ) ) + { + QTextStream myOutputStream( &myOutputFile ); + myOutputStream << "# " << tr( "QGIS Generated Color Map Export File" ) << "\n"; + myOutputStream << "INTERPOLATION:"; + if ( cboxColorInterpolation->currentText() == tr( "Linear" ) ) + { + myOutputStream << "INTERPOLATED\n"; + } + else if ( cboxColorInterpolation->currentText() == tr( "Discrete" ) ) + { + myOutputStream << "DISCRETE\n"; + } + else + { + myOutputStream << "EXACT\n"; + } + + int myTopLevelItemCount = mColormapTreeWidget->topLevelItemCount(); + QTreeWidgetItem* myCurrentItem; + QColor myColor; + for ( int i = 0; i < myTopLevelItemCount; ++i ) + { + myCurrentItem = mColormapTreeWidget->topLevelItem( i ); + if ( !myCurrentItem ) + { + continue; + } + myColor = myCurrentItem->background( 1 ).color(); + myOutputStream << myCurrentItem->text( 0 ).toDouble() << ","; + myOutputStream << myColor.red() << "," << myColor.green() << "," << myColor.blue() << "," << myColor.alpha() << ","; + if(myCurrentItem->text(2) == "") + { + myOutputStream << "Color entry " << i+1 << "\n"; + } + else + { + myOutputStream << myCurrentItem->text( 2 ) << "\n"; + } + } + myOutputStream.flush(); + myOutputFile.close(); + } + else + { + QMessageBox::warning( this, tr( "Write access denied" ), tr( "Write access denied. Adjust the file permissions and try again.\n\n" ) ); + } + } +} + +void QgsRasterLayerProperties::on_pbtnLoadColorMapFromFile_clicked() +{ + int myLineCounter = 0; + bool myImportError = false; + QString myBadLines; + QString myFileName = QFileDialog::getOpenFileName( this, tr( "Open file" ), "/", tr( "Textfile (*.txt)" ) ); + QFile myInputFile( myFileName ); + if ( myInputFile.open( QFile::ReadOnly ) ) + { + //clear the current tree + mColormapTreeWidget->clear(); + + QTextStream myInputStream( &myInputFile ); + QString myInputLine; + QStringList myInputStringComponents; + + //read through the input looking for valid data + while ( !myInputStream.atEnd() ) + { + myLineCounter++; + myInputLine = myInputStream.readLine(); + if ( !myInputLine.isEmpty() ) + { + if ( !myInputLine.simplified().startsWith( "#" ) ) + { + if(myInputLine.contains("INTERPOLATION", Qt::CaseInsensitive)) + { + myInputStringComponents = myInputLine.split(":"); + if(myInputStringComponents.size() == 2) + { + if(myInputStringComponents[1].trimmed().toUpper().compare ("INTERPOLATED", Qt::CaseInsensitive) == 0) + { + cboxColorInterpolation->setCurrentIndex( cboxColorInterpolation->findText( tr( "Linear" ) ) ); + } + else if(myInputStringComponents[1].trimmed().toUpper().compare ("DISCRETE", Qt::CaseInsensitive) == 0) + { + cboxColorInterpolation->setCurrentIndex( cboxColorInterpolation->findText( tr( "Discrete" ) ) ); + } + else + { + cboxColorInterpolation->setCurrentIndex( cboxColorInterpolation->findText( tr( "Exact" ) ) ); + } + } + else + { + myImportError = true; + myBadLines = myBadLines + QString::number( myLineCounter ) + ":\t[" + myInputLine + "]\n"; + } + } + else + { + myInputStringComponents = myInputLine.split(","); + if(myInputStringComponents.size() == 6) + { + QTreeWidgetItem* newItem = new QTreeWidgetItem( mColormapTreeWidget ); + newItem->setText( 0, myInputStringComponents[0] ); + newItem->setBackground( 1, QBrush( QColor::fromRgb(myInputStringComponents[1].toInt(), myInputStringComponents[2].toInt(), myInputStringComponents[3].toInt(), myInputStringComponents[4].toInt()) ) ); + newItem->setText( 2, myInputStringComponents[5] ); + } + else + { + myImportError = true; + myBadLines = myBadLines + QString::number( myLineCounter ) + ":\t[" + myInputLine + "]\n"; + } + } + } + } + myLineCounter++; + } + + + if ( myImportError ) + { + QMessageBox::warning( this, tr( "Import Error" ), tr( "The following lines contained errors\n\n" ) + myBadLines ); + } + } + else if ( !myFileName.isEmpty() ) + { + QMessageBox::warning( this, tr( "Read access denied" ), tr( "Read access denied. Adjust the file permissions and try again.\n\n" ) ); + } +} + void QgsRasterLayerProperties::on_pbtnLoadMinMax_clicked() { if ( mRasterLayerIsGdal && ( mRasterLayer->getDrawingStyle() == QgsRasterLayer::SINGLE_BAND_GRAY || mRasterLayer->getDrawingStyle() == QgsRasterLayer::MULTI_BAND_SINGLE_BAND_GRAY || mRasterLayer->getDrawingStyle() == QgsRasterLayer::MULTI_BAND_COLOR ) ) diff --git a/src/app/qgsrasterlayerproperties.h b/src/app/qgsrasterlayerproperties.h index 3aab9e78156a..aa756b2af9ab 100644 --- a/src/app/qgsrasterlayerproperties.h +++ b/src/app/qgsrasterlayerproperties.h @@ -106,6 +106,10 @@ class QgsRasterLayerProperties : public QDialog, private Ui::QgsRasterLayerPrope void on_mDeleteEntryButton_clicked(); /**Callback for double clicks on the colormap entry widget*/ void handleColormapTreeWidgetDoubleClick( QTreeWidgetItem* item, int column ); + /**This slots saves the current color map to a file */ + void on_pbtnExportColorMapToFile_clicked(); + /**This slots saves the current color map to a file */ + void on_pbtnLoadColorMapFromFile_clicked(); /**This slot loads the minimum and maximum values from the raster band and updates the gui*/ void on_pbtnLoadMinMax_clicked(); /**This slot sets the default band combination varaible to current band combination */ diff --git a/src/core/raster/qgscolorrampshader.cpp b/src/core/raster/qgscolorrampshader.cpp index 66838e2e1ab4..1fb6407acd79 100644 --- a/src/core/raster/qgscolorrampshader.cpp +++ b/src/core/raster/qgscolorrampshader.cpp @@ -29,12 +29,16 @@ QgsColorRampShader::QgsColorRampShader( double theMinimumValue, double theMaximu bool QgsColorRampShader::generateShadedValue( double theValue, int* theReturnRedValue, int* theReturnGreenValue, int* theReturnBlueValue ) { - if ( QgsColorRampShader::DISCRETE == mColorRampType ) + if ( QgsColorRampShader::INTERPOLATED == mColorRampType ) + { + return getInterpolatedColor( theValue, theReturnRedValue, theReturnGreenValue, theReturnBlueValue ); + } + else if ( QgsColorRampShader::DISCRETE == mColorRampType ) { return getDiscreteColor( theValue, theReturnRedValue, theReturnGreenValue, theReturnBlueValue ); } - return getInterpolatedColor( theValue, theReturnRedValue, theReturnGreenValue, theReturnBlueValue ); + return getExactColor( theValue, theReturnRedValue, theReturnGreenValue, theReturnBlueValue ); } bool QgsColorRampShader::generateShadedValue( double theRedValue, double theGreenValue, double theBlueValue, int* theReturnRedValue, int* theReturnGreenValue, int* theReturnBlueValue ) @@ -91,6 +95,27 @@ bool QgsColorRampShader::getDiscreteColor( double theValue, int* theReturnRedVal return false; // value not found } +bool QgsColorRampShader::getExactColor( double theValue, int* theReturnRedValue, int* theReturnGreenValue, int* theReturnBlueValue ) +{ + if ( mColorRampItemList.count() <= 0 ) + { + return false; + } + QList::const_iterator it; + for ( it = mColorRampItemList.begin(); it != mColorRampItemList.end(); ++it ) + { + if ( theValue == it->value ) + { + *theReturnRedValue = it->color.red(); + *theReturnGreenValue = it->color.green(); + *theReturnBlueValue = it->color.blue(); + return true; + } + } + + return false; // value not found +} + bool QgsColorRampShader::getInterpolatedColor( double theValue, int* theReturnRedValue, int* theReturnGreenValue, int* theReturnBlueValue ) { if ( mColorRampItemList.count() <= 0 ) diff --git a/src/core/raster/qgscolorrampshader.h b/src/core/raster/qgscolorrampshader.h index f17bdc0218ef..73a52a9f2a4f 100644 --- a/src/core/raster/qgscolorrampshader.h +++ b/src/core/raster/qgscolorrampshader.h @@ -73,6 +73,8 @@ class CORE_EXPORT QgsColorRampShader : public QgsRasterShaderFunction private: /**Gets the color for a pixel value from the classification vector mValueClassification. Assigns the color of the lower class for every pixel between two class breaks.*/ bool getDiscreteColor( double, int*, int*, int* ); + /**Gets the color for a pixel value from the classification vector mValueClassification. Assigns the color of the exact matching value in the color ramp item list */ + bool getExactColor( double, int*, int*, int* ); /**Gets the color for a pixel value from the classification vector mValueClassification. Interpolates the color between two class breaks linearly.*/ bool getInterpolatedColor( double, int*, int*, int* ); diff --git a/src/core/raster/qgsrasterlayer.cpp b/src/core/raster/qgsrasterlayer.cpp index 0f202a56ab35..419b44fb7dd8 100644 --- a/src/core/raster/qgsrasterlayer.cpp +++ b/src/core/raster/qgsrasterlayer.cpp @@ -1746,32 +1746,12 @@ void QgsRasterLayer::drawPalettedSingleBandPseudoColor( QPainter * theQPainter, mRasterShader->setMinimumValue( myMinimumValue ); mRasterShader->setMaximumValue( myMaximumValue ); - QgsColorTable *myColorTable = &( myRasterBandStats.colorTable ); - int myRedLUTValue = 0; - int myGreenLUTValue = 0; - int myBlueLUTValue; - double myPixelValue = 0.0; int myRedValue = 0; int myGreenValue = 0; int myBlueValue = 0; int myAlphaValue = 0; - //Set a pointer to the LUT color channel - int* myGrayValue; - if ( theColorQString == mRedBandName ) - { - myGrayValue = &myRedLUTValue; - } - else if ( theColorQString == mGreenBandName ) - { - myGrayValue = &myGreenLUTValue; - } - else - { - myGrayValue = &myBlueLUTValue; - } - for ( int myColumn = 0; myColumn < theRasterViewPort->drawableAreaYDim; ++myColumn ) { for ( int myRow = 0; myRow < theRasterViewPort->drawableAreaXDim; ++myRow ) @@ -1793,11 +1773,7 @@ void QgsRasterLayer::drawPalettedSingleBandPseudoColor( QPainter * theQPainter, continue; } - bool found = myColorTable->color( myPixelValue, &myRedLUTValue, &myGreenLUTValue, &myBlueLUTValue ); - if ( !found ) continue; - - - if ( !mRasterShader->generateShadedValue(( double )*myGrayValue, &myRedValue, &myGreenValue, &myBlueValue ) ) + if ( !mRasterShader->generateShadedValue(myPixelValue, &myRedValue, &myGreenValue, &myBlueValue ) ) { continue; } diff --git a/src/ui/qgsrasterlayerpropertiesbase.ui b/src/ui/qgsrasterlayerpropertiesbase.ui index 91d594dd9acd..456bc58384d4 100644 --- a/src/ui/qgsrasterlayerpropertiesbase.ui +++ b/src/ui/qgsrasterlayerpropertiesbase.ui @@ -1199,44 +1199,6 @@ Colormap - - 11 - - - 11 - - - 11 - - - 11 - - - - - Qt::Horizontal - - - - 71 - 20 - - - - - - - - Qt::Horizontal - - - - 61 - 20 - - - - @@ -1270,56 +1232,20 @@ - + Qt::Horizontal - 341 + 71 20 - - - - Delete entry - - - - - - - Classify - - - - - - - 3 - - - - 1 - - - - - 1 - - - - - 2 - - - - - + 11 @@ -1345,7 +1271,20 @@ - + + + + Qt::Horizontal + + + + 61 + 20 + + + + + 11 @@ -1371,6 +1310,81 @@ + + + + Classify + + + + + + + Delete entry + + + + + + + Qt::Horizontal + + + + 281 + 27 + + + + + + + + Load color map from file + + + ... + + + ../../images/themes/default/mActionFolder.png + + + + + + + Export color map to file + + + ... + + + ../../images/themes/default/mActionFileSave.png + + + + + + + 3 + + + + 1 + + + + + 1 + + + + + 2 + + + + @@ -1798,8 +1812,8 @@ <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'DejaVu Sans'; font-size:10pt; font-weight:400; font-style:normal;"> -<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans Serif'; font-size:9pt;"></p></body></html> +</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"></p></body></html>