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. Scaling problems in Ubuntu using QPixmap and QPainter
QtWS25 Last Chance

Scaling problems in Ubuntu using QPixmap and QPainter

Scheduled Pinned Locked Moved General and Desktop
8 Posts 2 Posters 5.2k 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.
  • T Offline
    T Offline
    TrailWalker
    wrote on last edited by
    #1

    Hi, I've created a drawing program that allow zooming of the image. For this I am using QPixmaps and QPainter. I have 2 functions for drawing. One is for drawing shapes to the QPixmap and the other outputs the QPixmap to the screen. These are:

    @void Window::paintEvent(QPaintEvent * /* event */) //for painting to screen@
    and
    @void Window::drawShape(moveTypes t) {} //for drawing to the QPixmap@

    I have included the code for paintEvent at the end of this message. Note that paintEvent first paints the background, then the QPixmap followed by the shape 'cursor' outline. It also uses double buffering.

    The problem I am having is that the program runs very fast when compiled for Windows XP (using Qt Creator/mingw32/g++). And this applies both without scaling and with the scale enlarged/reduced (using QPainter::scale -- and scaling up 8 times the length of the original image). However when I compile the program in Ubuntu (again using Qt Creator) I find that the drawing is acceptable without scaling, but becomes incredibly slow when scaling is being used (regardless of of the amount of scaling applied).

    For example when compiled for Windows I can work with very large images (e.g. 5000 x 5000 pixels) with only a small reduction of performance and regardless of scale. However with Ubuntu drawing becomes very slow when scaling is applied. It seems strange also because the windows release works much better on Ubuntu using Wine than the native compiled program. Of course it runs slower than on windows, however there is no performance loss with scaling -- so overall it draws much faster. I have also tried using 'setAttribute(Qt::WA_PaintOnScreen);' with the Ubuntu version and it makes very little difference.

    Is there something I can do to fix the code for Ubuntu? I'm used to Java and I'm also a C++/Qt beginner so please go gentle with me :-) Many thanks.

    Michael

    @void Window::paintEvent(QPaintEvent * /* event */)
    {

    QPainter painter(this);
    painter.scale(zoomScale, zoomScale);
    //painter.setBackgroundMode(Qt::TransparentMode);
    
    painter.drawPixmap(0, 0, *grid);
    //painter.drawRect(QRect(0,0, imageWidth*zoomScale, imageHeight*zoomScale));
    
    painter.drawPixmap(0, 0, *pixMap);
    
    
    //if (at_zero == false) {
    
        QBrush outline(QColor("black"));
    
        lineWidth = penWidth;
    
        if (RELATIVE_PEN_WIDTH == true) {
            if (lineWidth > (xRadius / 3)) lineWidth = xRadius/3;
            if (lineWidth > (yRadius / 3)) lineWidth = yRadius/3;
            if (lineWidth < 1) lineWidth = 1;
        } else {
            if (lineWidth > (xRadius * 2)) lineWidth = xRadius * 2;
            if (lineWidth > (yRadius * 2)) lineWidth = yRadius * 2;
    
        }
        //if (curTool != BRUSH_TOOL) return;
        QPen pen( outline,  lineWidth * brushScale, Qt::SolidLine, Qt::SquareCap, Qt::BevelJoin );
        painter.setPen(pen);
        int penOffset = 0;
        if (antiAliasing == false && zoomScale > 1) penOffset = 1;
    
    
        int drawX = (xPos - xRadius) * brushScale;
        int drawY = (yPos - yRadius) * brushScale;
    
        int transX = drawX + (xRadius * brushScale);
        int transY = drawY + (yRadius * brushScale);
        painter.translate(transX, transY);
        painter.rotate(rotateAngle);
        painter.translate(-transX, -transY);
    
        if (shape == ELLIPSE)
            painter.drawEllipse(drawX, drawY ,  (xRadius * 2) * brushScale   , (yRadius * 2)*brushScale);
        else
            painter.drawRect(drawX, drawY ,  (xRadius * 2) * brushScale   , (yRadius * 2)*brushScale);
    //}
    
    //}
    

    };@

    1 Reply Last reply
    0
    • Z Offline
      Z Offline
      ZapB
      wrote on last edited by
      #2

      What graphics system are you running with? Try launching your app with the -graphicssystem raster option:

      @./myapp -graphicssystem raster@

      Does that make it work faster/slower/same?

      Nokia Certified Qt Specialist
      Interested in hearing about Qt related work

      1 Reply Last reply
      0
      • T Offline
        T Offline
        TrailWalker
        wrote on last edited by
        #3

        That's awesome thank you! It's now drawing 'almost' as fast as on windows and without the scaling penalty. Is it possible to hard code this setting into the application? Or is this something particular to linux?

        I've got another question which is that the update when dragging the mouse is somewhat slower on Ubuntu (i.e. the program uses the Window::mouseMoveEvent ( QMouseEvent * event ){} to call the function for drawing shapes to the QPixmap/screen). It's not really all that much of a problem because I can simple increase the number of interpolation steps. And I also quite like the fact that the program "feels and runs" differently with different operating systems (since this is an artsy 'no limits' kind of application!). However ideally I would like to fix this (but only if it doesn't have negative side-effects -- I realise that there may be good reasons for this slower drag-update). I don't know if this is a setting specific to Ubuntu/Gnome or if this is more related to how Qt runs under Ubuntu/Gnome.

        Michael

        1 Reply Last reply
        0
        • Z Offline
          Z Offline
          ZapB
          wrote on last edited by
          #4

          The default graphics system for Qt apps is determined at configure time for Qt itself. It sounds as it Ubuntu is using the X11 graphics system as default then. Some code paths are known to be slow in the X11 graphics system which is why I suggested you try the raster one - that is the default on Windows. [NB. I use Gentoo and use raster as the default]

          It is possible to override the default graphics system on the command line as I showed you, or you can hard code it into the app using "QApplication::setGraphicsSystem":http://doc.qt.nokia.com/latest/qapplication.html#setGraphicsSystem. Note that you may want to surround this function call with platform-specific #ifdefs so that you override it for platforms only on platforms that need it.

          As for the dragging question, can you provide a small compilable example that reproduces it please? I am not quite sure what you mean from your description.

          Nokia Certified Qt Specialist
          Interested in hearing about Qt related work

          1 Reply Last reply
          0
          • T Offline
            T Offline
            TrailWalker
            wrote on last edited by
            #5

            I think you are right when you say Ubuntu uses X11. I will try your suggestion of using QApplication::setGraphicsSystem.

            It would be hard to provide a small example of the dragging problem because it uses a lot of class scope variables. However I don't think it would help you much because it is only slow relative to windows. I mean if I had never run the program on windows I would not think there is a problem.

            The update effect is seen when the user drags the mouse which triggers the mouseMoveEvent function which rotates the brush (if required) and then calls DrawShape(DRAG) function.

            @void Window::mouseMoveEvent ( QMouseEvent * event ) {

            //repaint();
            
            if (positioning == false) {
            
                //if (curTool != BRUSH_TOOL) return;
            
                xAbsolute = (float)event->x();
                yAbsolute = (float)event->y();
                QPoint qP = getCursorLocation(event->pos());
                xPos = qP.x() - xOffset;
                yPos = qP.y() - yOffset;
                if (drawing == false && justChangedBrushScale == true) {
                    drawing = true;
                    justChangedBrushScale = false;
                    prevX = xPos;
                    prevY = yPos;
                    prevRotateAngle = rotateAngle;
                }
            
            
                bool dragDraw = true;
                if (CUTOFF_ZERO == true && at_zero == true) dragDraw = false;
                if (drawing == true && dragDraw == true) {
                    //mouseMovedCount ++;
            
                    if (moveRotate == ROTATE_CLOCKWISE)
                        rotateShapeClockwise();
                    else if (moveRotate == ROTATE_ANTI_CLOCKWISE)
                        rotateShapeAntiClockwise();
            
            
                    drawShape(DRAG); //Call function for updated QPixmap
            
                    prevX = xPos;
                    prevY = yPos;
                    prevRotateAngle = rotateAngle;
            
                }
            }  else { //positioning is true
                QPoint qP = getCursorLocation(event->pos());
                xOffset = qP.x() - xPos ;
                yOffset = qP.y() - yPos ;
            }
            
            update();
            updateCoordsMessage();
            

            };@

            1 Reply Last reply
            0
            • T Offline
              T Offline
              TrailWalker
              wrote on last edited by
              #6

              Here is the code for updating the QPixmap. This is called from Window::mouseMoveEvent.

              @void Window::drawShape(moveTypes t) {

              lineWidth = penWidth;
              
              if (RELATIVE_PEN_WIDTH == true) {
                  if (lineWidth > (xRadius / 3)) lineWidth = xRadius/3;
                  if (lineWidth > (yRadius / 3)) lineWidth = yRadius/3;
                  if (penWidth > 0 && lineWidth == 0) lineWidth = 1;
              } else {
                  if (lineWidth > (xRadius * 2)) lineWidth = xRadius * 2;
                  if (lineWidth > (yRadius * 2)) lineWidth = yRadius * 2;
                  //if (penWidth > 0 && lineWidth == 0) lineWidth = 1;
              }
              
              QPainter painter(pixMap);
              painter.setBackgroundMode(Qt::TransparentMode);
              
              painter.scale(brushScale, brushScale);
              
              painter.setBackgroundMode(Qt::TransparentMode);
              painter.setRenderHint(QPainter::Antialiasing, antiAliasing);
              
              
              //QBrush outline(*penColour, Qt::CrossPattern);
              QBrush outline(*penColour);
              QPen pen( outline,  lineWidth , Qt::SolidLine, Qt::SquareCap, Qt::BevelJoin );
              if (penWidth > 0) painter.setPen(pen);
              else painter.setPen(Qt::NoPen);
              
              //QBrush brush(*brushColour, Qt::CrossPattern);
              QBrush brush(*brushColour);
              painter.setBrush(brush);
              
              
              if (t == DRAG && interpolationSteps > 1) {
                  //-----------------------------
                  //create steps for interpolation
                  float width = abs(xPos - prevX);
                  float height = abs(yPos - prevY);
                  float hyp = sqrt((width * width) + (height * height));
              
                  float distance = hyp / interpolationSteps;
              
                  float tangent = width / height;
                  float angle = atan(tangent);
                  //double angleDegrees = angle * 57.29578;
              
                  float newWidth = sin(angle) * distance;
                  float newHeight = cos(angle) * distance;
              
                  if (prevX > xPos) newWidth = -newWidth;
                  if (prevY > yPos) newHeight = -newHeight;
                  float curStepX = newWidth;
                  float curStepY = newHeight;
              
              
                  //angle steps
              
                  float angleDistance = 0;
                  float angleStep = 0;
                  //qDebug() << "angleDistance " << angleDistance;
                  if (ROTATE_INTERPOLATE == true) {
                      if (moveRotate == ROTATE_CLOCKWISE) {
                          if (rotateAngle >= prevRotateAngle) angleDistance = rotateAngle - prevRotateAngle;
                          else angleDistance = 360 - prevRotateAngle +rotateAngle;
                          angleStep = angleDistance / interpolationSteps;
                      } else if (moveRotate == ROTATE_ANTI_CLOCKWISE) {
                          if (prevRotateAngle  >= rotateAngle) angleDistance = prevRotateAngle - rotateAngle  ;
                          else angleDistance = 360 -rotateAngle + prevRotateAngle ;
                          angleStep = angleDistance / interpolationSteps;
                          angleStep = -angleStep;
                      }
                  }
              
                  float curAngleStep = angleStep;
              
                  //-----------------------------
              
                   for (int i = 0; i < interpolationSteps; i++) {
              
                      int drawX = prevX + curStepX - xRadius;
                      int drawY = prevY + curStepY - yRadius;
              
                      int transX = drawX+ xRadius;
                      int transY = drawY + yRadius;
              
              
                      painter.translate(transX, transY);
                      painter.rotate(prevRotateAngle + curAngleStep);
                      painter.translate(-transX, -transY);
              
                      //painter.setOpacity(0.3);
                      painter.setOpacity(opacity);
                      if (shape == ELLIPSE)
                          painter.drawEllipse(drawX , drawY , xRadius *2, yRadius *2);
                      else
                          painter.drawRect(drawX , drawY ,  xRadius *2, yRadius *2);
              
                      curStepX += newWidth;
                      curStepY += newHeight;
              
              
                      painter.translate(transX, transY);
                      painter.rotate(-(prevRotateAngle + curAngleStep));
                      painter.translate(-transX, -transY);
              
              
                      curAngleStep += angleStep;
                      //painter.rotate(-rotateAngle);
                  }
               } else {
              
                   int drawX = xPos - xRadius;
                   int drawY = yPos - yRadius;
              
              
                   int transX = drawX + xRadius;
                   int transY = drawY + yRadius;
                   painter.translate(transX, transY);
                   painter.rotate(rotateAngle);
                   painter.translate(-transX, -transY);
              
                   painter.setOpacity(opacity);
                   if (shape == ELLIPSE)
                       painter.drawEllipse(drawX , drawY , xRadius *2, yRadius *2);
                   else
                       painter.drawRect(drawX , drawY ,  xRadius *2, yRadius *2);
              
               }
              

              }@

              1 Reply Last reply
              0
              • T Offline
                T Offline
                TrailWalker
                wrote on last edited by
                #7

                Sorry I probably didn't explain that well. I mean it is the 'frequency' of calls to drawShape that is slow in mouseMoveEvent. So as the user drags the mouse the QPixmap image is updated less frequently when using the program with Ubuntu as compared to Windows. The resulting effect is that the shapes are spaced further apart... and so more interpolation is required to correct this.

                1 Reply Last reply
                0
                • Z Offline
                  Z Offline
                  ZapB
                  wrote on last edited by
                  #8

                  Ah OK I think I understand now. I am not entirely sure what the limiting factor is in the rate at which mouse mouse events are generated. It could well be tied into the resolution used by your X mouse driver - probably a setting in xorg.conf but depend on which version of X you have - one day they'll settle on a configuration method ;-). One thing to try would be to try changing the mouse driver resolution and seeing if that affects the frequency of your mouse move events. Let us know how you get on.

                  Nokia Certified Qt Specialist
                  Interested in hearing about Qt related work

                  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