GaussianBlur.qml 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  1. // Copyright (C) 2017 The Qt Company Ltd.
  2. // Copyright (C) 2017 Jolla Ltd, author: <gunnar.sletta@jollamobile.com>
  3. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
  4. // Qt-Security score:significant reason:default
  5. import QtQuick
  6. import QtQuick.Window
  7. import Qt5Compat.GraphicalEffects.private
  8. /*!
  9. \qmltype GaussianBlur
  10. \inqmlmodule Qt5Compat.GraphicalEffects
  11. \since QtGraphicalEffects 1.0
  12. \inherits QtQuick2::Item
  13. \ingroup qtgraphicaleffects-blur
  14. \brief Applies a higher quality blur effect.
  15. GaussianBlur effect softens the image by blurring it with an algorithm that
  16. uses the Gaussian function to calculate the effect. The effect produces
  17. higher quality than \l{Qt5Compat.GraphicalEffects::FastBlur}{FastBlur}, but is
  18. slower to render.
  19. In particular, modifying properties of Gaussian blur will in many cases require
  20. rebuilding the shader code from scratch, so animating properties of the effect
  21. may perform badly as well as require a large amount of cache space. Therefore,
  22. \l{FastBlur} should usually be preferred for animated blurs.
  23. \table
  24. \header
  25. \li Source
  26. \li Effect applied
  27. \row
  28. \li \image Original_bug.png
  29. \li \image GaussianBlur_bug.png
  30. \endtable
  31. \note This effect is available when running with OpenGL.
  32. \section1 Example
  33. The following example shows how to apply the effect.
  34. \snippet GaussianBlur-example.qml example
  35. Performing blur live is a costly operation. Fullscreen gaussian blur
  36. with even a moderate number of samples will only run at 60 fps on highend
  37. graphics hardware.
  38. */
  39. Item {
  40. id: root
  41. /*!
  42. This property defines the source item that is going to be blurred.
  43. \note It is not supported to let the effect include itself, for
  44. instance by setting source to the effect's parent.
  45. */
  46. property variant source
  47. /*!
  48. This property defines the distance of the neighboring pixels which
  49. affect the blurring of an individual pixel. A larger radius increases
  50. the blur effect.
  51. The ideal blur is achieved by selecting \c samples and \c radius such
  52. that \c {samples = 1 + radius * 2}, such as:
  53. \table
  54. \header \li Radius \li Samples
  55. \row \li 0 \e{(no blur)} \li 1
  56. \row \li 1 \li 3
  57. \row \li 2 \li 5
  58. \row \li 3 \li 7
  59. \endtable
  60. The value ranges from 0.0 (no blur) to inf. By default, the property is
  61. set to \c floor(samples / 2.0).
  62. \table
  63. \header
  64. \li Output examples with different radius values
  65. \li
  66. \li
  67. \row
  68. \li \image GaussianBlur_radius1.png
  69. \li \image GaussianBlur_radius2.png
  70. \li \image GaussianBlur_radius3.png
  71. \row
  72. \li \b { radius: 0 }
  73. \li \b { radius: 4 }
  74. \li \b { radius: 8 }
  75. \row
  76. \li \l samples: 16
  77. \li \l samples: 16
  78. \li \l samples: 16
  79. \row
  80. \li \l deviation: 3
  81. \li \l deviation: 3
  82. \li \l deviation: 3
  83. \endtable
  84. */
  85. property real radius: Math.floor(samples / 2);
  86. /*!
  87. This property defines how many samples are taken per pixel when blur
  88. calculation is done. Larger value produces better quality, but is slower
  89. to render.
  90. Ideally, this value should be twice as large as the highest required
  91. radius value plus 1, for example, if the radius is animated between 0.0
  92. and 4.0, samples should be set to 9.
  93. By default, the property is set to \c 9.
  94. \note This property is not intended to be animated. Changing this property may
  95. cause the underlying OpenGL shaders to be recompiled.
  96. */
  97. property int samples: 9
  98. /*!
  99. This property is a parameter to the gaussian function that is used when
  100. calculating neighboring pixel weights for the blurring. A larger
  101. deviation causes image to appear more blurry, but it also reduces the
  102. quality of the blur. A very large deviation value causes the effect to
  103. look a bit similar to what, for exmple, a box blur algorithm produces. A
  104. too small deviation values makes the effect insignificant for the pixels
  105. near the radius.
  106. \image GaussianBlur_deviation_graph.png
  107. \caption The image above shows the Gaussian function with two different
  108. deviation values, yellow (1) and cyan (2.7). The y-axis shows the
  109. weights, the x-axis shows the pixel distance.
  110. The value ranges from 0.0 (no deviation) to inf (maximum deviation). By
  111. default, deviation is bound to radius. When radius increases, deviation
  112. is automatically increased linearly. With the radius value of 8, the
  113. deviation default value becomes approximately 2.7034. This value
  114. produces a compromise between the blur quality and overall blurriness.
  115. \table
  116. \header
  117. \li Output examples with different deviation values
  118. \li
  119. \li
  120. \row
  121. \li \image GaussianBlur_deviation1.png
  122. \li \image GaussianBlur_deviation2.png
  123. \li \image GaussianBlur_deviation3.png
  124. \row
  125. \li \b { deviation: 1 }
  126. \li \b { deviation: 2 }
  127. \li \b { deviation: 4 }
  128. \row
  129. \li \l radius: 8
  130. \li \l radius: 8
  131. \li \l radius: 8
  132. \row
  133. \li \l samples: 16
  134. \li \l samples: 16
  135. \li \l samples: 16
  136. \endtable
  137. */
  138. property real deviation: (radius + 1.0) / 3.3333
  139. /*!
  140. This property defines the blur behavior near the edges of the item,
  141. where the pixel blurring is affected by the pixels outside the source
  142. edges.
  143. If the property is set to \c true, the pixels outside the source are
  144. interpreted to be transparent, which is similar to OpenGL
  145. clamp-to-border extension. The blur is expanded slightly outside the
  146. effect item area.
  147. If the property is set to \c false, the pixels outside the source are
  148. interpreted to contain the same color as the pixels at the edge of the
  149. item, which is similar to OpenGL clamp-to-edge behavior. The blur does
  150. not expand outside the effect item area.
  151. By default, the property is set to \c false.
  152. \table
  153. \header
  154. \li Output examples with different transparentBorder values
  155. \li
  156. \li
  157. \row
  158. \li \image GaussianBlur_transparentBorder1.png
  159. \li \image GaussianBlur_transparentBorder2.png
  160. \row
  161. \li \b { transparentBorder: false }
  162. \li \b { transparentBorder: true }
  163. \row
  164. \li \l radius: 8
  165. \li \l radius: 8
  166. \row
  167. \li \l samples: 16
  168. \li \l samples: 16
  169. \row
  170. \li \l deviation: 2.7
  171. \li \l deviation: 2.7
  172. \endtable
  173. */
  174. property bool transparentBorder: false
  175. /*!
  176. This property allows the effect output pixels to be cached in order to
  177. improve the rendering performance.
  178. Every time the source or effect properties are changed, the pixels in
  179. the cache must be updated. Memory consumption is increased, because an
  180. extra buffer of memory is required for storing the effect output.
  181. It is recommended to disable the cache when the source or the effect
  182. properties are animated.
  183. By default, the property is set to \c false.
  184. */
  185. property bool cached: false
  186. // private members...
  187. /*! \internal */
  188. property int _paddedTexWidth: transparentBorder ? width + 2 * radius: width;
  189. /*! \internal */
  190. property int _paddedTexHeight: transparentBorder ? height + 2 * radius: height;
  191. /*! \internal */
  192. property int _kernelRadius: Math.max(0, samples / 2);
  193. /*! \internal */
  194. property int _kernelSize: _kernelRadius * 2 + 1;
  195. /*! \internal */
  196. property real _dpr: Screen.devicePixelRatio;
  197. /*! \internal */
  198. property bool _alphaOnly: false;
  199. /*! \internal */
  200. property var _maskSource: undefined
  201. /*! \internal */
  202. property alias _output: sourceProxy.output;
  203. /*! \internal */
  204. property alias _outputRect: sourceProxy.sourceRect;
  205. /*! \internal */
  206. property alias _color: verticalBlur.color;
  207. /*! \internal */
  208. property real _thickness: 0;
  209. /*! \internal */
  210. property bool _componentIsComplete: false
  211. onSamplesChanged: _rebuildShaders();
  212. on_KernelSizeChanged: _rebuildShaders();
  213. onDeviationChanged: _rebuildShaders();
  214. on_DprChanged: _rebuildShaders();
  215. on_MaskSourceChanged: _rebuildShaders();
  216. Component.onCompleted: {
  217. _componentIsComplete = true
  218. _rebuildShaders();
  219. }
  220. /*! \internal */
  221. function _rebuildShaders() {
  222. if (!_componentIsComplete)
  223. return
  224. var params = {
  225. radius: _kernelRadius,
  226. // Limit deviation to something very small avoid getting NaN in the shader.
  227. deviation: Math.max(0.00001, deviation),
  228. alphaOnly: root._alphaOnly,
  229. masked: _maskSource != undefined,
  230. fallback: root.radius != _kernelRadius
  231. }
  232. var shaders = ShaderBuilder.gaussianBlur(params);
  233. horizontalBlur.fragmentShader = shaders.fragmentShader;
  234. horizontalBlur.vertexShader = shaders.vertexShader;
  235. }
  236. SourceProxy {
  237. id: sourceProxy
  238. interpolation: SourceProxy.LinearInterpolation
  239. input: root.source
  240. sourceRect: root.transparentBorder
  241. ? Qt.rect(-root.radius, 0, root._paddedTexWidth, parent.height)
  242. : Qt.rect(0, 0, 0, 0)
  243. }
  244. ShaderEffect {
  245. id: horizontalBlur
  246. width: root.transparentBorder ? root._paddedTexWidth : root.width
  247. height: root.height;
  248. // Used by all shaders
  249. property Item source: sourceProxy.output;
  250. property real spread: root.radius / root._kernelRadius;
  251. property var dirstep: Qt.vector2d(1 / (root._paddedTexWidth * root._dpr), 0);
  252. // Used by fallback shader (sampleCount exceeds number of varyings)
  253. property real deviation: root.deviation
  254. // Only in use for DropShadow and Glow
  255. property color color: "white"
  256. property real thickness: Math.max(0, Math.min(0.98, 1 - root._thickness * 0.98));
  257. // Only in use for MaskedBlur
  258. property var mask: root._maskSource;
  259. layer.enabled: true
  260. layer.smooth: true
  261. layer.sourceRect: root.transparentBorder
  262. ? Qt.rect(0, -root.radius, width, root._paddedTexHeight)
  263. : Qt.rect(0, 0, 0, 0)
  264. visible: false
  265. blending: false
  266. }
  267. ShaderEffect {
  268. id: verticalBlur
  269. x: transparentBorder ? -root.radius : 0
  270. y: x;
  271. width: root.transparentBorder ? root._paddedTexWidth: root.width
  272. height: root.transparentBorder ? root._paddedTexHeight : root.height;
  273. fragmentShader: horizontalBlur.fragmentShader
  274. vertexShader: horizontalBlur.vertexShader
  275. property Item source: horizontalBlur
  276. property real spread: horizontalBlur.spread
  277. property var dirstep: Qt.vector2d(0, 1 / (root._paddedTexHeight * root._dpr));
  278. property real deviation: horizontalBlur.deviation
  279. property color color: "black"
  280. property real thickness: horizontalBlur.thickness;
  281. property var mask: horizontalBlur.mask;
  282. visible: true
  283. }
  284. ShaderEffectSource {
  285. id: cacheItem
  286. anchors.fill: verticalBlur
  287. visible: root.cached
  288. smooth: true
  289. sourceItem: verticalBlur
  290. hideSource: visible
  291. }
  292. }