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. How to draw an SVG with a custom opacity

How to draw an SVG with a custom opacity

Scheduled Pinned Locked Moved Solved General and Desktop
12 Posts 3 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.
  • JoeCFDJ JoeCFD

    @additional-pumpkin Why do not you set opacity inside your svg file? Just curious.

    additional-pumpkinA Offline
    additional-pumpkinA Offline
    additional-pumpkin
    wrote on last edited by additional-pumpkin
    #3

    @JoeCFD For 2 reasons. First the svg file can be supplied by the user. Second by setting it in the svg file you get a different result than what I want.

    This is what the original svg looks like Screenshot_20230530_201637.png

    This is what happens after changing the opacity in the svg file
    Screenshot_20230530_201627.png

    This is what I want to happen (ignore the fact that the image is larger)
    Screenshot_20230530_201655.png

    But changing the file isn't really an option anyway since the user can supply it.

    1 Reply Last reply
    0
    • additional-pumpkinA Offline
      additional-pumpkinA Offline
      additional-pumpkin
      wrote on last edited by
      #4

      Also this SVG will normally be drawn with a normal opacity. Only when the user interacts with it and drags it it will leave behind a ghost svg which is what i want to implement by making in transparent.

      Here's an example of it being done (by rust-chessground)
      Screenshot_20230530_221802.png

      And this is what it looks like in my app right nowScreenshot_20230530_222058.png

      I want the piece that is being dragged to leave behind a 'ghost' piece on the square it was dragged from. This would be very simple to implement if I could set an custom opacity while rendering the svg with QSvgRenderer, but since QSvgRenderer has no such functionality how can I do this?

      JoeCFDJ 2 Replies Last reply
      0
      • additional-pumpkinA additional-pumpkin

        Also this SVG will normally be drawn with a normal opacity. Only when the user interacts with it and drags it it will leave behind a ghost svg which is what i want to implement by making in transparent.

        Here's an example of it being done (by rust-chessground)
        Screenshot_20230530_221802.png

        And this is what it looks like in my app right nowScreenshot_20230530_222058.png

        I want the piece that is being dragged to leave behind a 'ghost' piece on the square it was dragged from. This would be very simple to implement if I could set an custom opacity while rendering the svg with QSvgRenderer, but since QSvgRenderer has no such functionality how can I do this?

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

        @additional-pumpkin I understand your problem now. Maybe take a look at the source code of SVG and figure out how to avoid overlaps(no mix, but only reset of pixel color). Then create a customized class to inherit SVG class and override the generation part of image from svg without overlaps.

        additional-pumpkinA 1 Reply Last reply
        0
        • JoeCFDJ JoeCFD

          @additional-pumpkin I understand your problem now. Maybe take a look at the source code of SVG and figure out how to avoid overlaps(no mix, but only reset of pixel color). Then create a customized class to inherit SVG class and override the generation part of image from svg without overlaps.

          additional-pumpkinA Offline
          additional-pumpkinA Offline
          additional-pumpkin
          wrote on last edited by
          #6

          @JoeCFD I'm sorry but I don't understand...
          Which svg class? QSvgRenderer? QSvgGenerator? What SVG source code? Do you mean the xml in the svg file? How do I "override the generation part of image from svg without overlaps"?

          JoeCFDJ 1 Reply Last reply
          0
          • additional-pumpkinA additional-pumpkin

            @JoeCFD I'm sorry but I don't understand...
            Which svg class? QSvgRenderer? QSvgGenerator? What SVG source code? Do you mean the xml in the svg file? How do I "override the generation part of image from svg without overlaps"?

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

            @additional-pumpkin said in How to draw an SVG with a custom opacity:

            QSvgRenderer

            line 378
            https://code.qt.io/cgit/qt/qtsvg.git/tree/src/svg/qsvgrenderer.cpp?h=dev
            QSvgRenderer::render(); /* I use this one, not sure which one you use. Can you show some code? */

            I guess you need to dig it deeper.

            additional-pumpkinA 1 Reply Last reply
            0
            • JoeCFDJ JoeCFD

              @additional-pumpkin said in How to draw an SVG with a custom opacity:

              QSvgRenderer

              line 378
              https://code.qt.io/cgit/qt/qtsvg.git/tree/src/svg/qsvgrenderer.cpp?h=dev
              QSvgRenderer::render(); /* I use this one, not sure which one you use. Can you show some code? */

              I guess you need to dig it deeper.

              additional-pumpkinA Offline
              additional-pumpkinA Offline
              additional-pumpkin
              wrote on last edited by
              #8

              @JoeCFD

              Here's my code for drawing the pieces
              (pieces[] is an array of QSvgRenderers)

              void BoardView::draw_pieces(QPaintEvent *event)
              {
                  QPainter painter(this);
                  painter.setRenderHint(QPainter::Antialiasing);
                  for (chessops::Square sq = chessops::A1; sq <= chessops::H8; ++sq) {
                      int x = sq % 8;
                      int y = 7 - sq / 8;
                      QPointF pos(x * m_square_size, y * m_square_size);
                      chessops::Piece piece = m_board.get_piece_at(sq);
                      if (m_board.is_check() && chessops::type_of(piece) == chessops::PieceType::KING && chessops::color_of(piece) == m_board.get_stm()) {
                          QRadialGradient check_indicator(QPointF(pos.x() + m_square_size/2, pos.y() + m_square_size/2), m_square_size/2);
                          check_indicator.setColorAt(0, Qt::red);
                          check_indicator.setColorAt(1, Qt::transparent);
                          painter.fillRect(QRectF(pos, QSizeF(m_square_size, m_square_size)), check_indicator);
                      }
                      if (sq == m_drag_start) {
                          painter.fillRect(QRectF(pos, QSizeF(m_square_size, m_square_size)), QBrush(QColor(20, 85, 30, 255/2)));
                          // continue;
                      }
                      if(piece != chessops::PIECE_NONE) {
                          pieces[m_board.get_piece_at(sq)].render(&painter, QRectF(pos, QSizeF(m_square_size, m_square_size)));
                      }
                      if(m_board.is_piece_attack(m_drag_start, sq)) {
                          if (piece == chessops::Piece::PIECE_NONE) {
                              QPointF circle_pos = pos;
                              circle_pos.setX(circle_pos.x() + m_square_size/4 + m_square_size/8);
                              circle_pos.setY(circle_pos.y() + m_square_size/4 + m_square_size/8);
                              painter.setPen(Qt::transparent);
                              painter.setBrush(QColor(20, 85, 30, 128));
                              painter.drawEllipse(QRectF(circle_pos, QSizeF(m_square_size/4, m_square_size/4)));
                          }
                          else {
                              QPointF circle_pos = pos;
                              circle_pos.setX(circle_pos.x() - m_square_size/16);
                              circle_pos.setY(circle_pos.y() - m_square_size/16);
                              QPainterPath path;
                              QPainterPath bounds;
                              path.addRect(QRectF(pos, QSizeF(m_square_size, m_square_size)));
                              path.addEllipse(QRectF(circle_pos, QSizeF(m_square_size + m_square_size/8, m_square_size + m_square_size/8)));
                              bounds.addRect(QRectF(pos, QSizeF(m_square_size/4, m_square_size/4)));
                              bounds.addRect(QRectF(QPointF(pos.x() + m_square_size - m_square_size/4, pos.y()), QSizeF(m_square_size/4, m_square_size/4)));
                              bounds.addRect(QRectF(QPointF(pos.x(), pos.y() + m_square_size - m_square_size/4), QSizeF(m_square_size/4, m_square_size/4)));
                              bounds.addRect(QRectF(QPointF(pos.x() + m_square_size - m_square_size/4, pos.y() + m_square_size - m_square_size/4), QSizeF(m_square_size/4, m_square_size/4)));
                              painter.setPen(Qt::transparent);
                              painter.setBrush(QColor(20, 85, 30, 128));
                              // painter.drawPath(path);
                              painter.drawPath(path.intersected(bounds));
                              // painter.fillPath(bounds, QColor(Qt::red));
              
                          }
                      }
              
                      if (m_debug_overlay) {
                          if (m_board.debug_is_enemy_attack(sq)) {
                              painter.setPen(QPen(Qt::red, 10));
                              painter.setBrush(Qt::transparent);
                              painter.drawEllipse(QRectF(pos, QSizeF(m_square_size, m_square_size)));
                          }
                      }
                  }
                  if (m_drag_start != chessops::SQUARE_NONE && m_board.get_piece_at(m_drag_start) != chessops::PIECE_NONE)
                      pieces[m_board.get_piece_at(m_drag_start)].render(&painter, QRectF(m_dragged_piece_pos, QSizeF(m_square_size, m_square_size)));
              }```
              JoeCFDJ Chris KawaC 2 Replies Last reply
              0
              • additional-pumpkinA additional-pumpkin

                @JoeCFD

                Here's my code for drawing the pieces
                (pieces[] is an array of QSvgRenderers)

                void BoardView::draw_pieces(QPaintEvent *event)
                {
                    QPainter painter(this);
                    painter.setRenderHint(QPainter::Antialiasing);
                    for (chessops::Square sq = chessops::A1; sq <= chessops::H8; ++sq) {
                        int x = sq % 8;
                        int y = 7 - sq / 8;
                        QPointF pos(x * m_square_size, y * m_square_size);
                        chessops::Piece piece = m_board.get_piece_at(sq);
                        if (m_board.is_check() && chessops::type_of(piece) == chessops::PieceType::KING && chessops::color_of(piece) == m_board.get_stm()) {
                            QRadialGradient check_indicator(QPointF(pos.x() + m_square_size/2, pos.y() + m_square_size/2), m_square_size/2);
                            check_indicator.setColorAt(0, Qt::red);
                            check_indicator.setColorAt(1, Qt::transparent);
                            painter.fillRect(QRectF(pos, QSizeF(m_square_size, m_square_size)), check_indicator);
                        }
                        if (sq == m_drag_start) {
                            painter.fillRect(QRectF(pos, QSizeF(m_square_size, m_square_size)), QBrush(QColor(20, 85, 30, 255/2)));
                            // continue;
                        }
                        if(piece != chessops::PIECE_NONE) {
                            pieces[m_board.get_piece_at(sq)].render(&painter, QRectF(pos, QSizeF(m_square_size, m_square_size)));
                        }
                        if(m_board.is_piece_attack(m_drag_start, sq)) {
                            if (piece == chessops::Piece::PIECE_NONE) {
                                QPointF circle_pos = pos;
                                circle_pos.setX(circle_pos.x() + m_square_size/4 + m_square_size/8);
                                circle_pos.setY(circle_pos.y() + m_square_size/4 + m_square_size/8);
                                painter.setPen(Qt::transparent);
                                painter.setBrush(QColor(20, 85, 30, 128));
                                painter.drawEllipse(QRectF(circle_pos, QSizeF(m_square_size/4, m_square_size/4)));
                            }
                            else {
                                QPointF circle_pos = pos;
                                circle_pos.setX(circle_pos.x() - m_square_size/16);
                                circle_pos.setY(circle_pos.y() - m_square_size/16);
                                QPainterPath path;
                                QPainterPath bounds;
                                path.addRect(QRectF(pos, QSizeF(m_square_size, m_square_size)));
                                path.addEllipse(QRectF(circle_pos, QSizeF(m_square_size + m_square_size/8, m_square_size + m_square_size/8)));
                                bounds.addRect(QRectF(pos, QSizeF(m_square_size/4, m_square_size/4)));
                                bounds.addRect(QRectF(QPointF(pos.x() + m_square_size - m_square_size/4, pos.y()), QSizeF(m_square_size/4, m_square_size/4)));
                                bounds.addRect(QRectF(QPointF(pos.x(), pos.y() + m_square_size - m_square_size/4), QSizeF(m_square_size/4, m_square_size/4)));
                                bounds.addRect(QRectF(QPointF(pos.x() + m_square_size - m_square_size/4, pos.y() + m_square_size - m_square_size/4), QSizeF(m_square_size/4, m_square_size/4)));
                                painter.setPen(Qt::transparent);
                                painter.setBrush(QColor(20, 85, 30, 128));
                                // painter.drawPath(path);
                                painter.drawPath(path.intersected(bounds));
                                // painter.fillPath(bounds, QColor(Qt::red));
                
                            }
                        }
                
                        if (m_debug_overlay) {
                            if (m_board.debug_is_enemy_attack(sq)) {
                                painter.setPen(QPen(Qt::red, 10));
                                painter.setBrush(Qt::transparent);
                                painter.drawEllipse(QRectF(pos, QSizeF(m_square_size, m_square_size)));
                            }
                        }
                    }
                    if (m_drag_start != chessops::SQUARE_NONE && m_board.get_piece_at(m_drag_start) != chessops::PIECE_NONE)
                        pieces[m_board.get_piece_at(m_drag_start)].render(&painter, QRectF(m_dragged_piece_pos, QSizeF(m_square_size, m_square_size)));
                }```
                JoeCFDJ Offline
                JoeCFDJ Offline
                JoeCFD
                wrote on last edited by
                #9

                @additional-pumpkin I think you call the func in the line 413. Go deep from there and make your func to get rid of overlaps.

                1 Reply Last reply
                0
                • additional-pumpkinA additional-pumpkin

                  Also this SVG will normally be drawn with a normal opacity. Only when the user interacts with it and drags it it will leave behind a ghost svg which is what i want to implement by making in transparent.

                  Here's an example of it being done (by rust-chessground)
                  Screenshot_20230530_221802.png

                  And this is what it looks like in my app right nowScreenshot_20230530_222058.png

                  I want the piece that is being dragged to leave behind a 'ghost' piece on the square it was dragged from. This would be very simple to implement if I could set an custom opacity while rendering the svg with QSvgRenderer, but since QSvgRenderer has no such functionality how can I do this?

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

                  @additional-pumpkin making a 3D board may have more fun.

                  1 Reply Last reply
                  0
                  • additional-pumpkinA additional-pumpkin

                    @JoeCFD

                    Here's my code for drawing the pieces
                    (pieces[] is an array of QSvgRenderers)

                    void BoardView::draw_pieces(QPaintEvent *event)
                    {
                        QPainter painter(this);
                        painter.setRenderHint(QPainter::Antialiasing);
                        for (chessops::Square sq = chessops::A1; sq <= chessops::H8; ++sq) {
                            int x = sq % 8;
                            int y = 7 - sq / 8;
                            QPointF pos(x * m_square_size, y * m_square_size);
                            chessops::Piece piece = m_board.get_piece_at(sq);
                            if (m_board.is_check() && chessops::type_of(piece) == chessops::PieceType::KING && chessops::color_of(piece) == m_board.get_stm()) {
                                QRadialGradient check_indicator(QPointF(pos.x() + m_square_size/2, pos.y() + m_square_size/2), m_square_size/2);
                                check_indicator.setColorAt(0, Qt::red);
                                check_indicator.setColorAt(1, Qt::transparent);
                                painter.fillRect(QRectF(pos, QSizeF(m_square_size, m_square_size)), check_indicator);
                            }
                            if (sq == m_drag_start) {
                                painter.fillRect(QRectF(pos, QSizeF(m_square_size, m_square_size)), QBrush(QColor(20, 85, 30, 255/2)));
                                // continue;
                            }
                            if(piece != chessops::PIECE_NONE) {
                                pieces[m_board.get_piece_at(sq)].render(&painter, QRectF(pos, QSizeF(m_square_size, m_square_size)));
                            }
                            if(m_board.is_piece_attack(m_drag_start, sq)) {
                                if (piece == chessops::Piece::PIECE_NONE) {
                                    QPointF circle_pos = pos;
                                    circle_pos.setX(circle_pos.x() + m_square_size/4 + m_square_size/8);
                                    circle_pos.setY(circle_pos.y() + m_square_size/4 + m_square_size/8);
                                    painter.setPen(Qt::transparent);
                                    painter.setBrush(QColor(20, 85, 30, 128));
                                    painter.drawEllipse(QRectF(circle_pos, QSizeF(m_square_size/4, m_square_size/4)));
                                }
                                else {
                                    QPointF circle_pos = pos;
                                    circle_pos.setX(circle_pos.x() - m_square_size/16);
                                    circle_pos.setY(circle_pos.y() - m_square_size/16);
                                    QPainterPath path;
                                    QPainterPath bounds;
                                    path.addRect(QRectF(pos, QSizeF(m_square_size, m_square_size)));
                                    path.addEllipse(QRectF(circle_pos, QSizeF(m_square_size + m_square_size/8, m_square_size + m_square_size/8)));
                                    bounds.addRect(QRectF(pos, QSizeF(m_square_size/4, m_square_size/4)));
                                    bounds.addRect(QRectF(QPointF(pos.x() + m_square_size - m_square_size/4, pos.y()), QSizeF(m_square_size/4, m_square_size/4)));
                                    bounds.addRect(QRectF(QPointF(pos.x(), pos.y() + m_square_size - m_square_size/4), QSizeF(m_square_size/4, m_square_size/4)));
                                    bounds.addRect(QRectF(QPointF(pos.x() + m_square_size - m_square_size/4, pos.y() + m_square_size - m_square_size/4), QSizeF(m_square_size/4, m_square_size/4)));
                                    painter.setPen(Qt::transparent);
                                    painter.setBrush(QColor(20, 85, 30, 128));
                                    // painter.drawPath(path);
                                    painter.drawPath(path.intersected(bounds));
                                    // painter.fillPath(bounds, QColor(Qt::red));
                    
                                }
                            }
                    
                            if (m_debug_overlay) {
                                if (m_board.debug_is_enemy_attack(sq)) {
                                    painter.setPen(QPen(Qt::red, 10));
                                    painter.setBrush(Qt::transparent);
                                    painter.drawEllipse(QRectF(pos, QSizeF(m_square_size, m_square_size)));
                                }
                            }
                        }
                        if (m_drag_start != chessops::SQUARE_NONE && m_board.get_piece_at(m_drag_start) != chessops::PIECE_NONE)
                            pieces[m_board.get_piece_at(m_drag_start)].render(&painter, QRectF(m_dragged_piece_pos, QSizeF(m_square_size, m_square_size)));
                    }```
                    Chris KawaC Offline
                    Chris KawaC Offline
                    Chris Kawa
                    Lifetime Qt Champion
                    wrote on last edited by
                    #11

                    @additional-pumpkin Unless the pieces change in some way you shouldn't be rendering them directly from an SVG every time you draw a piece. SVG is a complicated format and that's very inefficient, especially since you're gonna draw the same type of piece multiple times (e.g. the pawns). Draw each piece once to a pixmap and store it. When you need to draw the piece draw the stored pixmap instead. Additional benefit is that drawing a pixmap with a regular painter will let you set opacity on the painter. It's gonna be much more performant and will solve your opacity problem at the same time.

                    additional-pumpkinA 1 Reply Last reply
                    2
                    • Chris KawaC Chris Kawa

                      @additional-pumpkin Unless the pieces change in some way you shouldn't be rendering them directly from an SVG every time you draw a piece. SVG is a complicated format and that's very inefficient, especially since you're gonna draw the same type of piece multiple times (e.g. the pawns). Draw each piece once to a pixmap and store it. When you need to draw the piece draw the stored pixmap instead. Additional benefit is that drawing a pixmap with a regular painter will let you set opacity on the painter. It's gonna be much more performant and will solve your opacity problem at the same time.

                      additional-pumpkinA Offline
                      additional-pumpkinA Offline
                      additional-pumpkin
                      wrote on last edited by
                      #12

                      @Chris-Kawa Thank you so much!! This works great!

                      1 Reply Last reply
                      0
                      • additional-pumpkinA additional-pumpkin has marked this topic as solved on

                      • Login

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