Branch data Line data Source code
1 : : /*************************************************************************** 2 : : qgsblureffect.cpp 3 : : ----------------- 4 : : begin : December 2014 5 : : copyright : (C) 2014 Nyall Dawson 6 : : email : nyall dot dawson at gmail dot com 7 : : ***************************************************************************/ 8 : : 9 : : /*************************************************************************** 10 : : * * 11 : : * This program is free software; you can redistribute it and/or modify * 12 : : * it under the terms of the GNU General Public License as published by * 13 : : * the Free Software Foundation; either version 2 of the License, or * 14 : : * (at your option) any later version. * 15 : : * * 16 : : ***************************************************************************/ 17 : : 18 : : #include "qgsblureffect.h" 19 : : #include "qgsimageoperation.h" 20 : : #include "qgsrendercontext.h" 21 : : #include "qgssymbollayerutils.h" 22 : : 23 : 10 : QgsPaintEffect *QgsBlurEffect::create( const QVariantMap &map ) 24 : : { 25 : 10 : QgsBlurEffect *newEffect = new QgsBlurEffect(); 26 : 10 : newEffect->readProperties( map ); 27 : 10 : return newEffect; 28 : 0 : } 29 : : 30 : 0 : void QgsBlurEffect::draw( QgsRenderContext &context ) 31 : : { 32 : 0 : if ( !source() || !enabled() || !context.painter() ) 33 : 0 : return; 34 : : 35 : 0 : switch ( mBlurMethod ) 36 : : { 37 : : case StackBlur: 38 : 0 : drawStackBlur( context ); 39 : 0 : break; 40 : : case GaussianBlur: 41 : 0 : drawGaussianBlur( context ); 42 : 0 : break; 43 : : } 44 : 0 : } 45 : : 46 : 0 : void QgsBlurEffect::drawStackBlur( QgsRenderContext &context ) 47 : : { 48 : 0 : int blurLevel = std::round( context.convertToPainterUnits( mBlurLevel, mBlurUnit, mBlurMapUnitScale ) ); 49 : 0 : QImage im = sourceAsImage( context )->copy(); 50 : 0 : QgsImageOperation::stackBlur( im, blurLevel ); 51 : 0 : drawBlurredImage( context, im ); 52 : 0 : } 53 : : 54 : 0 : void QgsBlurEffect::drawGaussianBlur( QgsRenderContext &context ) 55 : : { 56 : 0 : int blurLevel = std::round( context.convertToPainterUnits( mBlurLevel, mBlurUnit, mBlurMapUnitScale ) ); 57 : 0 : QImage *im = QgsImageOperation::gaussianBlur( *sourceAsImage( context ), blurLevel ); 58 : 0 : drawBlurredImage( context, *im ); 59 : 0 : delete im; 60 : 0 : } 61 : : 62 : 0 : void QgsBlurEffect::drawBlurredImage( QgsRenderContext &context, QImage &image ) 63 : : { 64 : : //opacity 65 : 0 : QgsImageOperation::multiplyOpacity( image, mOpacity ); 66 : : 67 : 0 : QPainter *painter = context.painter(); 68 : 0 : QgsScopedQPainterState painterState( painter ); 69 : 0 : painter->setCompositionMode( mBlendMode ); 70 : 0 : painter->drawImage( imageOffset( context ), image ); 71 : 0 : } 72 : : 73 : 0 : QVariantMap QgsBlurEffect::properties() const 74 : : { 75 : 0 : QVariantMap props; 76 : 0 : props.insert( QStringLiteral( "enabled" ), mEnabled ? QStringLiteral( "1" ) : QStringLiteral( "0" ) ); 77 : 0 : props.insert( QStringLiteral( "draw_mode" ), QString::number( static_cast< int >( mDrawMode ) ) ); 78 : 0 : props.insert( QStringLiteral( "blend_mode" ), QString::number( static_cast< int >( mBlendMode ) ) ); 79 : 0 : props.insert( QStringLiteral( "opacity" ), QString::number( mOpacity ) ); 80 : 0 : props.insert( QStringLiteral( "blur_level" ), QString::number( mBlurLevel ) ); 81 : 0 : props.insert( QStringLiteral( "blur_unit" ), QgsUnitTypes::encodeUnit( mBlurUnit ) ); 82 : 0 : props.insert( QStringLiteral( "blur_unit_scale" ), QgsSymbolLayerUtils::encodeMapUnitScale( mBlurMapUnitScale ) ); 83 : 0 : props.insert( QStringLiteral( "blur_method" ), QString::number( static_cast< int >( mBlurMethod ) ) ); 84 : 0 : return props; 85 : 0 : } 86 : : 87 : 20 : void QgsBlurEffect::readProperties( const QVariantMap &props ) 88 : : { 89 : : bool ok; 90 : 40 : QPainter::CompositionMode mode = static_cast< QPainter::CompositionMode >( props.value( QStringLiteral( "blend_mode" ) ).toInt( &ok ) ); 91 : 20 : if ( ok ) 92 : : { 93 : 10 : mBlendMode = mode; 94 : 10 : } 95 : 40 : if ( props.contains( QStringLiteral( "transparency" ) ) ) 96 : : { 97 : 0 : double transparency = props.value( QStringLiteral( "transparency" ) ).toDouble( &ok ); 98 : 0 : if ( ok ) 99 : : { 100 : 0 : mOpacity = 1.0 - transparency; 101 : 0 : } 102 : 0 : } 103 : : else 104 : : { 105 : 40 : double opacity = props.value( QStringLiteral( "opacity" ) ).toDouble( &ok ); 106 : 20 : if ( ok ) 107 : : { 108 : 10 : mOpacity = opacity; 109 : 10 : } 110 : : } 111 : : 112 : 60 : mEnabled = props.value( QStringLiteral( "enabled" ), QStringLiteral( "1" ) ).toInt(); 113 : 60 : mDrawMode = static_cast< QgsPaintEffect::DrawMode >( props.value( QStringLiteral( "draw_mode" ), QStringLiteral( "2" ) ).toInt() ); 114 : 40 : double level = props.value( QStringLiteral( "blur_level" ) ).toDouble( &ok ); 115 : 20 : if ( ok ) 116 : : { 117 : 10 : mBlurLevel = level; 118 : 20 : if ( !props.contains( QStringLiteral( "blur_unit" ) ) ) 119 : : { 120 : : // deal with pre blur unit era by assuming 96 dpi and converting pixel values as millimeters 121 : 0 : mBlurLevel *= 0.2645; 122 : 0 : } 123 : 10 : } 124 : 40 : mBlurUnit = QgsUnitTypes::decodeRenderUnit( props.value( QStringLiteral( "blur_unit" ) ).toString() ); 125 : 40 : mBlurMapUnitScale = QgsSymbolLayerUtils::decodeMapUnitScale( props.value( QStringLiteral( "blur_unit_scale" ) ).toString() ); 126 : 40 : QgsBlurEffect::BlurMethod method = static_cast< QgsBlurEffect::BlurMethod >( props.value( QStringLiteral( "blur_method" ) ).toInt( &ok ) ); 127 : 20 : if ( ok ) 128 : : { 129 : 10 : mBlurMethod = method; 130 : 10 : } 131 : 20 : } 132 : : 133 : 0 : QgsBlurEffect *QgsBlurEffect::clone() const 134 : : { 135 : 0 : QgsBlurEffect *newEffect = new QgsBlurEffect( *this ); 136 : 0 : return newEffect; 137 : 0 : } 138 : : 139 : 0 : QRectF QgsBlurEffect::boundingRect( const QRectF &rect, const QgsRenderContext &context ) const 140 : : { 141 : 0 : int blurLevel = std::round( context.convertToPainterUnits( mBlurLevel, mBlurUnit, mBlurMapUnitScale ) ); 142 : : //plus possible extension due to blur, with a couple of extra pixels thrown in for safety 143 : 0 : double spread = blurLevel * 2.0 + 10; 144 : 0 : return rect.adjusted( -spread, -spread, spread, spread ); 145 : : }