How to display an animated SVG in PyQt5?

379 Views Asked by At

I have a PyQt5 application that send request to an API and display image that it retrived from API. When the request is being processed, I want to display a loading animation.

I have a animated SVG file which is supposed to be displayed like so: How SVG is supposed to be rendered

But when I tried to display the loader, it only displayed the circle part, I mean like this: How it is being rendered

Here is the Python Code
import sys
from PyQt5.QtWidgets import QApplication
from PyQt5.QtSvg import QSvgWidget, QSvgRenderer

file = open('./loader.svg', 'r')
svg_str = file.read()
file.close()
svg_bytes = bytearray(svg_str, encoding='utf-8')

app = QApplication(sys.argv)

svgWidget = QSvgWidget()
svgWidget.renderer().load(svg_bytes)
svgWidget.setGeometry(100,100,300,300)
svgWidget.show()

print(svgWidget.renderer().isValid())
print(svgWidget.renderer().animated())

sys.exit(app.exec_())

And here is the SVG code
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" style="margin:auto;background:transparent;display:block;" width="200px" height="200px" viewBox="0 0 100 100" preserveAspectRatio="xMidYMid">
<defs>
  <filter id="ldio-htco43jgr5i-filter" x="-100%" y="-100%" width="300%" height="300%" color-interpolation-filters="sRGB">
    <feGaussianBlur in="SourceGraphic" stdDeviation="3"></feGaussianBlur>
    <feComponentTransfer result="cutoff">
      <feFuncA type="linear" slope="60" intercept="-40"></feFuncA>
    </feComponentTransfer>
  </filter>
</defs>
<g filter="url(#ldio-htco43jgr5i-filter)">
  <animateTransform attributeName="transform" type="rotate" repeatCount="indefinite" dur="3.0303030303030303s" values="0 50 50;360 50 50" keyTimes="0;1"></animateTransform>
  <g>
  <g transform="translate(50 20)">
    <circle cx="0" cy="0" r="0" fill="#fe718d" transform="scale(0.5)"></circle>
  </g>
  <animateTransform attributeName="transform" calcMode="spline" type="rotate" values="0 50 50;360 50 50" keyTimes="0;1" dur="1.0101010101010102" keySplines="0.7666666666666666 0 0.6666666666666666 1" repeatCount="indefinite"></animateTransform>
</g><g>
  <g transform="translate(50 20)">
    <circle cx="0" cy="0" r="1" fill="#fe718d" transform="scale(0.5)"></circle>
  </g>
  <animateTransform attributeName="transform" calcMode="spline" type="rotate" values="0 50 50;360 50 50" keyTimes="0;1" dur="1.0101010101010102" keySplines="0.7333333333333333 0 0.6333333333333333 1" repeatCount="indefinite"></animateTransform>
</g><g>
  <g transform="translate(50 20)">
    <circle cx="0" cy="0" r="2" fill="#fe718d" transform="scale(0.5)"></circle>
  </g>
  <animateTransform attributeName="transform" calcMode="spline" type="rotate" values="0 50 50;360 50 50" keyTimes="0;1" dur="1.0101010101010102" keySplines="0.7 0 0.6 1" repeatCount="indefinite"></animateTransform>
</g><g>
  <g transform="translate(50 20)">
    <circle cx="0" cy="0" r="3" fill="#fe718d" transform="scale(0.5)"></circle>
  </g>
  <animateTransform attributeName="transform" calcMode="spline" type="rotate" values="0 50 50;360 50 50" keyTimes="0;1" dur="1.0101010101010102" keySplines="0.6666666666666666 0 0.5666666666666667 1" repeatCount="indefinite"></animateTransform>
</g><g>
  <g transform="translate(50 20)">
    <circle cx="0" cy="0" r="4" fill="#fe718d" transform="scale(0.5)"></circle>
  </g>
  <animateTransform attributeName="transform" calcMode="spline" type="rotate" values="0 50 50;360 50 50" keyTimes="0;1" dur="1.0101010101010102" keySplines="0.6333333333333333 0 0.5333333333333333 1" repeatCount="indefinite"></animateTransform>
</g><g>
  <g transform="translate(50 20)">
    <circle cx="0" cy="0" r="5" fill="#fe718d" transform="scale(0.5)"></circle>
  </g>
  <animateTransform attributeName="transform" calcMode="spline" type="rotate" values="0 50 50;360 50 50" keyTimes="0;1" dur="1.0101010101010102" keySplines="0.6 0 0.5 1" repeatCount="indefinite"></animateTransform>
</g><g>
  <g transform="translate(50 20)">
    <circle cx="0" cy="0" r="6" fill="#fe718d" transform="scale(0.5)"></circle>
  </g>
  <animateTransform attributeName="transform" calcMode="spline" type="rotate" values="0 50 50;360 50 50" keyTimes="0;1" dur="1.0101010101010102" keySplines="0.5666666666666667 0 0.4666666666666667 1" repeatCount="indefinite"></animateTransform>
</g><g>
  <g transform="translate(50 20)">
    <circle cx="0" cy="0" r="7" fill="#fe718d" transform="scale(0.5)"></circle>
  </g>
  <animateTransform attributeName="transform" calcMode="spline" type="rotate" values="0 50 50;360 50 50" keyTimes="0;1" dur="1.0101010101010102" keySplines="0.5333333333333333 0 0.43333333333333335 1" repeatCount="indefinite"></animateTransform>
</g><g>
  <g transform="translate(50 20)">
    <circle cx="0" cy="0" r="8" fill="#fe718d" transform="scale(0.5)"></circle>
  </g>
  <animateTransform attributeName="transform" calcMode="spline" type="rotate" values="0 50 50;360 50 50" keyTimes="0;1" dur="1.0101010101010102" keySplines="0.5 0 0.4 1" repeatCount="indefinite"></animateTransform>
</g><g>
  <g transform="translate(50 20)">
    <circle cx="0" cy="0" r="9" fill="#fe718d" transform="scale(0.5)"></circle>
  </g>
  <animateTransform attributeName="transform" calcMode="spline" type="rotate" values="0 50 50;360 50 50" keyTimes="0;1" dur="1.0101010101010102" keySplines="0.4666666666666667 0 0.36666666666666664 1" repeatCount="indefinite"></animateTransform>
</g><g>
  <g transform="translate(50 20)">
    <circle cx="0" cy="0" r="10" fill="#fe718d" transform="scale(0.5)"></circle>
  </g>
  <animateTransform attributeName="transform" calcMode="spline" type="rotate" values="0 50 50;360 50 50" keyTimes="0;1" dur="1.0101010101010102" keySplines="0.43333333333333335 0 0.3333333333333333 1" repeatCount="indefinite"></animateTransform>
</g><g>
  <g transform="translate(50 20)">
    <circle cx="0" cy="0" r="11" fill="#fe718d" transform="scale(0.5)"></circle>
  </g>
  <animateTransform attributeName="transform" calcMode="spline" type="rotate" values="0 50 50;360 50 50" keyTimes="0;1" dur="1.0101010101010102" keySplines="0.4 0 0.3 1" repeatCount="indefinite"></animateTransform>
</g><g>
  <g transform="translate(50 20)">
    <circle cx="0" cy="0" r="12" fill="#fe718d" transform="scale(0.5)"></circle>
  </g>
  <animateTransform attributeName="transform" calcMode="spline" type="rotate" values="0 50 50;360 50 50" keyTimes="0;1" dur="1.0101010101010102" keySplines="0.3666666666666667 0 0.26666666666666666 1" repeatCount="indefinite"></animateTransform>
</g><g>
  <g transform="translate(50 20)">
    <circle cx="0" cy="0" r="13" fill="#fe718d" transform="scale(0.5)"></circle>
  </g>
  <animateTransform attributeName="transform" calcMode="spline" type="rotate" values="0 50 50;360 50 50" keyTimes="0;1" dur="1.0101010101010102" keySplines="0.33333333333333337 0 0.23333333333333334 1" repeatCount="indefinite"></animateTransform>
</g><g>
  <g transform="translate(50 20)">
    <circle cx="0" cy="0" r="14" fill="#fe718d" transform="scale(0.5)"></circle>
  </g>
  <animateTransform attributeName="transform" calcMode="spline" type="rotate" values="0 50 50;360 50 50" keyTimes="0;1" dur="1.0101010101010102" keySplines="0.30000000000000004 0 0.2 1" repeatCount="indefinite"></animateTransform>
</g><g>
  <g transform="translate(50 20)">
    <circle cx="0" cy="0" r="15" fill="#fe718d" transform="scale(0.5)"></circle>
  </g>
  <animateTransform attributeName="transform" calcMode="spline" type="rotate" values="0 50 50;360 50 50" keyTimes="0;1" dur="1.0101010101010102" keySplines="0.26666666666666666 0 0.16666666666666666 1" repeatCount="indefinite"></animateTransform>
</g><g>
  <g transform="translate(50 20)">
    <circle cx="0" cy="0" r="16" fill="#fe718d" transform="scale(0.5)"></circle>
  </g>
  <animateTransform attributeName="transform" calcMode="spline" type="rotate" values="0 50 50;360 50 50" keyTimes="0;1" dur="1.0101010101010102" keySplines="0.23333333333333334 0 0.13333333333333333 1" repeatCount="indefinite"></animateTransform>
</g><g>
  <g transform="translate(50 20)">
    <circle cx="0" cy="0" r="17" fill="#fe718d" transform="scale(0.5)"></circle>
  </g>
  <animateTransform attributeName="transform" calcMode="spline" type="rotate" values="0 50 50;360 50 50" keyTimes="0;1" dur="1.0101010101010102" keySplines="0.2 0 0.1 1" repeatCount="indefinite"></animateTransform>
</g><g>
  <g transform="translate(50 20)">
    <circle cx="0" cy="0" r="18" fill="#fe718d" transform="scale(0.5)"></circle>
  </g>
  <animateTransform attributeName="transform" calcMode="spline" type="rotate" values="0 50 50;360 50 50" keyTimes="0;1" dur="1.0101010101010102" keySplines="0.16666666666666669 0 0.06666666666666667 1" repeatCount="indefinite"></animateTransform>
</g><g>
  <g transform="translate(50 20)">
    <circle cx="0" cy="0" r="19" fill="#fe718d" transform="scale(0.5)"></circle>
  </g>
  <animateTransform attributeName="transform" calcMode="spline" type="rotate" values="0 50 50;360 50 50" keyTimes="0;1" dur="1.0101010101010102" keySplines="0.13333333333333333 0 0.03333333333333333 1" repeatCount="indefinite"></animateTransform>
</g>
</g>
</svg>

I want to display full svg when the request is being processed.

1

There are 1 best solutions below

0
musicamante On

This is not possible with the Qt SVG module: according to the SVG documentation, "Qt supports the static features of SVG 1.2 Tiny", which does not provide any filter.

Unfortunately, you don't have a lot of options.

There is the cairosvg module, but it has two major issues:

  • it would force you to render the animation in Cairo and convert it to a sequence of raster images, so, either the animation is prerendered before with a predefined size (thus limiting the vectorialization benefits), or it will add a further overhead during real time rendering;
  • it provides limited filter support due to limitations of Cairo, and they don't include those you are using;

Full SVG support is obviously available using the QtWebEngine module, but it doesn't make a lot of sense to load a whole web browser engine to display a loading animation (unless you already use it for other purposes in your program).

Considering the above, the only remaining option is to prerender the animations, possibly at various ideal sizes, using an external program like Inkscape or through ImageMagick tools, and provide those as assets for your program with a custom QWidget subclass that will simulate the animation.