Uploaded image for project: 'Qt for Python'
  1. Qt for Python
  2. PYSIDE-532

"pyside2-uic" Rasterizes SVG Icons, Which Is Bad

    XMLWordPrintable

    Details

    • Type: Bug
    • Status: Closed
    • Priority: P3: Somewhat important
    • Resolution: Out of scope
    • Affects Version/s: 5.6, 5.9, dev
    • Fix Version/s: dev
    • Component/s: Other
    • Labels:

      Description

      The 5.6 (and probably dev) branch of pyside-tools fails to preserve SVG icons as in-memory vector images. Instead, the Python logic generated by pyside2-uic unconditionally downgrades all SVG icons to in-memory raster pixmaps.

      This is horrible for any number of obvious reasons, including:

      • Pixellation. Rasterization of vector images inevitably introduces visual artifacting. Sadly, SVG icons are no exception.
      • No upscaling. Qt wisely refuses to upscale raster pixmaps. However, Qt typically converts SVG icons to extremely small raster pixmaps. Together, these two observations imply that SVG icons are locked to extremely small sizes. On high-DPI displays (e.g., Retina), the resulting raster pixmaps are effectively invisible.

      Examples or The Little Dog Gets It

      Why did this horrible thing happen? A minimal-length example should hopefully clarify.

      Given the attached mainwindow.ui and mainwindow.qrc files, pyside2-uic encapsulates the attached dashboard.svg icon with the following Python:

          icon = QtGui.QIcon()
          icon.addPixmap(QtGui.QPixmap(":/dashboard.svg"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
      

      Note the rasterization of this SVG icon into an in-memory pixmap. Since the QIcon::addFile() method already implicitly supports SVG icons, however, this rasterization is needlessly destructive. Ideally, pyside2-uic should encapsulate this icon with a call to the QIcon::addFile() method instead: e.g.,

          icon = QtGui.QIcon()
          icon.addFile(":/dashboard.svg", QtCore.QSize(), QtGui.QIcon.Normal, QtGui.QIcon.Off)
      

      Note the need to pass an additional size parameter to the QIcon::addFile() method, which remains unconstrained due to the infinitely rescalable nature of vector images.

      Note also that there appears to be no benefit to calling QIcon::addPixmap() at all – even for non-vector icons (e.g., jpg, png). QIcon::addFile() already supports all image filetypes and is thus probably always preferable to QIcon::addPixmap() here.

      Or maybe I have no idea what I'm talking about. (A distinct possibility.)

      Better Examples or The Little Dog Really Gets It

      The attached qiconpixmap.py application embeds this SVG icon as a toolbar action of an otherwise empty main window. This application is runnable in the usual way. For example, at a Bash terminal:

      pyside2-uic -omainwindow.py mainwindow.ui
      pyside2-rcc -o mainwindow_rc.py mainwindow.qrc
      python3 qiconpixmap.py
      

      The SVG icon should appear rasterized to an extremely small size rather than stretching to vertically fill the height of its parent toolbar.

      Hacky Workaround for Great Justice

      Our downstream application currently hacks around this by forcibly performing a sed-style global search-and-replacement on the text emitted by the pyside2uic module before serializing this text to disk. Assuming this text to be assigned to local variable ui_code_str, the following string munging suffices:

      import re
      ui_code_str = re.sub(
          (
              r'^(\s*icon\d*\.add)'
              r'Pixmap\(QtGui\.QPixmap\('
              r'("[^"]+\.svg")'
              r'\)(.*)$'
          ),
          r'\1File(\2, QtCore.QSize()\3',
          ui_code_str,
          flags=re.MULTILINE,
      )
      

      Thanks to that black magic, this isn't necessarily a high-priority issue for us.

      Everybody else might feel differently.

        Attachments

        1. dashboard.svg
          0.5 kB
        2. mainwindow.qrc
          0.1 kB
        3. mainwindow.ui
          1 kB
        4. pyside532.zip
          2 kB
        5. qiconpixmap.py
          0.3 kB

          Issue Links

          No reviews matched the request. Check your Options in the drop-down menu of this sections header.

            Activity

              People

              • Assignee:
                Unassigned
                Reporter:
                leycec Cecil Curry
              • Votes:
                2 Vote for this issue
                Watchers:
                6 Start watching this issue

                Dates

                • Created:
                  Updated:
                  Resolved:

                  Gerrit Reviews

                  There are no open Gerrit changes