Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. QSvgRenderer and QByteArray problem
Qt 6.11 is out! See what's new in the release blog

QSvgRenderer and QByteArray problem

Scheduled Pinned Locked Moved Solved General and Desktop
12 Posts 4 Posters 1.6k Views 3 Watching
  • 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.
  • JonBJ JonB

    This is a question about my using QSvgRenderer and it not behaving as I would expect. Now initially that sounds scary, because I'm probably the only one using it here, but don't let it put you off this question: it might be a question about QByteArray and strings instead... :)

    I have some SVG I am loading into a QGraphicsSvgItem. What it is/does really shouldn't matter, but someone will want to know, so here it is:

    <?xml version="1.0" encoding="UTF-8" standalone="no"?>
    <svg version="1.1">
        <g id="src/plugins/projectexplorer/images/buildstepdisable">
          <rect
             style="fill:#ffffff;fill-opacity:1"
             width="16"
             height="16"
             x="48"
             y="552" />
          <circle
             style="fill:none;fill-opacity:0;stroke:#000000;stroke-width:1.42;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
             cx="56"
             cy="560"
             r="5.2929001" />
          <path
             d="m 52,564 c 8,-8 8,-8 8,-8"
             style="fill:none;stroke:#000000;stroke-width:1.42;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
        </g>
    </svg>
    

    Now, if I have just this in a file and I create via

    QSvgRenderer *svgRenderer = new QSvgRenderer(QString("/home/jon/QtTests/QtSvg/qtcreatoricons2.svg"));
    QGraphicsSvgItem *svgItem = new QGraphicsSvgItem(this);
    svgItem->setSharedRenderer(svgRenderer);
    

    all is well, the icon gets rendered fine.

    But I don't want such a small piece of literal in a file. I want to do it from a literal string in code. I'm going to need to use the constructor QSvgRenderer::QSvgRenderer(const QByteArray &contents, QObject *parent = nullptr), right?

    Constructs a new renderer with the given parent and loads the SVG data from the byte array specified by contents.

    So I'm going to need a QByteArray. I copy & paste the above file content into code:

        static QByteArray svg =
            R"(
                <?xml version="1.0" encoding="UTF-8" standalone="no"?>
                ...
                )";
        QSvgRenderer *svgRenderer = new QSvgRenderer(svg);
    

    No icon now appears. QSvgRenderer & QGraphicsSvgItem are pretty (totally) quiet when they don't get what they want, so I don't get any message to tell me what might have happened. But no icon appearing happens whenever the SVG presented is not acceptable, that must be the case. [UPDATE: Yes: I found bool QSvgRenderer::isValid() const, sure enough that returns true when initialised from my file but false when from my byte array.]

    Why? Is there anything wrong with my R"( ... )" around all that file content? Or assigning it to a QByteArray? How can I "debug" what the issue is (no, I don't have Qt sources)?

    artwawA Offline
    artwawA Offline
    artwaw
    wrote on last edited by
    #2

    @JonB Both constructors do

    /*!
        Loads the specified SVG format \a contents, returning true if the content
        was successfully parsed; otherwise returns false.
    */
    bool QSvgRenderer::load(const QByteArray &contents)
    {
        Q_D(QSvgRenderer);
        return loadDocument(this, d, contents);
    }
    

    but I don't have the sources to dig deeper. What could you possibly test is if your QByteArray is same as the content of the file, maybe load the content of the file into QByteArray and try too?

    For more information please re-read.

    Kind Regards,
    Artur

    JonBJ 2 Replies Last reply
    0
    • artwawA artwaw

      @JonB Both constructors do

      /*!
          Loads the specified SVG format \a contents, returning true if the content
          was successfully parsed; otherwise returns false.
      */
      bool QSvgRenderer::load(const QByteArray &contents)
      {
          Q_D(QSvgRenderer);
          return loadDocument(this, d, contents);
      }
      

      but I don't have the sources to dig deeper. What could you possibly test is if your QByteArray is same as the content of the file, maybe load the content of the file into QByteArray and try too?

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

      @artwaw
      Well, I know there are some differences. In file the lines are against the left-margin, in the literal string the lines start with whitespace per the pasted indentation in code inside the R"( ... "). But whitespace shouldn't be relevant here.....

      Let me go at least do as you say and load the file into memory QByteArray and see how it goes....

      1 Reply Last reply
      1
      • artwawA artwaw

        @JonB Both constructors do

        /*!
            Loads the specified SVG format \a contents, returning true if the content
            was successfully parsed; otherwise returns false.
        */
        bool QSvgRenderer::load(const QByteArray &contents)
        {
            Q_D(QSvgRenderer);
            return loadDocument(this, d, contents);
        }
        

        but I don't have the sources to dig deeper. What could you possibly test is if your QByteArray is same as the content of the file, maybe load the content of the file into QByteArray and try too?

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

        @artwaw
        Well, what a surprise (not!), of course it works if I open the file and read in its bytes.
        The question is: why is my literal R(" ... )", where the ... is replaced by pasting the whole of the file content into the code, not producing a similarly-acceptable QByteArray content...?

        To be sure, a copy paste of what I have in code reads:

            static QByteArray svg =
                R"(
                    <?xml version="1.0" encoding="UTF-8" standalone="no"?>
                    <svg version="1.1">
                        <g id="src/plugins/projectexplorer/images/buildstepdisable">
                          <rect
                             style="fill:#ffffff;fill-opacity:1"
                             width="16"
                             height="16"
                             x="48"
                             y="552" />
                          <circle
                             style="fill:none;fill-opacity:0;stroke:#000000;stroke-width:1.42;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
                             cx="56"
                             cy="560"
                             r="5.2929001" />
                          <path
                             d="m 52,564 c 8,-8 8,-8 8,-8"
                             style="fill:none;stroke:#000000;stroke-width:1.42;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
                        </g>
                    </svg>
                    )";
        

        Can anyone spot anything wrong?

        raven-worxR 1 Reply Last reply
        0
        • JonBJ JonB

          This is a question about my using QSvgRenderer and it not behaving as I would expect. Now initially that sounds scary, because I'm probably the only one using it here, but don't let it put you off this question: it might be a question about QByteArray and strings instead... :)

          I have some SVG I am loading into a QGraphicsSvgItem. What it is/does really shouldn't matter, but someone will want to know, so here it is:

          <?xml version="1.0" encoding="UTF-8" standalone="no"?>
          <svg version="1.1">
              <g id="src/plugins/projectexplorer/images/buildstepdisable">
                <rect
                   style="fill:#ffffff;fill-opacity:1"
                   width="16"
                   height="16"
                   x="48"
                   y="552" />
                <circle
                   style="fill:none;fill-opacity:0;stroke:#000000;stroke-width:1.42;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
                   cx="56"
                   cy="560"
                   r="5.2929001" />
                <path
                   d="m 52,564 c 8,-8 8,-8 8,-8"
                   style="fill:none;stroke:#000000;stroke-width:1.42;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
              </g>
          </svg>
          

          Now, if I have just this in a file and I create via

          QSvgRenderer *svgRenderer = new QSvgRenderer(QString("/home/jon/QtTests/QtSvg/qtcreatoricons2.svg"));
          QGraphicsSvgItem *svgItem = new QGraphicsSvgItem(this);
          svgItem->setSharedRenderer(svgRenderer);
          

          all is well, the icon gets rendered fine.

          But I don't want such a small piece of literal in a file. I want to do it from a literal string in code. I'm going to need to use the constructor QSvgRenderer::QSvgRenderer(const QByteArray &contents, QObject *parent = nullptr), right?

          Constructs a new renderer with the given parent and loads the SVG data from the byte array specified by contents.

          So I'm going to need a QByteArray. I copy & paste the above file content into code:

              static QByteArray svg =
                  R"(
                      <?xml version="1.0" encoding="UTF-8" standalone="no"?>
                      ...
                      )";
              QSvgRenderer *svgRenderer = new QSvgRenderer(svg);
          

          No icon now appears. QSvgRenderer & QGraphicsSvgItem are pretty (totally) quiet when they don't get what they want, so I don't get any message to tell me what might have happened. But no icon appearing happens whenever the SVG presented is not acceptable, that must be the case. [UPDATE: Yes: I found bool QSvgRenderer::isValid() const, sure enough that returns true when initialised from my file but false when from my byte array.]

          Why? Is there anything wrong with my R"( ... )" around all that file content? Or assigning it to a QByteArray? How can I "debug" what the issue is (no, I don't have Qt sources)?

          raven-worxR Offline
          raven-worxR Offline
          raven-worx
          Moderators
          wrote on last edited by raven-worx
          #5

          @JonB
          A quick way if the XML is still valid after you created the bytearray:

          QDomDocument doc;
          int errorLine, errorColumn;
          QString errorMsg;
          if( !doc.setContent(data, &errorMsg, &errorLine, &errorColumn ) )
              qDebug() << "XML Error:" << errorMsg << errorLine << errorColumn;
          

          --- SUPPORT REQUESTS VIA CHAT WILL BE IGNORED ---
          If you have a question please use the forum so others can benefit from the solution in the future

          1 Reply Last reply
          1
          • JonBJ JonB

            @artwaw
            Well, what a surprise (not!), of course it works if I open the file and read in its bytes.
            The question is: why is my literal R(" ... )", where the ... is replaced by pasting the whole of the file content into the code, not producing a similarly-acceptable QByteArray content...?

            To be sure, a copy paste of what I have in code reads:

                static QByteArray svg =
                    R"(
                        <?xml version="1.0" encoding="UTF-8" standalone="no"?>
                        <svg version="1.1">
                            <g id="src/plugins/projectexplorer/images/buildstepdisable">
                              <rect
                                 style="fill:#ffffff;fill-opacity:1"
                                 width="16"
                                 height="16"
                                 x="48"
                                 y="552" />
                              <circle
                                 style="fill:none;fill-opacity:0;stroke:#000000;stroke-width:1.42;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
                                 cx="56"
                                 cy="560"
                                 r="5.2929001" />
                              <path
                                 d="m 52,564 c 8,-8 8,-8 8,-8"
                                 style="fill:none;stroke:#000000;stroke-width:1.42;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
                            </g>
                        </svg>
                        )";
            

            Can anyone spot anything wrong?

            raven-worxR Offline
            raven-worxR Offline
            raven-worx
            Moderators
            wrote on last edited by raven-worx
            #6

            @JonB
            ok, your problem is simply that your XML starts with an empty line, which makes it invalid.
            The check of mine above prints: XML Error: "invalid name for processing instruction 2 22"

            Change

            R"(
                        <?xml version="1.0" encoding="UTF-8" standalone="no"?>
                        .....
            

            to

            R"(<?xml version="1.0" encoding="UTF-8" standalone="no"?>
                 ....
            

            and it should work.

            --- SUPPORT REQUESTS VIA CHAT WILL BE IGNORED ---
            If you have a question please use the forum so others can benefit from the solution in the future

            JonBJ 1 Reply Last reply
            3
            • raven-worxR raven-worx

              @JonB
              ok, your problem is simply that your XML starts with an empty line, which makes it invalid.
              The check of mine above prints: XML Error: "invalid name for processing instruction 2 22"

              Change

              R"(
                          <?xml version="1.0" encoding="UTF-8" standalone="no"?>
                          .....
              

              to

              R"(<?xml version="1.0" encoding="UTF-8" standalone="no"?>
                   ....
              

              and it should work.

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

              @raven-worx said in QSvgRenderer and QByteArray problem:

              ok, your problem is simply that your XML starts with an empty line, which makes it invalid.

              I literally had just wondered about exactly this myself (honest!), and was about to test removing it when you replied!

              I like your idea of the XML read, I agree that would have told me the problem here. But --- just to verify --- there is no way I can get that error message out of new QSvgRenderer(QByteArray svg) call, is there?

              raven-worxR 1 Reply Last reply
              0
              • JonBJ JonB

                @raven-worx said in QSvgRenderer and QByteArray problem:

                ok, your problem is simply that your XML starts with an empty line, which makes it invalid.

                I literally had just wondered about exactly this myself (honest!), and was about to test removing it when you replied!

                I like your idea of the XML read, I agree that would have told me the problem here. But --- just to verify --- there is no way I can get that error message out of new QSvgRenderer(QByteArray svg) call, is there?

                raven-worxR Offline
                raven-worxR Offline
                raven-worx
                Moderators
                wrote on last edited by
                #8

                @JonB said in QSvgRenderer and QByteArray problem:

                there is no way I can get that error message out of new QSvgRenderer(QByteArray svg) call, is there?

                no. You can jsut check the return value of load() or isValid()

                --- SUPPORT REQUESTS VIA CHAT WILL BE IGNORED ---
                If you have a question please use the forum so others can benefit from the solution in the future

                JonBJ 2 Replies Last reply
                0
                • raven-worxR raven-worx

                  @JonB said in QSvgRenderer and QByteArray problem:

                  there is no way I can get that error message out of new QSvgRenderer(QByteArray svg) call, is there?

                  no. You can jsut check the return value of load() or isValid()

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

                  @raven-worx
                  Yeah, I want a lastLoadError() method :)

                  It's working now, I'll mark your earlier as the solution, thank you :)

                  1 Reply Last reply
                  0
                  • raven-worxR raven-worx

                    @JonB said in QSvgRenderer and QByteArray problem:

                    there is no way I can get that error message out of new QSvgRenderer(QByteArray svg) call, is there?

                    no. You can jsut check the return value of load() or isValid()

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

                    @raven-worx
                    If you're still here, one quick not-quite-related question, else I might have to open a new topic....

                    Do you happen to know: I am using this QGraphicsSvgItem to put a small "icon overlay" on a QGraphicsPixmapItem. Problem: I allow "zoom" (via mousewheel) on the graphics items/view/scene. Works fine, the QGraphicsPixmapItem with their pixmaps grow/shrink. But this QGraphicsSvgItem icon overlay --- which is a child of the QGraphicsPixmapItem --- does not change size in response. SVG does not scale? QGraphicsSvgItem does not scale? The particular SVG I am using is set not to scale? Any idea what I should do?

                    EDIT Hang on, sorry, I may be mistaken. At present the overlay icon is so small it's hard to tell, maybe it is scaling and I can't see. I need to go make it bigger....

                    JoeCFDJ 1 Reply Last reply
                    0
                    • JonBJ JonB

                      @raven-worx
                      If you're still here, one quick not-quite-related question, else I might have to open a new topic....

                      Do you happen to know: I am using this QGraphicsSvgItem to put a small "icon overlay" on a QGraphicsPixmapItem. Problem: I allow "zoom" (via mousewheel) on the graphics items/view/scene. Works fine, the QGraphicsPixmapItem with their pixmaps grow/shrink. But this QGraphicsSvgItem icon overlay --- which is a child of the QGraphicsPixmapItem --- does not change size in response. SVG does not scale? QGraphicsSvgItem does not scale? The particular SVG I am using is set not to scale? Any idea what I should do?

                      EDIT Hang on, sorry, I may be mistaken. At present the overlay icon is so small it's hard to tell, maybe it is scaling and I can't see. I need to go make it bigger....

                      JoeCFDJ Offline
                      JoeCFDJ Offline
                      JoeCFD
                      wrote on last edited by JoeCFD
                      #11

                      @JonB You may need to override func shape to change the size of your icon. This is how I draw my circle inside my class RadioNode : public QGraphicsSvgItem. Catch mouse wheel event and set new diameter, then update?

                      QPainterPath RadioNode::shape() const
                      {
                          QPainterPath path;
                          path.addEllipse( -m_diameter * 0.5, -m_diameter * 0.5, m_diameter, m_diameter );
                          return path;
                      }
                      
                      JonBJ 1 Reply Last reply
                      0
                      • JoeCFDJ JoeCFD

                        @JonB You may need to override func shape to change the size of your icon. This is how I draw my circle inside my class RadioNode : public QGraphicsSvgItem. Catch mouse wheel event and set new diameter, then update?

                        QPainterPath RadioNode::shape() const
                        {
                            QPainterPath path;
                            path.addEllipse( -m_diameter * 0.5, -m_diameter * 0.5, m_diameter, m_diameter );
                            return path;
                        }
                        
                        JonBJ Offline
                        JonBJ Offline
                        JonB
                        wrote on last edited by
                        #12

                        @JoeCFD
                        I think I am just wrong to have said it does not scale. I think it does. Playing with it now....

                        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