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. Qpainter scale pixmap to parent with aspect ratio

Qpainter scale pixmap to parent with aspect ratio

Scheduled Pinned Locked Moved Unsolved General and Desktop
qpainterscale to fitaspect ratiopixm
15 Posts 4 Posters 12.8k 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.
  • P pauledd
    18 Jun 2018, 07:04

    Hi there,

    I have a mainwindow (red). Inside there I have a QFrame derived "VideoFrame" (green).
    Inside that I have an overwritten paintevent and a QPainter. Inside that I have a centered painter.pixmap().

    0_1529305105666_Bildschirmfoto_2018-06-18_08-37-26.png

    I want that painter/pixmap to grow to the edges of the green Frame if I resize the mainwindow, but keeping its aspect ratio (should be 1.333333 with 320x240).

    I simply dont get behind how to do it but I tried it with painter.scale():

    void VideoFrame::paintEvent(QPaintEvent *)
    {
        QPainter painter(this);
        painter.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform,1);
        QPixmap pxmap;
        QPoint center(this->width()/2,this->height()/2);
        painter.translate(center);
    
        painter.scale(1*(this->width()/240.0),1*(this->width()/320.0));
    
        painter.rotate(v_rotation);
        painter.translate(0-320/2,0-240/2);
        painter.drawPixmap(0,0,320,240,QPixmap::fromImage(QImage("image_320.png")));
    
    }
    

    The problem with that is it grows over the top/buttom edges, but stays inside left/right and keeps aspect ratio, so I guess I am close to the solution...

    0_1529305412522_Peek 2018-06-18 09-02.gif

    Any ideas anyone?

    V Offline
    V Offline
    VRonin
    wrote on 18 Jun 2018, 07:35 last edited by VRonin
    #3
    void VideoFrame::paintEvent(QPaintEvent *)
    {
        QPainter painter(this);
        QSize widgetSize = rect().size();
        const QPixmap paintPixmap(QStringLiteral("image_320.png"));
        const auto newHeight = widgetSize.width()*paintPixmap.height()/paintPixmap.width();
        if(newHeight<=widgetSize.height())
            widgetSize.setHeight(newHeight);
        else
            widgetSize.setWidth(widgetSize.height()*paintPixmap.width()/paintPixmap.height());
        style()->drawItemPixmap(&painter,rect(),Qt::AlignCenter,paintPixmap.scaled(widgetSize));
    }
    

    "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
    ~Napoleon Bonaparte

    On a crusade to banish setIndexWidget() from the holy land of Qt

    1 Reply Last reply
    3
    • P Offline
      P Offline
      pauledd
      wrote on 18 Jun 2018, 14:21 last edited by pauledd
      #4

      thanks to you both :)
      @raven-worx
      I tried your code but the image "plopps" strangely and gets bigger than the frame for a short time...

      0_1529331170841_Peek 2018-06-18 16-10.gif
      Why caching the pixmap? Did you do this for performance reasons?

      @VRonin
      Your code worked flawlessly.

      I will later replace the image file again with a pointer to an QImage that gets updated at 9fps (thermal camera source) so @VRonin solution "feels" better for now, because I dont know how this caching the image while resize will impact my livestream...

      R 1 Reply Last reply 18 Jun 2018, 18:23
      0
      • P pauledd
        18 Jun 2018, 14:21

        thanks to you both :)
        @raven-worx
        I tried your code but the image "plopps" strangely and gets bigger than the frame for a short time...

        0_1529331170841_Peek 2018-06-18 16-10.gif
        Why caching the pixmap? Did you do this for performance reasons?

        @VRonin
        Your code worked flawlessly.

        I will later replace the image file again with a pointer to an QImage that gets updated at 9fps (thermal camera source) so @VRonin solution "feels" better for now, because I dont know how this caching the image while resize will impact my livestream...

        R Offline
        R Offline
        raven-worx
        Moderators
        wrote on 18 Jun 2018, 18:23 last edited by raven-worx
        #5

        @pauledd said in Qpainter scale pixmap to parent with aspect ratio:

        I tried your code but the image "plopps" strangely and gets bigger than the frame for a short time...

        as stated its untested, and straight out of my head. But i guess i'ts just a minor mistake in the calculation.

        Why caching the pixmap? Did you do this for performance reasons?

        yes, because there is no need to load a pixmap from file in every paintEvent() call!

        --- 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

        P 1 Reply Last reply 18 Jun 2018, 19:12
        2
        • R raven-worx
          18 Jun 2018, 18:23

          @pauledd said in Qpainter scale pixmap to parent with aspect ratio:

          I tried your code but the image "plopps" strangely and gets bigger than the frame for a short time...

          as stated its untested, and straight out of my head. But i guess i'ts just a minor mistake in the calculation.

          Why caching the pixmap? Did you do this for performance reasons?

          yes, because there is no need to load a pixmap from file in every paintEvent() call!

          P Offline
          P Offline
          pauledd
          wrote on 18 Jun 2018, 19:12 last edited by
          #6

          @raven-worx said in Qpainter scale pixmap to parent with aspect ratio:

          yes, because there is no need to load a pixmap from file in every paintEvent() call!

          Okay but later I will use this:

          bool VideoFrame::startCam()
          {
          ...
          for(int i=0;i<img->height();i++)
              {
                  memcpy(img->scanLine(i), frame1.row(i).data, img->bytesPerLine());
              }
              update();
          ...
          }
          ...
          
          
          
          void VideoFrame::paintEvent(QPaintEvent *)
          {
          ...
              const QPixmap paintPixmap(QPixmap::fromImage(*img));
          ...
          }
          

          I have camera data from frame1 that is constantly copied to "img" and then drawed in the paintEvent... would that caching make then sense too? I used the static image just as placeholder to demonstrate...

          @VRonin
          I got a new problem with your code.. how can I then rotate the rect/image around its centerpoint. If I simply rotate the painter the centerpoint lays in the upper left corner. I then tried to translate the painter to half of the image dimensions and then tried painter.rotate but with your code that doesnt work anymore, can you give me a hint how to solve that?

          R V 2 Replies Last reply 19 Jun 2018, 06:11
          0
          • P pauledd
            18 Jun 2018, 19:12

            @raven-worx said in Qpainter scale pixmap to parent with aspect ratio:

            yes, because there is no need to load a pixmap from file in every paintEvent() call!

            Okay but later I will use this:

            bool VideoFrame::startCam()
            {
            ...
            for(int i=0;i<img->height();i++)
                {
                    memcpy(img->scanLine(i), frame1.row(i).data, img->bytesPerLine());
                }
                update();
            ...
            }
            ...
            
            
            
            void VideoFrame::paintEvent(QPaintEvent *)
            {
            ...
                const QPixmap paintPixmap(QPixmap::fromImage(*img));
            ...
            }
            

            I have camera data from frame1 that is constantly copied to "img" and then drawed in the paintEvent... would that caching make then sense too? I used the static image just as placeholder to demonstrate...

            @VRonin
            I got a new problem with your code.. how can I then rotate the rect/image around its centerpoint. If I simply rotate the painter the centerpoint lays in the upper left corner. I then tried to translate the painter to half of the image dimensions and then tried painter.rotate but with your code that doesnt work anymore, can you give me a hint how to solve that?

            R Offline
            R Offline
            raven-worx
            Moderators
            wrote on 19 Jun 2018, 06:11 last edited by
            #7

            @pauledd said in Qpainter scale pixmap to parent with aspect ratio:

            I have camera data from frame1 that is constantly copied to "img" and then drawed in the paintEvent... would that caching make then sense too?

            basically yes, since you do not know how often the paintEvent() will be called until the next image is received.

            And also btw, it's not necessary to convert the QImage to a QPixmap just for drawing. QPainter also provides methods to draw a QImage directly.

            --- 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
            • P pauledd
              18 Jun 2018, 19:12

              @raven-worx said in Qpainter scale pixmap to parent with aspect ratio:

              yes, because there is no need to load a pixmap from file in every paintEvent() call!

              Okay but later I will use this:

              bool VideoFrame::startCam()
              {
              ...
              for(int i=0;i<img->height();i++)
                  {
                      memcpy(img->scanLine(i), frame1.row(i).data, img->bytesPerLine());
                  }
                  update();
              ...
              }
              ...
              
              
              
              void VideoFrame::paintEvent(QPaintEvent *)
              {
              ...
                  const QPixmap paintPixmap(QPixmap::fromImage(*img));
              ...
              }
              

              I have camera data from frame1 that is constantly copied to "img" and then drawed in the paintEvent... would that caching make then sense too? I used the static image just as placeholder to demonstrate...

              @VRonin
              I got a new problem with your code.. how can I then rotate the rect/image around its centerpoint. If I simply rotate the painter the centerpoint lays in the upper left corner. I then tried to translate the painter to half of the image dimensions and then tried painter.rotate but with your code that doesnt work anymore, can you give me a hint how to solve that?

              V Offline
              V Offline
              VRonin
              wrote on 19 Jun 2018, 07:36 last edited by
              #8

              @pauledd said in Qpainter scale pixmap to parent with aspect ratio:

              how can I then rotate the rect/image around its centerpoint.

              Do not rotate the painter, rotate the pixmap.

              QPainter painter(this);
                  QSize widgetSize = rect().size();
                  QPixmap paintPixmap(QStringLiteral("image_320.png"));
                  QTransform rotateTransform;
                  rotateTransform.rotate(45);
                  paintPixmap=paintPixmap.transformed(rotateTransform);
                  const auto newHeight = widgetSize.width()*paintPixmap.height()/paintPixmap.width();
                  if(newHeight<=widgetSize.height())
                      widgetSize.setHeight(newHeight);
                  else
                      widgetSize.setWidth(widgetSize.height()*paintPixmap.width()/paintPixmap.height());
                  style()->drawItemPixmap(&painter,rect(),Qt::AlignCenter,paintPixmap.scaled(widgetSize));
              

              Caching does makes a lot of sense, you can use QPixmapCache

              @raven-worx said in Qpainter scale pixmap to parent with aspect ratio:

              QPainter also provides methods to draw a QImage directly.

              Yes but:

              • it just calls QPixmap::fromImage internally: https://code.woboq.org/qt5/qtbase/src/gui/painting/qpaintengine.cpp.html#625
              • QStyle doesn't have it

              "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
              ~Napoleon Bonaparte

              On a crusade to banish setIndexWidget() from the holy land of Qt

              1 Reply Last reply
              3
              • P Offline
                P Offline
                pauledd
                wrote on 19 Jun 2018, 11:04 last edited by
                #9

                Great, thank you both for the hints, I will try to go on by myself but keep that topic unresolved for a few days as long as I am not finshed.

                1 Reply Last reply
                0
                • P Offline
                  P Offline
                  pauledd
                  wrote on 19 Jun 2018, 13:06 last edited by
                  #10

                  @VRonin I dont yet get behind the way you draw the pixmap in your code.
                  you use (still noob beginner ;) ):

                  style()->drawItemPixmap(&painter,rect(),Qt::AlignCenter,paintPixmap.scaled(widgetSize));
                  

                  I've never seen such a style()-> ... alone without an object... it seems to be not declared somewhere, to what does it refer to? To the Qpainter?

                  The same is with the:

                  QSize widgetSize = rect().size();
                  

                  rect().size(); refers to the QFrame? I usually would expext an "this.rect().size();"

                  And that brings me to another question. If I need to draw an ellipse, as I did
                  previously with painter.drawEllipse, into that image area, for example at position 40,40 seen from top/left and staying at that point while rotating with the image how would that fit into your way to draw with:

                  style()->drawItem...
                  

                  or is that not possible?

                  M V 2 Replies Last reply 19 Jun 2018, 13:17
                  0
                  • P pauledd
                    19 Jun 2018, 13:06

                    @VRonin I dont yet get behind the way you draw the pixmap in your code.
                    you use (still noob beginner ;) ):

                    style()->drawItemPixmap(&painter,rect(),Qt::AlignCenter,paintPixmap.scaled(widgetSize));
                    

                    I've never seen such a style()-> ... alone without an object... it seems to be not declared somewhere, to what does it refer to? To the Qpainter?

                    The same is with the:

                    QSize widgetSize = rect().size();
                    

                    rect().size(); refers to the QFrame? I usually would expext an "this.rect().size();"

                    And that brings me to another question. If I need to draw an ellipse, as I did
                    previously with painter.drawEllipse, into that image area, for example at position 40,40 seen from top/left and staying at that point while rotating with the image how would that fit into your way to draw with:

                    style()->drawItem...
                    

                    or is that not possible?

                    M Offline
                    M Offline
                    mrjj
                    Lifetime Qt Champion
                    wrote on 19 Jun 2018, 13:17 last edited by mrjj
                    #11

                    Hi
                    style()
                    refers to the QWidget member method that returns the active
                    QStyle.
                    It would be the same as this->Style().
                    Same with
                    rect().size();
                    also means this-> rect().size();
                    They are defined in the base class. ( QWidget )

                    1 Reply Last reply
                    1
                    • P pauledd
                      19 Jun 2018, 13:06

                      @VRonin I dont yet get behind the way you draw the pixmap in your code.
                      you use (still noob beginner ;) ):

                      style()->drawItemPixmap(&painter,rect(),Qt::AlignCenter,paintPixmap.scaled(widgetSize));
                      

                      I've never seen such a style()-> ... alone without an object... it seems to be not declared somewhere, to what does it refer to? To the Qpainter?

                      The same is with the:

                      QSize widgetSize = rect().size();
                      

                      rect().size(); refers to the QFrame? I usually would expext an "this.rect().size();"

                      And that brings me to another question. If I need to draw an ellipse, as I did
                      previously with painter.drawEllipse, into that image area, for example at position 40,40 seen from top/left and staying at that point while rotating with the image how would that fit into your way to draw with:

                      style()->drawItem...
                      

                      or is that not possible?

                      V Offline
                      V Offline
                      VRonin
                      wrote on 19 Jun 2018, 13:20 last edited by
                      #12

                      @pauledd said in Qpainter scale pixmap to parent with aspect ratio:

                      I usually would expext an "this.rect().size();"

                      Do you come from python? it is this->rect() and this->style() but in C++ you don't need to explicitly use this in front.

                      to what does it refer to? To the Qpainter?

                      http://doc.qt.io/qt-5/qwidget.html#style

                      @pauledd said in Qpainter scale pixmap to parent with aspect ratio:

                      If I need to draw an ellipse, as I did

                      QStyle/QStylePainter is an abstraction over the drawing of controls, it does not provide drawing of basics like lines and circles. See http://doc.qt.io/qt-5/qstyle.html#developing-style-aware-custom-widgets

                      "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
                      ~Napoleon Bonaparte

                      On a crusade to banish setIndexWidget() from the holy land of Qt

                      1 Reply Last reply
                      0
                      • P Offline
                        P Offline
                        pauledd
                        wrote on 19 Jun 2018, 13:39 last edited by
                        #13

                        Okay thanks, so I will paint an ellipse as png and then load it the same way you did with the "style()->drawItem..." :)

                        V 1 Reply Last reply 20 Jun 2018, 07:52
                        0
                        • P pauledd
                          19 Jun 2018, 13:39

                          Okay thanks, so I will paint an ellipse as png and then load it the same way you did with the "style()->drawItem..." :)

                          V Offline
                          V Offline
                          VRonin
                          wrote on 20 Jun 2018, 07:52 last edited by VRonin
                          #14

                          @pauledd said in Qpainter scale pixmap to parent with aspect ratio:

                          I will paint an ellipse as png

                          Saving and loading to png file format is expensive, I would advise against it.

                          If the position of the ellipsis doesn't change in the pixmap then draw it using QPainter on the pixmap and cache it. If the ellipsis is dynamic then paint it directly on the widget from the paintEvent

                          "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
                          ~Napoleon Bonaparte

                          On a crusade to banish setIndexWidget() from the holy land of Qt

                          1 Reply Last reply
                          0
                          • P Offline
                            P Offline
                            pauledd
                            wrote on 20 Jun 2018, 08:59 last edited by
                            #15

                            Ok, I will try that...
                            Maybe I should have been more clearly what I intend to get...
                            I had it all working already, just without the scaling issue

                            alt text

                            I get camera images and I let opencv compute min/max values and a centerpoint. Somethimes the camera is rotated in a undesired position so the user should be able to rotate the view, including the measurepoints, and more complex including the point values so that the stay at the points but do not rotate staying readable...

                            I keep trying with qpainter draw

                            1 Reply Last reply
                            0

                            12/15

                            19 Jun 2018, 13:20

                            • Login

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