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
Forum Updated to NodeBB v4.3 + New Features

Qpainter scale pixmap to parent with aspect ratio

Scheduled Pinned Locked Moved Unsolved General and Desktop
qpainterscale to fitaspect ratiopixm
15 Posts 4 Posters 13.0k Views 2 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.
  • pauleddP Offline
    pauleddP Offline
    pauledd
    wrote on last edited by
    #1

    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?

    raven-worxR VRoninV 2 Replies Last reply
    0
    • pauleddP pauledd

      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?

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

      @pauledd
      i suggest to cache the pixmap upon widget resize and just paint it in the paintEvent().

      void VideoFrame::resizeEvent(QResizeEvent* event)
      {
           const QSize size = event->size();
           m_CachedPixmap =  size.height() < size.width() ? m_Pixmap.scaledToHeight(size.height(), Qt::SmoothTransformation) : m_Pixmap.scaledToWidth(size.width(), Qt::SmoothTransformation);
           this->update();
           QWidget::resizeEvent(event);
      }
      
      void VideoFrame::paintEvent(QPaintEvent *)
      {
         ...
         const QSize pixSIze = m_CachedPixmap.size();
         const int x = (this->rect().width() - pixSize .width()) / 2.0;
         const int y = (this->rect().height() - pixSize .height()) / 2.0;
         painter.drawPixmap(x,y, pixSize.width(), pixSIze .height(), m_CachedPixmap);
         ...
      }
      

      (untested)

      --- 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
      3
      • pauleddP pauledd

        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?

        VRoninV Offline
        VRoninV Offline
        VRonin
        wrote on 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
        • pauleddP Offline
          pauleddP Offline
          pauledd
          wrote on 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...

          raven-worxR 1 Reply Last reply
          0
          • pauleddP pauledd

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

            raven-worxR Offline
            raven-worxR Offline
            raven-worx
            Moderators
            wrote on 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

            pauleddP 1 Reply Last reply
            2
            • raven-worxR raven-worx

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

              pauleddP Offline
              pauleddP Offline
              pauledd
              wrote on 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?

              raven-worxR VRoninV 2 Replies Last reply
              0
              • pauleddP pauledd

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

                raven-worxR Offline
                raven-worxR Offline
                raven-worx
                Moderators
                wrote on 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
                • pauleddP pauledd

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

                  VRoninV Offline
                  VRoninV Offline
                  VRonin
                  wrote on 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
                  • pauleddP Offline
                    pauleddP Offline
                    pauledd
                    wrote on 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
                    • pauleddP Offline
                      pauleddP Offline
                      pauledd
                      wrote on 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?

                      mrjjM VRoninV 2 Replies Last reply
                      0
                      • pauleddP pauledd

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

                        mrjjM Offline
                        mrjjM Offline
                        mrjj
                        Lifetime Qt Champion
                        wrote on 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
                        • pauleddP pauledd

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

                          VRoninV Offline
                          VRoninV Offline
                          VRonin
                          wrote on 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
                          • pauleddP Offline
                            pauleddP Offline
                            pauledd
                            wrote on 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..." :)

                            VRoninV 1 Reply Last reply
                            0
                            • pauleddP pauledd

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

                              VRoninV Offline
                              VRoninV Offline
                              VRonin
                              wrote on 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
                              • pauleddP Offline
                                pauleddP Offline
                                pauledd
                                wrote on 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

                                • Login

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