Skip to content

Commit

Permalink
[FEATURE] Option to convert a raster to grayscale with choice of desa…
Browse files Browse the repository at this point in the history
…turation mode (lightness, luminosity, average) (fix #5837)
  • Loading branch information
nyalldawson committed Mar 26, 2013
1 parent 030960e commit 3d02fbe
Show file tree
Hide file tree
Showing 5 changed files with 136 additions and 18 deletions.
25 changes: 25 additions & 0 deletions src/app/qgsrasterlayerproperties.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,9 @@ QgsRasterLayerProperties::QgsRasterLayerProperties( QgsMapLayer* lyr, QgsMapCanv
connect( sliderSaturation, SIGNAL( valueChanged( int ) ), spinBoxSaturation, SLOT( setValue( int ) ) );
connect( spinBoxSaturation, SIGNAL( valueChanged( int ) ), sliderSaturation, SLOT( setValue( int ) ) );

// enable or disable saturation slider and spin box depending on grayscale combo choice
connect( comboGrayscale, SIGNAL( currentIndexChanged( int ) ), this, SLOT( toggleSaturationControls( int ) ) );

// enable or disable Build Pyramids button depending on selection in pyramid list
connect( lbxPyramidResolutions, SIGNAL( itemSelectionChanged() ), this, SLOT( toggleBuildPyramidsButton() ) );

Expand Down Expand Up @@ -255,6 +258,10 @@ QgsRasterLayerProperties::QgsRasterLayerProperties( QgsMapLayer* lyr, QgsMapCanv
if ( hueSaturationFilter )
{
sliderSaturation->setValue( hueSaturationFilter->saturation() );
comboGrayscale->setCurrentIndex(( int ) hueSaturationFilter->grayscaleMode() );

// Set initial state of saturation controls based on grayscale mode choice
toggleSaturationControls( hueSaturationFilter->grayscaleMode() == QgsHueSaturationFilter::GrayscaleOff );
}

//blend mode
Expand Down Expand Up @@ -820,6 +827,7 @@ void QgsRasterLayerProperties::apply()
if ( hueSaturationFilter )
{
hueSaturationFilter->setSaturation( sliderSaturation->value() );
hueSaturationFilter->setGrayscaleMode(( QgsHueSaturationFilter::GrayscaleMode ) comboGrayscale->currentIndex() );
}


Expand Down Expand Up @@ -1456,6 +1464,23 @@ void QgsRasterLayerProperties::sliderTransparency_valueChanged( int theValue )
lblTransparencyPercent->setText( QString::number( myInt ) + "%" );
}//sliderTransparency_valueChanged

void QgsRasterLayerProperties::toggleSaturationControls( int theValue )
{
// Enable or disable saturation controls based on choice of grayscale mode
if ( theValue == 0 )
{
// Grayscale set to off, enable controls
sliderSaturation->setEnabled( true );
spinBoxSaturation->setEnabled( true );
}
else
{
// A grayscale mode is selected, disable saturation controls
sliderSaturation->setEnabled( false );
spinBoxSaturation->setEnabled( false );
}
}

QLinearGradient QgsRasterLayerProperties::redGradient()
{
//define a gradient
Expand Down
3 changes: 3 additions & 0 deletions src/app/qgsrasterlayerproperties.h
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,9 @@ class QgsRasterLayerProperties : public QDialog, private Ui::QgsRasterLayerPrope
/**Enable or disable Build pyramids button depending on selection in pyramids list*/
void toggleBuildPyramidsButton();

/**Enable or disable saturation controls depending on choice of grayscale mode */
void toggleSaturationControls( int theValue );

/** Update items in pipe list */
void pipeItemClicked( QTreeWidgetItem * item, int column );

Expand Down
68 changes: 52 additions & 16 deletions src/core/raster/qgshuesaturationfilter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@

QgsHueSaturationFilter::QgsHueSaturationFilter( QgsRasterInterface* input )
: QgsRasterInterface( input ),
mSaturation( 0 )
mSaturation( 0 ),
mGrayscaleMode( QgsHueSaturationFilter::GrayscaleOff )
{
}

Expand Down Expand Up @@ -128,9 +129,9 @@ QgsRasterBlock * QgsHueSaturationFilter::block( int bandNo, QgsRectangle const
return outputBlock;
}

if ( mSaturation == 0 )
if ( mSaturation == 0 && mGrayscaleMode == GrayscaleOff )
{
QgsDebugMsg( "No saturation change." );
QgsDebugMsg( "No hue/saturation change." );
delete outputBlock;
return inputBlock;
}
Expand All @@ -144,7 +145,8 @@ QgsRasterBlock * QgsHueSaturationFilter::block( int bandNo, QgsRectangle const
// adjust image
QRgb myNoDataColor = qRgba( 0, 0, 0, 0 );
QColor myColor;
int h, s, v;
int h, s, l;
int r, g, b;

// Scale saturation value to [0-2], where 0 = desaturated
double saturationScale = (( double ) mSaturation / 100 ) + 1;
Expand All @@ -157,24 +159,56 @@ QgsRasterBlock * QgsHueSaturationFilter::block( int bandNo, QgsRectangle const
continue;
}

// Get current color in hsv
// Get hsv and rgb for color
myColor = QColor( inputBlock->color( i ) );
myColor.getHsv( &h, &s, &v );
myColor.getHsl( &h, &s, &l );
myColor.getRgb( &r, &g, &b );

if ( saturationScale < 1 )
switch ( mGrayscaleMode )
{
// Lowering the saturation. Use a simple linear relationship
s = qMin(( int )( s * saturationScale ), 255 );
}
else
{
// Raising the saturation. Use a saturation curve to prevent
// clipping at maximum saturation with ugly results.
s = qMin(( int )( 255. * ( 1 - pow( 1 - (( double )s / 255. ) , saturationScale * 2 ) ) ), 255 );
case GrayscaleLightness:
{
// Lightness mode, set saturation to zero
s = 0;
myColor = QColor::fromHsl( h, s, l );
break;
}
case GrayscaleLuminosity:
{
// Grayscale by weighted rgb components
int luminosity = 0.21 * r + 0.72 * g + 0.07 * b;
r = g = b = luminosity;
myColor = QColor::fromRgb( r, g, b );
break;
}
case GrayscaleAverage:
{
// Grayscale by average of rgb components
int average = ( r + g + b ) / 3;
r = g = b = average;
myColor = QColor::fromRgb( r, g, b );
break;
}
case GrayscaleOff:
{
// Not being made grayscale, do saturation change
if ( saturationScale < 1 )
{
// Lowering the saturation. Use a simple linear relationship
s = qMin(( int )( s * saturationScale ), 255 );
}
else
{
// Raising the saturation. Use a saturation curve to prevent
// clipping at maximum saturation with ugly results.
s = qMin(( int )( 255. * ( 1 - pow( 1 - (( double )s / 255. ) , saturationScale * 2 ) ) ), 255 );
}
myColor = QColor::fromHsl( h, s, l );
break;
}
}

// Convert back to rgb
myColor = QColor::fromHsv( h, s, v );
outputBlock->setColor( i, myColor.rgb() );
}

Expand All @@ -192,6 +226,7 @@ void QgsHueSaturationFilter::writeXML( QDomDocument& doc, QDomElement& parentEle
QDomElement filterElem = doc.createElement( "huesaturation" );

filterElem.setAttribute( "saturation", QString::number( mSaturation ) );
filterElem.setAttribute( "grayscaleMode", QString::number( mGrayscaleMode ) );
parentElem.appendChild( filterElem );
}

Expand All @@ -203,4 +238,5 @@ void QgsHueSaturationFilter::readXML( const QDomElement& filterElem )
}

mSaturation = filterElem.attribute( "saturation", "0" ).toInt();
mGrayscaleMode = ( QgsHueSaturationFilter::GrayscaleMode )filterElem.attribute( "grayscaleMode", "0" ).toInt();
}
16 changes: 16 additions & 0 deletions src/core/raster/qgshuesaturationfilter.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,16 @@ class QDomElement;
class CORE_EXPORT QgsHueSaturationFilter : public QgsRasterInterface
{
public:

// Available modes for converting a raster to grayscale
enum GrayscaleMode
{
GrayscaleOff,
GrayscaleLightness,
GrayscaleLuminosity,
GrayscaleAverage
};

QgsHueSaturationFilter( QgsRasterInterface *input = 0 );
~QgsHueSaturationFilter();

Expand All @@ -45,6 +55,9 @@ class CORE_EXPORT QgsHueSaturationFilter : public QgsRasterInterface
void setSaturation( int saturation ) { mSaturation = qBound( -100, saturation, 100 ); }
int saturation() const { return mSaturation; }

void setGrayscaleMode( QgsHueSaturationFilter::GrayscaleMode grayscaleMode ) { mGrayscaleMode = grayscaleMode; }
QgsHueSaturationFilter::GrayscaleMode grayscaleMode() const { return mGrayscaleMode; }

void writeXML( QDomDocument& doc, QDomElement& parentElem );

/**Sets base class members from xml. Usually called from create() methods of subclasses*/
Expand All @@ -54,6 +67,9 @@ class CORE_EXPORT QgsHueSaturationFilter : public QgsRasterInterface
/**Current saturation value. Range: -100 (desaturated) ... 0 (no change) ... 100 (increased)*/
int mSaturation;

/**Current grayscale mode*/
QgsHueSaturationFilter::GrayscaleMode mGrayscaleMode;

};

#endif // QGSHUESATURATIONFILTER_H
42 changes: 40 additions & 2 deletions src/ui/qgsrasterlayerpropertiesbase.ui
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@
<bool>true</bool>
</property>
<layout class="QGridLayout" name="_7">
<item row="0" column="0">
<item row="0" column="1">
<widget class="QSlider" name="sliderSaturation">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
Expand All @@ -288,7 +288,7 @@
</property>
</widget>
</item>
<item row="0" column="1">
<item row="0" column="2">
<widget class="QSpinBox" name="spinBoxSaturation">
<property name="minimum">
<number>-100</number>
Expand All @@ -304,6 +304,44 @@
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QLabel" name="labelSaturation">
<property name="text">
<string>Saturation</string>
</property>
</widget>
</item>
<item row="0" column="4">
<widget class="QLabel" name="labelGrayscale">
<property name="text">
<string>Grayscale</string>
</property>
</widget>
</item>
<item row="0" column="5">
<widget class="QComboBox" name="comboGrayscale">
<item>
<property name="text">
<string>Off</string>
</property>
</item>
<item>
<property name="text">
<string>By lightness</string>
</property>
</item>
<item>
<property name="text">
<string>By luminosity</string>
</property>
</item>
<item>
<property name="text">
<string>By average</string>
</property>
</item>
</widget>
</item>
</layout>
</widget>
</item>
Expand Down

0 comments on commit 3d02fbe

Please sign in to comment.