Search code examples
pyqt5qgraphicssceneqpainterqimageqrect

QGraphicsScene: Artifacts when rendering and saving the scene to a file


I am working with PyQt5 (Version 5.15.7) in PyCharm Community on Windows 11.

I have subclassed the QGraphicsScene and added some attribute and methods I need. I add some QGraphicsItems and QGraphicsItemGroups on the scene and display it in a QMainWindow using a QGraphicsView. Now I want to store the content of the whole scene as simple PNG with transparency. I added self.setBackgroundBrush(Qt.transparent) to my QGraphicsScene subclass.

I use now the following Code to render from my QGraphicsScene into a QImage and then I store the QImage:


# Get region of scene to capture from somewhere.
areaF = self.my_scene.sceneRect()  # Return type: QRectF

# Create a QImage to render to and fix up a QPainter for it.
image = QImage( areaF.toRect().size(), Image.Format_ARGB32_Premultiplied ) 

painter = QPainter( image )

# Render the region of interest to the QImage.
painter.begin( image)
self.my_scene.render( painter,
                      QRectF( image.rect() ),  # target
                      areaF )  # source
painter.end()

# Save the image to a file.
image.save( filename[ 0 ] )

I found the code above as question here on stackoverflow and adapted it respecting to the comments. Everything is fine, BUT the PNG contains very often artifacts like this: (Enlarged screenshots from MSPaint):

This is the original picture taken as screenshot from my app

The PNG should look like the last screenshot...without these strange points and lines... The artifacts are sometimes really hard, sometimes they don't appear... Does anybody have an idea why these artifacts appear and how I could evade them?


Solution

  • I changed the Code according to the musicamente's comments, and it works without artifacts :-)

    Here the Code with the changes applied (the method is now part of my subclassed QGraphicsScene):

        def scene_to_image( self ):
            # Get region of scene to capture from somewhere.
            areaF = self.sceneRect()  # Return type: QRectF
            # Create a QImage to render to and fix up a QPainter for it.
            image = QImage(areaF.toRect().size(),
                           QImage.Format_ARGB32_Premultiplied
                           )  
            # MUSICAmAnte :-)
            image.fill(Qt.transparent)
    
            painter = QPainter(image)
    
            # MUSICAmAnte :-)
            painter.setRenderHint(painter.Antialiasing)
    
            # Render the region of interest to the QImage.
            self.render(painter, 
                        QRectF(image.rect()),  # target
                        areaF                  # source
                        )
            painter.end()
            return image