// Process a colorization and update resultant HSL & RGB values void QgsHueSaturationFilter::processColorization( int &r, int &g, int &b, int &h, int &s, int &l ) { QColor myColor; // Overwrite hue and saturation with values from colorize color h = mColorizeH; s = mColorizeS; QColor colorizedColor = QColor::fromHsl( h, s, l ); if ( mColorizeStrength == 100 ) { // Full strength myColor = colorizedColor; // RGB may have changed, update them myColor.getRgb( &r, &g, &b ); } else { // Get rgb for colorized color int colorizedR, colorizedG, colorizedB; colorizedColor.getRgb( &colorizedR, &colorizedG, &colorizedB ); // Now, linearly scale by colorize strength double p = ( double ) mColorizeStrength / 100.; r = p * colorizedR + ( 1 - p ) * r; g = p * colorizedG + ( 1 - p ) * g; b = p * colorizedB + ( 1 - p ) * b; // RGB changed, so update HSL values myColor = QColor::fromRgb( r, g, b ); myColor.getHsl( &h, &s, &l ); } }
void tst_QColor::setHsl() { QColor color; for (int A = 0; A <= USHRT_MAX; ++A) { { // 0-255 int a = A >> 8; color.setHsl(0, 0, 0, a); QCOMPARE(color.alpha(), a); int h, s, l, a2; color.getHsv(&h, &s, &l, &a2); QCOMPARE(a2, a); } { // 0.0-1.0 qreal a = A / qreal(USHRT_MAX); color.setHslF(0.0, 0.0, 0.0, a); QCOMPARE(color.alphaF(), a); qreal h, s, l, a2; color.getHslF(&h, &s, &l, &a2); QCOMPARE(a2, a); } } for (int H = 0; H < 36000; ++H) { { // 0-255 int h = H / 100; color.setHsl(h, 0, 0, 0); QCOMPARE(color.hslHue(), h); int h2, s, l, a; color.getHsl(&h2, &s, &l, &a); QCOMPARE(h2, h); } { // 0.0-1.0 qreal h = H / 36000.0; color.setHslF(h, 0.0, 0.0, 0.0); QCOMPARE(color.hslHueF(), h); qreal h2, s, l, a; color.getHslF(&h2, &s, &l, &a); QCOMPARE(h2, h); } } for (int S = 0; S <= USHRT_MAX; ++S) { { // 0-255 int s = S >> 8; color.setHsl(0, s, 0, 0); QCOMPARE(color.hslSaturation(), s); int h, s2, l, a; color.getHsl(&h, &s2, &l, &a); QCOMPARE(s2, s); } { // 0.0-1.0 qreal s = S / qreal(USHRT_MAX); color.setHslF(0.0, s, 0.0, 0.0); QCOMPARE(color.hslSaturationF(), s); qreal h, s2, l, a; color.getHslF(&h, &s2, &l, &a); QCOMPARE(s2, s); } } for (int L = 0; L <= USHRT_MAX; ++L) { { // 0-255 int l = L >> 8; color.setHsl(0, 0, l, 0); QCOMPARE(color.lightness(), l); int h, s, l2, a; color.getHsl(&h, &s, &l2, &a); QCOMPARE(l2, l); } { // 0.0-1.0 qreal l = L / qreal(USHRT_MAX); color.setHslF(0.0, 0.0, l, 0.0); QCOMPARE(color.lightnessF(), l); qreal h, s, l2, a; color.getHslF(&h, &s, &l2, &a); QCOMPARE(l2, l); } } }
QColor color_selector::change_param_by_type (QColor color, int value, color_single_selector_type type) { int h = 0, s, v, l, r, g, b, a, c, m, y, k; switch (type) { case color_single_selector_type::HSV_SATURATION: case color_single_selector_type::HSV_HUE: case color_single_selector_type::HSV_VALUE: case color_single_selector_type::HSV_ALPHA: color.getHsv (&h, &s, &v, &a); break; case color_single_selector_type::HSL_HUE: case color_single_selector_type::HSL_SATURATION: case color_single_selector_type::HSL_LIGHTNESS: case color_single_selector_type::HSL_ALPHA: color.getHsl (&h, &s, &l, &a); break; case color_single_selector_type::RGB_RED: case color_single_selector_type::RGB_GREEN: case color_single_selector_type::RGB_BLUE: case color_single_selector_type::RGB_ALPHA: color.getRgb (&r, &g, &b, &a); break; case color_single_selector_type::CMYK_CYAN: case color_single_selector_type::CMYK_MAGENTA: case color_single_selector_type::CMYK_YELLOW: case color_single_selector_type::CMYK_BLACK: case color_single_selector_type::CMYK_ALPHA: color.getCmyk (&c, &m, &y, &k, &a); break; } if (value < 0) value = 0; if (value > get_param_maximum_by_type (type)) value = get_param_maximum_by_type (type); if (h < 0) h = 0; switch (type) { case color_single_selector_type::HSL_HUE: color.setHsl (value, s, l, a); break; case color_single_selector_type::HSV_HUE: color.setHsv (value, s, v, a); break; case color_single_selector_type::HSL_LIGHTNESS: color.setHsl (h, s, value, a); break; case color_single_selector_type::HSL_SATURATION: color.setHsl (h, value, l, a); break; case color_single_selector_type::HSV_SATURATION: color.setHsv (h, value, v, a); break; case color_single_selector_type::HSV_VALUE: color.setHsv (h, s, value, a); break; case color_single_selector_type::RGB_RED: color.setRgb (value, g, b, a); break; case color_single_selector_type::RGB_GREEN: color.setRgb (r, value, b, a); break; case color_single_selector_type::RGB_BLUE: color.setRgb (r, g, value, a); break; case color_single_selector_type::RGB_ALPHA: color.setRgb (r, g, b, value); break; case color_single_selector_type::CMYK_CYAN: color.setCmyk (value, m, y, k, a); break; case color_single_selector_type::CMYK_MAGENTA: color.setCmyk (c, value, y, k, a); break; case color_single_selector_type::CMYK_YELLOW: color.setCmyk (c, m, value, k, a); break; case color_single_selector_type::CMYK_BLACK: color.setCmyk (c, m, y, value, a); break; case color_single_selector_type::HSL_ALPHA: color.setHsl (h, s, l, value); break; case color_single_selector_type::HSV_ALPHA: color.setHsv (h, s, v, value); break; case color_single_selector_type::CMYK_ALPHA: color.setCmyk (c, m, y, k, value); break; } return color; }
// Process a change in saturation and update resultant HSL & RGB values void QgsHueSaturationFilter::processSaturation( int &r, int &g, int &b, int &h, int &s, int &l ) { QColor myColor; // Are we converting layer to grayscale? switch ( mGrayscaleMode ) { case GrayscaleLightness: { // Lightness mode, set saturation to zero s = 0; // Saturation changed, so update rgb values myColor = QColor::fromHsl( h, s, l ); myColor.getRgb( &r, &g, &b ); return; } case GrayscaleLuminosity: { // Grayscale by weighted rgb components int luminosity = 0.21 * r + 0.72 * g + 0.07 * b; r = g = b = luminosity; // RGB changed, so update HSL values myColor = QColor::fromRgb( r, g, b ); myColor.getHsl( &h, &s, &l ); return; } case GrayscaleAverage: { // Grayscale by average of rgb components int average = ( r + g + b ) / 3; r = g = b = average; // RGB changed, so update HSL values myColor = QColor::fromRgb( r, g, b ); myColor.getHsl( &h, &s, &l ); return; } case GrayscaleOff: { // Not being made grayscale, do saturation change if ( mSaturationScale < 1 ) { // Lowering the saturation. Use a simple linear relationship s = qMin(( int )( s * mSaturationScale ), 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 - ( s / 255. ), pow( mSaturationScale, 2 ) ) ) ), 255 ); } // Saturation changed, so update rgb values myColor = QColor::fromHsl( h, s, l ); myColor.getRgb( &r, &g, &b ); return; } } }
QgsRasterBlock * QgsHueSaturationFilter::block( int bandNo, QgsRectangle const & extent, int width, int height, QgsRasterBlockFeedback* feedback ) { Q_UNUSED( bandNo ); QgsDebugMsgLevel( QString( "width = %1 height = %2 extent = %3" ).arg( width ).arg( height ).arg( extent.toString() ), 4 ); QgsRasterBlock *outputBlock = new QgsRasterBlock(); if ( !mInput ) { return outputBlock; } // At this moment we know that we read rendered image int bandNumber = 1; QgsRasterBlock *inputBlock = mInput->block( bandNumber, extent, width, height, feedback ); if ( !inputBlock || inputBlock->isEmpty() ) { QgsDebugMsg( "No raster data!" ); delete inputBlock; return outputBlock; } if ( mSaturation == 0 && mGrayscaleMode == GrayscaleOff && !mColorizeOn ) { QgsDebugMsgLevel( "No hue/saturation change.", 4 ); delete outputBlock; return inputBlock; } if ( !outputBlock->reset( Qgis::ARGB32_Premultiplied, width, height ) ) { delete inputBlock; return outputBlock; } // adjust image QRgb myNoDataColor = qRgba( 0, 0, 0, 0 ); QRgb myRgb; QColor myColor; int h, s, l; int r, g, b, alpha; double alphaFactor = 1.0; for ( qgssize i = 0; i < ( qgssize )width*height; i++ ) { if ( inputBlock->color( i ) == myNoDataColor ) { outputBlock->setColor( i, myNoDataColor ); continue; } myRgb = inputBlock->color( i ); myColor = QColor( myRgb ); // Alpha must be taken from QRgb, since conversion from QRgb->QColor loses alpha alpha = qAlpha( myRgb ); if ( alpha == 0 ) { // totally transparent, no changes required outputBlock->setColor( i, myRgb ); continue; } // Get rgb for color myColor.getRgb( &r, &g, &b ); if ( alpha != 255 ) { // Semi-transparent pixel. We need to adjust the colors since we are using Qgis::ARGB32_Premultiplied // and color values have been premultiplied by alpha alphaFactor = alpha / 255.; r /= alphaFactor; g /= alphaFactor; b /= alphaFactor; myColor = QColor::fromRgb( r, g, b ); } myColor.getHsl( &h, &s, &l ); // Changing saturation? if (( mGrayscaleMode != GrayscaleOff ) || ( mSaturationScale != 1 ) ) { processSaturation( r, g, b, h, s, l ); } // Colorizing? if ( mColorizeOn ) { processColorization( r, g, b, h, s, l ); } // Convert back to rgb if ( alpha != 255 ) { // Transparent pixel, need to premultiply color components r *= alphaFactor; g *= alphaFactor; b *= alphaFactor; } outputBlock->setColor( i, qRgba( r, g, b, alpha ) ); } delete inputBlock; return outputBlock; }