GaussianBlur.qml 13 KB

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