Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. Qt for Python
  4. PyQt6: QSvgWidget does not render when loading a QByteArray instead of a file
Forum Updated to NodeBB v4.3 + New Features

PyQt6: QSvgWidget does not render when loading a QByteArray instead of a file

Scheduled Pinned Locked Moved Unsolved Qt for Python
14 Posts 2 Posters 1.0k Views
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • E Offline
    E Offline
    ErwanM
    wrote on last edited by
    #1

    I'm using PyQt6 with python 3.12

    I want to display a diagram with live values inside a GroupBox widget to show a process values.
    For that, i want to use a SVG that is not loaded from a file but generated at each values changes.

    QSvgWidget allow to load a QByteArray that contains an svg but it does not work. The viewbox space is reserved but nothing is drown.

    My test svg is :

    <?xml version="1.0" encoding="UTF-8" standalone="no"?>
    <svg version="1.1" viewBox="0 0 100 100" width="100px" height="100px" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">
      <defs>
        <style type="text/css">
    .shape-other{fill:#0852f8;stroke:none;}
    .text-channel{fill:#fefefe;text-anchor: middle; font-size:28px;}
        </style>
      </defs>
      <rect class="shape-other" x="0" y="0" width="100" height="100" rx="2" ry="2" />
      <text class="text-channel" x="50" y="50">TEXT</text>
    </svg>
    

    Loading the svg from a file works well:

    OpDiagram = QSvgWidget("./images/TestDiagram.svg")
    

    But loading from inline bytes string does not: no error reported by Qt

    RawSvg= """
    <?xml version="1.0" encoding="UTF-8" standalone="no"?>
    <svg version="1.1" viewBox="0 0 100 100" width="100px" height="100px" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">
      <defs>
        <style type="text/css">
    .shape-other{fill:#0852f8;stroke:none;}
    .text-channel{fill:#fefefe;text-anchor: middle; font-size:28px;}
        </style>
      </defs>
      <rect class="shape-other" x="0" y="0" width="100" height="100" rx="2" ry="2" />
      <text class="text-channel" x="50" y="50">TEXT</text>
    </svg>
    """
    OpDiagram = QSvgWidget() # can't load direct content at init ; need to call load to do so in a second stage
    OpDiagram.load(QByteArray(bytes(RawSvg, 'utf-8')))
    

    Can someone explain why the loading of QByteArray stored svg screwed up ?

    JonBJ 1 Reply Last reply
    0
    • E ErwanM

      I'm using PyQt6 with python 3.12

      I want to display a diagram with live values inside a GroupBox widget to show a process values.
      For that, i want to use a SVG that is not loaded from a file but generated at each values changes.

      QSvgWidget allow to load a QByteArray that contains an svg but it does not work. The viewbox space is reserved but nothing is drown.

      My test svg is :

      <?xml version="1.0" encoding="UTF-8" standalone="no"?>
      <svg version="1.1" viewBox="0 0 100 100" width="100px" height="100px" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">
        <defs>
          <style type="text/css">
      .shape-other{fill:#0852f8;stroke:none;}
      .text-channel{fill:#fefefe;text-anchor: middle; font-size:28px;}
          </style>
        </defs>
        <rect class="shape-other" x="0" y="0" width="100" height="100" rx="2" ry="2" />
        <text class="text-channel" x="50" y="50">TEXT</text>
      </svg>
      

      Loading the svg from a file works well:

      OpDiagram = QSvgWidget("./images/TestDiagram.svg")
      

      But loading from inline bytes string does not: no error reported by Qt

      RawSvg= """
      <?xml version="1.0" encoding="UTF-8" standalone="no"?>
      <svg version="1.1" viewBox="0 0 100 100" width="100px" height="100px" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">
        <defs>
          <style type="text/css">
      .shape-other{fill:#0852f8;stroke:none;}
      .text-channel{fill:#fefefe;text-anchor: middle; font-size:28px;}
          </style>
        </defs>
        <rect class="shape-other" x="0" y="0" width="100" height="100" rx="2" ry="2" />
        <text class="text-channel" x="50" y="50">TEXT</text>
      </svg>
      """
      OpDiagram = QSvgWidget() # can't load direct content at init ; need to call load to do so in a second stage
      OpDiagram.load(QByteArray(bytes(RawSvg, 'utf-8')))
      

      Can someone explain why the loading of QByteArray stored svg screwed up ?

      JonBJ Offline
      JonBJ Offline
      JonB
      wrote on last edited by JonB
      #2

      @ErwanM
      To my knowledge both PySide and PyQt treat bytes as QByteArray internally (just like they treat str as QString). Did you try just passing the bytes(...) to load() without the QByteArray conversion? Just a thought. I do not know whether the utf-8 is right or not (probably is), never have understood! You might also verify that the return result of the bytes() and/or the QByteArray() have about the same size/number of bytes as the original file content/string.

      Having said that, I see from https://stackoverflow.com/questions/77792905/pyside2-load-svg-from-variable-rather-than-from-file (also https://stackoverflow.com/a/52838067/489865) that they seem to do much as you do. Try exactly that example and verify whether that works for you? I note they use svgWidget.renderer().load(svg_bytes) rather than calling load() directly on the QSvgWidget. Does that make any difference? It might be that in older PySide/PyQts the latter was not available, I don't know, but maybe worth a try?

      1 Reply Last reply
      0
      • E Offline
        E Offline
        ErwanM
        wrote on last edited by
        #3

        I've found the problem: it's a pure python syntax problem.
        Adding a carriage return in the first line of the string put the xml header in line 2 so the entire content is ignored at load.

        RawSvg= """<?xml version="1.0" encoding="UTF-8" standalone="no"?>
        <svg version="1.1" viewBox="0 0 100 100" width="100px" height="100px" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">
          <defs>
            <style type="text/css">
        .shape-other{fill:#0852f8;stroke:none;}
        .text-channel{fill:#fefefe;text-anchor: middle; font-size:28px;}
            </style>
          </defs>
          <rect class="shape-other" x="0" y="0" width="100" height="100" rx="2" ry="2" />
          <text class="text-channel" x="50" y="50">TEXT</text>
        </svg>
        """
        
        JonBJ 1 Reply Last reply
        2
        • E ErwanM

          I've found the problem: it's a pure python syntax problem.
          Adding a carriage return in the first line of the string put the xml header in line 2 so the entire content is ignored at load.

          RawSvg= """<?xml version="1.0" encoding="UTF-8" standalone="no"?>
          <svg version="1.1" viewBox="0 0 100 100" width="100px" height="100px" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns="http://www.w3.org/2000/svg" xmlns:svg="http://www.w3.org/2000/svg">
            <defs>
              <style type="text/css">
          .shape-other{fill:#0852f8;stroke:none;}
          .text-channel{fill:#fefefe;text-anchor: middle; font-size:28px;}
              </style>
            </defs>
            <rect class="shape-other" x="0" y="0" width="100" height="100" rx="2" ry="2" />
            <text class="text-channel" x="50" y="50">TEXT</text>
          </svg>
          """
          
          JonBJ Offline
          JonBJ Offline
          JonB
          wrote on last edited by JonB
          #4

          @ErwanM
          Ah, I did not realise that the <?xml ... must appear starting from the very first byte/line of the input, not just after any whitespace (such as a CR-LF). Good spot.

          https://en.wikipedia.org/wiki/XML only states of <?xml ...

          XML declaration

          XML documents may begin with an XML declaration that describes some information about themselves. An example is <?xml version="1.0" encoding="UTF-8"?>.

          It does not define precisely what "begin with" constitutes. I don't know whether this behaviour is a Qt thing. The answer at https://superuser.com/a/1509336/479430 may hint at this exact behaviour, I'm not sure.

          1 Reply Last reply
          0
          • E Offline
            E Offline
            ErwanM
            wrote on last edited by
            #5

            @JonB many thanks for your links.
            My own search leaded me to similar answers that where written for Pyside2 or PyQt5 but none of them was really relevant for my case.

            I can now go further and make my SVG produced dynamically by a refresh function. I will see if loading another svg will trigger the rendering. Yous links could be interesting if rendering does not occur in that case.

            Concerning utf-8, no one should use any other encoding now for python scripts, svg or any text file unless having a very good reason to use another encoding. With windows API, utf16-le is also common but it's a niche.

            JonBJ 1 Reply Last reply
            0
            • E ErwanM

              @JonB many thanks for your links.
              My own search leaded me to similar answers that where written for Pyside2 or PyQt5 but none of them was really relevant for my case.

              I can now go further and make my SVG produced dynamically by a refresh function. I will see if loading another svg will trigger the rendering. Yous links could be interesting if rendering does not occur in that case.

              Concerning utf-8, no one should use any other encoding now for python scripts, svg or any text file unless having a very good reason to use another encoding. With windows API, utf16-le is also common but it's a niche.

              JonBJ Offline
              JonBJ Offline
              JonB
              wrote on last edited by
              #6

              @ErwanM
              Technically this has nothing to do with PySide, PyQt or Python. I imagine you would get same problem if you sent it from C++ or wherever with preceding whitespace, or if you edited your external file and put a blank line at the very start.

              E 1 Reply Last reply
              0
              • JonBJ JonB

                @ErwanM
                Technically this has nothing to do with PySide, PyQt or Python. I imagine you would get same problem if you sent it from C++ or wherever with preceding whitespace, or if you edited your external file and put a blank line at the very start.

                E Offline
                E Offline
                ErwanM
                wrote on last edited by
                #7

                @JonB the link to python comes from the here string syntax: the string start just after the triple quote and not at the next line.
                In others language like perl, the here string start at the next line to preserve the first line indent.

                C++ 11 introduced a here string like construction and, again, the raw string start at the next line.

                So this error is in part due to the language syntax for here string.

                1 Reply Last reply
                0
                • JonBJ Offline
                  JonBJ Offline
                  JonB
                  wrote on last edited by JonB
                  #8

                  Well if you don't know whether your language happens to put in or not put a linefeed in whatever string literal construct you choose to use that is a problem. But the error here is the due to the parsing of the XML requiring there be no leading whitespace, that's all I'm saying.

                  @ErwanM said in PyQt6: QSvgWidget does not render when loading a QByteArray instead of a file:

                  C++ 11 introduced a here string like construction and, again, the raw string start at the next line.

                  Pardon/really? Not to the best of my knowledge, but I may be at fault. Which construct are you talking about (example please) and where do you claim " the raw string start at the next line" is the case? The C++ literals I can think of (e.g. R"(...)") would not only "start at the next line", the initial line where the string literal opener is placed would "count" towards the string content. Perl or Linux shells have the "here document", and that indeed does not count the start line, only the following line below, but that's not C++.

                  E 1 Reply Last reply
                  0
                  • JonBJ JonB

                    Well if you don't know whether your language happens to put in or not put a linefeed in whatever string literal construct you choose to use that is a problem. But the error here is the due to the parsing of the XML requiring there be no leading whitespace, that's all I'm saying.

                    @ErwanM said in PyQt6: QSvgWidget does not render when loading a QByteArray instead of a file:

                    C++ 11 introduced a here string like construction and, again, the raw string start at the next line.

                    Pardon/really? Not to the best of my knowledge, but I may be at fault. Which construct are you talking about (example please) and where do you claim " the raw string start at the next line" is the case? The C++ literals I can think of (e.g. R"(...)") would not only "start at the next line", the initial line where the string literal opener is placed would "count" towards the string content. Perl or Linux shells have the "here document", and that indeed does not count the start line, only the following line below, but that's not C++.

                    E Offline
                    E Offline
                    ErwanM
                    wrote on last edited by
                    #9

                    @JonB as many people do, i don't make use of a single language but many of them from several assembly languages to high level ones like perl, php, javascript, SQL or even bash/cmd.

                    When programmers have to switch between many languages, any particularity represent a potential trap. Python here string syntax is one of them because it's not the common way to do it.

                    JonBJ 1 Reply Last reply
                    0
                    • E ErwanM

                      @JonB as many people do, i don't make use of a single language but many of them from several assembly languages to high level ones like perl, php, javascript, SQL or even bash/cmd.

                      When programmers have to switch between many languages, any particularity represent a potential trap. Python here string syntax is one of them because it's not the common way to do it.

                      JonBJ Offline
                      JonBJ Offline
                      JonB
                      wrote on last edited by
                      #10

                      @ErwanM
                      I asked you a simple question. You stated:

                      C++ 11 introduced a here string like construction and, again, the raw string start at the next line.

                      And I said I did not think so. Could you kindly provide an example of whatever you mean by "a here string like construction" in C++ which has "the raw string start at the next line"? Because the only think I can think you might mean is the R"(...)" construction and as I said that does not "start on the next line", it started immediately after the opening R"(, just as is does for the Python """.

                      This is not a criticism of you, and of course your swapping between multiple languages (just as I do) is an understandable source of confusion. It is merely an attempt to clarify or put the record straight for other readers of your earlier statement. We like to keep things accurate on this site :)

                      E 1 Reply Last reply
                      0
                      • JonBJ JonB

                        @ErwanM
                        I asked you a simple question. You stated:

                        C++ 11 introduced a here string like construction and, again, the raw string start at the next line.

                        And I said I did not think so. Could you kindly provide an example of whatever you mean by "a here string like construction" in C++ which has "the raw string start at the next line"? Because the only think I can think you might mean is the R"(...)" construction and as I said that does not "start on the next line", it started immediately after the opening R"(, just as is does for the Python """.

                        This is not a criticism of you, and of course your swapping between multiple languages (just as I do) is an understandable source of confusion. It is merely an attempt to clarify or put the record straight for other readers of your earlier statement. We like to keep things accurate on this site :)

                        E Offline
                        E Offline
                        ErwanM
                        wrote on last edited by
                        #11

                        @JonB yes, you're right. C++ raw string literals start just after the first delimiter.

                        Coupled with the fact that end delimiter can be on the same line as content, this makes two traps instead of one.

                        These characteristics allow the construction of a one line raw string but this is not the common case i think.

                        In the examples i found on Stack overflow, i've seen xml files, starting at the next line after the start delimiter.

                        This is just a banana peel that python and C++ developers have left to make developer slip away.

                        JonBJ 1 Reply Last reply
                        0
                        • E ErwanM

                          @JonB yes, you're right. C++ raw string literals start just after the first delimiter.

                          Coupled with the fact that end delimiter can be on the same line as content, this makes two traps instead of one.

                          These characteristics allow the construction of a one line raw string but this is not the common case i think.

                          In the examples i found on Stack overflow, i've seen xml files, starting at the next line after the start delimiter.

                          This is just a banana peel that python and C++ developers have left to make developer slip away.

                          JonBJ Offline
                          JonBJ Offline
                          JonB
                          wrote on last edited by
                          #12

                          @ErwanM said in PyQt6: QSvgWidget does not render when loading a QByteArray instead of a file:

                          In the examples i found on Stack overflow, i've seen xml files, starting at the next line after the start delimiter.

                          That would be interesting. Any links? Because as we have discovered if they start with the <?xml declaration that must be in very first character position, no whitespace/newline character before. OTOH if they do not have this declaration, e.g. they just start with <SomeNode>, then per the XML spec that can be preceded by whitespace (e.g. newline), it is only the <?xml which has to appear from first character spot, maybe that is what you saw?

                          1 Reply Last reply
                          0
                          • E Offline
                            E Offline
                            ErwanM
                            wrote on last edited by
                            #13

                            In this thread, most of people are using raw string literal as i do with line breaks around the raw string: https://stackoverflow.com/questions/1135841/how-to-write-a-multi-line-string-literal

                            JonBJ 1 Reply Last reply
                            0
                            • E ErwanM

                              In this thread, most of people are using raw string literal as i do with line breaks around the raw string: https://stackoverflow.com/questions/1135841/how-to-write-a-multi-line-string-literal

                              JonBJ Offline
                              JonBJ Offline
                              JonB
                              wrote on last edited by JonB
                              #14

                              @ErwanM
                              Yes, the ones there using the R"(-type construct are shown having leading & trailing newlines which will be in the resulting string. One guy does even say

                              All the spaces and indentation and the newlines in the string are preserved.

                              That's up to them for their examples where it doesn't matter. In your case of <?xml we simply cannot afford that.

                              The one which starts

                              std::string index_html=R"html(
                              <!DOCTYPE html>
                              

                              would have a newline before the <!DOCTYPE html>, but maybe that is allowed, unlike for <?xml. Or maybe it isn't allowed either and they didn't check!

                              Anyway, there we are, that's just how it is.

                              1 Reply Last reply
                              0

                              • Login

                              • Login or register to search.
                              • First post
                                Last post
                              0
                              • Categories
                              • Recent
                              • Tags
                              • Popular
                              • Users
                              • Groups
                              • Search
                              • Get Qt Extensions
                              • Unsolved