1/**************************************************************************** 2** 3** Copyright (C) 2017 The Qt Company Ltd. 4** Copyright (C) 2017 Jolla Ltd, author: <gunnar.sletta@jollamobile.com> 5** Contact: https://www.qt.io/licensing/ 6** 7** This file is part of the Qt Graphical Effects module. 8** 9** $QT_BEGIN_LICENSE:LGPL$ 10** Commercial License Usage 11** Licensees holding valid commercial Qt licenses may use this file in 12** accordance with the commercial license agreement provided with the 13** Software or, alternatively, in accordance with the terms contained in 14** a written agreement between you and The Qt Company. For licensing terms 15** and conditions see https://www.qt.io/terms-conditions. For further 16** information use the contact form at https://www.qt.io/contact-us. 17** 18** GNU Lesser General Public License Usage 19** Alternatively, this file may be used under the terms of the GNU Lesser 20** General Public License version 3 as published by the Free Software 21** Foundation and appearing in the file LICENSE.LGPL3 included in the 22** packaging of this file. Please review the following information to 23** ensure the GNU Lesser General Public License version 3 requirements 24** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. 25** 26** GNU General Public License Usage 27** Alternatively, this file may be used under the terms of the GNU 28** General Public License version 2.0 or (at your option) the GNU General 29** Public license version 3 or any later version approved by the KDE Free 30** Qt Foundation. The licenses are as published by the Free Software 31** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 32** included in the packaging of this file. Please review the following 33** information to ensure the GNU General Public License requirements will 34** be met: https://www.gnu.org/licenses/gpl-2.0.html and 35** https://www.gnu.org/licenses/gpl-3.0.html. 36** 37** $QT_END_LICENSE$ 38** 39****************************************************************************/ 40 41import QtQuick 2.12 42import QtQuick.Window 2.12 43import QtGraphicalEffects.private 1.12 44 45/*! 46 \qmltype GaussianBlur 47 \inqmlmodule QtGraphicalEffects 48 \since QtGraphicalEffects 1.0 49 \inherits QtQuick2::Item 50 \ingroup qtgraphicaleffects-blur 51 \brief Applies a higher quality blur effect. 52 53 GaussianBlur effect softens the image by blurring it with an algorithm that 54 uses the Gaussian function to calculate the effect. The effect produces 55 higher quality than \l{QtGraphicalEffects::FastBlur}{FastBlur}, but is 56 slower to render. 57 58 \table 59 \header 60 \li Source 61 \li Effect applied 62 \row 63 \li \image Original_bug.png 64 \li \image GaussianBlur_bug.png 65 \endtable 66 67 \note This effect is available when running with OpenGL. 68 69 \section1 Example 70 71 The following example shows how to apply the effect. 72 \snippet GaussianBlur-example.qml example 73 74 Performing blur live is a costly operation. Fullscreen gaussian blur 75 with even a moderate number of samples will only run at 60 fps on highend 76 graphics hardware. 77 78*/ 79Item { 80 id: root 81 82 /*! 83 This property defines the source item that is going to be blurred. 84 85 \note It is not supported to let the effect include itself, for 86 instance by setting source to the effect's parent. 87 */ 88 property variant source 89 90 /*! 91 This property defines the distance of the neighboring pixels which 92 affect the blurring of an individual pixel. A larger radius increases 93 the blur effect. 94 95 The ideal blur is achieved by selecting \c samples and \c radius such 96 that \c {samples = 1 + radius * 2}, such as: 97 98 \table 99 \header \li Radius \li Samples 100 \row \li 0 \e{(no blur)} \li 1 101 \row \li 1 \li 3 102 \row \li 2 \li 5 103 \row \li 3 \li 7 104 \endtable 105 106 The value ranges from 0.0 (no blur) to inf. By default, the property is 107 set to \c floor(samples / 2.0). 108 109 \table 110 \header 111 \li Output examples with different radius values 112 \li 113 \li 114 \row 115 \li \image GaussianBlur_radius1.png 116 \li \image GaussianBlur_radius2.png 117 \li \image GaussianBlur_radius3.png 118 \row 119 \li \b { radius: 0 } 120 \li \b { radius: 4 } 121 \li \b { radius: 8 } 122 \row 123 \li \l samples: 16 124 \li \l samples: 16 125 \li \l samples: 16 126 \row 127 \li \l deviation: 3 128 \li \l deviation: 3 129 \li \l deviation: 3 130 \endtable 131 132 */ 133 property real radius: Math.floor(samples / 2); 134 135 /*! 136 This property defines how many samples are taken per pixel when blur 137 calculation is done. Larger value produces better quality, but is slower 138 to render. 139 140 Ideally, this value should be twice as large as the highest required 141 radius value plus 1, for example, if the radius is animated between 0.0 142 and 4.0, samples should be set to 9. 143 144 By default, the property is set to \c 9. 145 146 \note This property is not intended to be animated. Changing this property may 147 cause the underlying OpenGL shaders to be recompiled. 148 149 */ 150 property int samples: 9 151 152 /*! 153 This property is a parameter to the gaussian function that is used when 154 calculating neighboring pixel weights for the blurring. A larger 155 deviation causes image to appear more blurry, but it also reduces the 156 quality of the blur. A very large deviation value causes the effect to 157 look a bit similar to what, for exmple, a box blur algorithm produces. A 158 too small deviation values makes the effect insignificant for the pixels 159 near the radius. 160 161 \inlineimage GaussianBlur_deviation_graph.png 162 \caption The image above shows the Gaussian function with two different 163 deviation values, yellow (1) and cyan (2.7). The y-axis shows the 164 weights, the x-axis shows the pixel distance. 165 166 The value ranges from 0.0 (no deviation) to inf (maximum deviation). By 167 default, devaition is binded to radius. When radius increases, deviation 168 is automatically increased linearly. With the radius value of 8, the 169 deviation default value becomes approximately 2.7034. This value 170 produces a compromise between the blur quality and overall blurriness. 171 172 \table 173 \header 174 \li Output examples with different deviation values 175 \li 176 \li 177 \row 178 \li \image GaussianBlur_deviation1.png 179 \li \image GaussianBlur_deviation2.png 180 \li \image GaussianBlur_deviation3.png 181 \row 182 \li \b { deviation: 1 } 183 \li \b { deviation: 2 } 184 \li \b { deviation: 4 } 185 \row 186 \li \l radius: 8 187 \li \l radius: 8 188 \li \l radius: 8 189 \row 190 \li \l samples: 16 191 \li \l samples: 16 192 \li \l samples: 16 193 \endtable 194 195 */ 196 property real deviation: (radius + 1) / 3.3333 197 198 /*! 199 This property defines the blur behavior near the edges of the item, 200 where the pixel blurring is affected by the pixels outside the source 201 edges. 202 203 If the property is set to \c true, the pixels outside the source are 204 interpreted to be transparent, which is similar to OpenGL 205 clamp-to-border extension. The blur is expanded slightly outside the 206 effect item area. 207 208 If the property is set to \c false, the pixels outside the source are 209 interpreted to contain the same color as the pixels at the edge of the 210 item, which is similar to OpenGL clamp-to-edge behavior. The blur does 211 not expand outside the effect item area. 212 213 By default, the property is set to \c false. 214 215 \table 216 \header 217 \li Output examples with different transparentBorder values 218 \li 219 \li 220 \row 221 \li \image GaussianBlur_transparentBorder1.png 222 \li \image GaussianBlur_transparentBorder2.png 223 \row 224 \li \b { transparentBorder: false } 225 \li \b { transparentBorder: true } 226 \row 227 \li \l radius: 8 228 \li \l radius: 8 229 \row 230 \li \l samples: 16 231 \li \l samples: 16 232 \row 233 \li \l deviation: 2.7 234 \li \l deviation: 2.7 235 \endtable 236 */ 237 property bool transparentBorder: false 238 239 /*! 240 This property allows the effect output pixels to be cached in order to 241 improve the rendering performance. 242 Every time the source or effect properties are changed, the pixels in 243 the cache must be updated. Memory consumption is increased, because an 244 extra buffer of memory is required for storing the effect output. 245 246 It is recommended to disable the cache when the source or the effect 247 properties are animated. 248 249 By default, the property is set to \c false. 250 251 */ 252 property bool cached: false 253 254 255 // private members... 256 /*! \internal */ 257 property int _paddedTexWidth: transparentBorder ? width + 2 * radius: width; 258 /*! \internal */ 259 property int _paddedTexHeight: transparentBorder ? height + 2 * radius: height; 260 /*! \internal */ 261 property int _kernelRadius: Math.max(0, samples / 2); 262 /*! \internal */ 263 property int _kernelSize: _kernelRadius * 2 + 1; 264 /*! \internal */ 265 property real _dpr: Screen.devicePixelRatio; 266 /*! \internal */ 267 property bool _alphaOnly: false; 268 /*! \internal */ 269 property var _maskSource: undefined 270 271 /*! \internal */ 272 property alias _output: sourceProxy.output; 273 /*! \internal */ 274 property alias _outputRect: sourceProxy.sourceRect; 275 /*! \internal */ 276 property alias _color: verticalBlur.color; 277 /*! \internal */ 278 property real _thickness: 0; 279 280 onSamplesChanged: _rebuildShaders(); 281 on_KernelSizeChanged: _rebuildShaders(); 282 onDeviationChanged: _rebuildShaders(); 283 on_DprChanged: _rebuildShaders(); 284 on_MaskSourceChanged: _rebuildShaders(); 285 Component.onCompleted: _rebuildShaders(); 286 287 /*! \internal */ 288 function _rebuildShaders() { 289 var params = { 290 radius: _kernelRadius, 291 // Limit deviation to something very small avoid getting NaN in the shader. 292 deviation: Math.max(0.00001, deviation), 293 alphaOnly: root._alphaOnly, 294 masked: _maskSource != undefined, 295 fallback: root.radius != _kernelRadius 296 } 297 var shaders = ShaderBuilder.gaussianBlur(params); 298 horizontalBlur.fragmentShader = shaders.fragmentShader; 299 horizontalBlur.vertexShader = shaders.vertexShader; 300 } 301 302 SourceProxy { 303 id: sourceProxy 304 interpolation: SourceProxy.LinearInterpolation 305 input: root.source 306 sourceRect: root.transparentBorder 307 ? Qt.rect(-root.radius, 0, root._paddedTexWidth, parent.height) 308 : Qt.rect(0, 0, 0, 0) 309 } 310 311 ShaderEffect { 312 id: horizontalBlur 313 width: root.transparentBorder ? root._paddedTexWidth : root.width 314 height: root.height; 315 316 // Used by all shaders 317 property Item source: sourceProxy.output; 318 property real spread: root.radius / root._kernelRadius; 319 property var dirstep: Qt.vector2d(1 / (root._paddedTexWidth * root._dpr), 0); 320 321 // Used by fallback shader (sampleCount exceeds number of varyings) 322 property real deviation: root.deviation 323 324 // Only in use for DropShadow and Glow 325 property color color: "white" 326 property real thickness: Math.max(0, Math.min(0.98, 1 - root._thickness * 0.98)); 327 328 // Only in use for MaskedBlur 329 property var mask: root._maskSource; 330 331 layer.enabled: true 332 layer.smooth: true 333 layer.sourceRect: root.transparentBorder 334 ? Qt.rect(0, -root.radius, width, root._paddedTexHeight) 335 : Qt.rect(0, 0, 0, 0) 336 visible: false 337 blending: false 338 } 339 340 ShaderEffect { 341 id: verticalBlur 342 x: transparentBorder ? -root.radius : 0 343 y: x; 344 width: root.transparentBorder ? root._paddedTexWidth: root.width 345 height: root.transparentBorder ? root._paddedTexHeight : root.height; 346 fragmentShader: horizontalBlur.fragmentShader 347 vertexShader: horizontalBlur.vertexShader 348 349 property Item source: horizontalBlur 350 property real spread: horizontalBlur.spread 351 property var dirstep: Qt.vector2d(0, 1 / (root._paddedTexHeight * root._dpr)); 352 353 property real deviation: horizontalBlur.deviation 354 355 property color color: "black" 356 property real thickness: horizontalBlur.thickness; 357 358 property var mask: horizontalBlur.mask; 359 360 visible: true 361 } 362 363 ShaderEffectSource { 364 id: cacheItem 365 anchors.fill: verticalBlur 366 visible: root.cached 367 smooth: true 368 sourceItem: verticalBlur 369 hideSource: visible 370 } 371 372} 373