Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. Qt for Python
  4. How to resize images so they always fit to the scene ?
Forum Updated to NodeBB v4.3 + New Features

How to resize images so they always fit to the scene ?

Scheduled Pinned Locked Moved Unsolved Qt for Python
3 Posts 3 Posters 4.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.
  • M Offline
    M Offline
    Mattik
    wrote on last edited by
    #1

    Hello, so I am very new to coding but wanna learn as a hobby. What I'm trying to do as a first project is an image viewer in python using pyside6.

    After hours of banging my head against walls for the last few days I managed to figure out some stuff but I can't figure out how to correctly do one of the most important thing for an image viewer, make it so the images always fit the entirety of the window.

    Here's my code so far :

    import sys
    import os
    from PySide6.QtCore import Qt, QSize
    from PySide6.QtGui import QPixmap, QAction, QColor, QShortcut, QKeySequence, QImage
    from PySide6.QtWidgets import QApplication, QGraphicsScene, QGraphicsView, QMainWindow, QVBoxLayout, QWidget, QFileDialog, QGraphicsTextItem, QGraphicsPixmapItem
    
    class ImageViewer(QMainWindow):
        def __init__(self):
            super().__init__()
    
            self.initUI()
    
        def initUI(self):
            self.setWindowTitle("Image Viewer")
            self.setGeometry(100, 100, 800, 600)
            
            background_color = QColor(3, 5, 15)
    
            # Create a central widget and set it as the main window's central widget
            central_widget = QWidget(self)
            self.setCentralWidget(central_widget)
    
            # Create a QGraphicsView and set it as the central widget
            layout = QVBoxLayout(central_widget)
            layout.setContentsMargins(0, 0, 0, 0)
    
            #layout.setSpacing(0)
            self.view = QGraphicsView(self)
            self.view.setBackgroundBrush(background_color)
            layout.addWidget(self.view)
    
            # Create a QGraphicsScene
            self.scene = QGraphicsScene(self)
            self.view.setScene(self.scene)
    
            # Create a QAction to open an image
            open_action = QAction("Open Image", self)
            open_action.triggered.connect(self.openImage)
            self.menuBar().addAction(open_action)
    
            self.grouped_images = {}  # Dictionary to store images in groups
            self.group_names = []  # List to store group names
            self.current_group_index = 0  # Index of the currently selected group
            self.current_image_index = 0  # Index of the currently displayed image within the group
    
            text_item = QGraphicsTextItem("Alice")
    
            font = text_item.font()
            font.setPointSize(150)  # Adjust the font size as needed
            text_item.setFont(font)
    
            text_item.setDefaultTextColor(Qt.red)
    
            text_item.setPos(100, 100)
    
            self.scene.addItem(text_item)
    
            self.setShortcuts()
        
        def setShortcuts(self):
            QShortcut(QKeySequence(Qt.Key_F11), self, self.toggleFullScreen)
    
            QShortcut(QKeySequence(Qt.Key_Right), self, self.nextImage)
    
            QShortcut(QKeySequence(Qt.Key_Left), self, self.previousImage)
    
            QShortcut(QKeySequence(Qt.Key_Up), self, self.switchGroupUp)
    
            QShortcut(QKeySequence(Qt.Key_Down), self, self.switchGroupDown)
    
        def openImage(self):
            folder_dialog = QFileDialog.getExistingDirectory(self, "Open Directory")
        
            if folder_dialog:
                self.grouped_images, self.group_names = self.collectGroupedImages(folder_dialog)
                self.current_group_index = 0  # Reset the current group index
                self.current_image_index = 0  # Reset the current image index within the group
                
                if self.group_names:
                    self.displayImage()
    
        def collectGroupedImages(self, directory):
            grouped_images = {}
            group_names = []
            for root, _, files in os.walk(directory):
                # Determine the group name (folder name)
                group_name = os.path.basename(root)
                if group_name not in grouped_images:
                    grouped_images[group_name] = []
                    group_names.append(group_name)
                
                for filename in files:
                    if filename.lower().endswith(('.jpg', '.jpeg', '.png', '.gif', '.bmp', '.tiff', '.tif')):
                        image_path = os.path.join(root, filename)
                        grouped_images[group_name].append(image_path)
            return grouped_images, group_names
    
        def switchGroupUp(self):
            if self.group_names:
                self.current_group_index = (self.current_group_index - 1) % len(self.group_names)
                self.current_image_index = 0  # Reset the current image index within the new group
                self.displayImage()
    
        def switchGroupDown(self):
            if self.group_names:
                self.current_group_index = (self.current_group_index + 1) % len(self.group_names)
                self.current_image_index = 0  # Reset the current image index within the new group
                self.displayImage()
    
        def nextImage(self):
            if self.group_names:
                current_group_name = self.group_names[self.current_group_index]
                current_group = self.grouped_images.get(current_group_name, [])
                if current_group:
                    self.current_image_index = (self.current_image_index + 1) % len(current_group)
                    self.displayImage()
    
        def previousImage(self):
            if self.group_names:
                current_group_name = self.group_names[self.current_group_index]
                current_group = self.grouped_images.get(current_group_name, [])
                if current_group:
                    self.current_image_index = (self.current_image_index - 1) % len(current_group)
                    self.displayImage()
    
        def displayImage(self):
            #self.timer.start(self.new_delay * 1000)
            if self.group_names:
                current_group_name = self.group_names[self.current_group_index]
                current_group = self.grouped_images.get(current_group_name, [])
                if current_group:
                    image_path = current_group[self.current_image_index]
                    image = QImage(image_path)
                    pixmap = QPixmap(image)
                    pixmap_item = QGraphicsPixmapItem(pixmap)
    
                    self.scene.clear()
                    self.scene.addItem(pixmap_item)
    
                    self.scene.setSceneRect(0, 0, pixmap.width(), pixmap.height())
    
                    self.view.setScene(self.scene)
                    self.view.fitInView(self.scene.sceneRect(), Qt.KeepAspectRatio)
    
        def resizeEvent(self, event):
            self.view.fitInView(self.scene.sceneRect(), Qt.KeepAspectRatio)
    
        def toggleFullScreen(self):
            if self.isFullScreen():
                self.showNormal()
                self.menuBar().show()
            else:
                self.showFullScreen()
                self.menuBar().hide()
    
    def main():
        app = QApplication(sys.argv)
        viewer = ImageViewer()
        viewer.show()
        sys.exit(app.exec())
    
    if __name__ == '__main__':
        main()
    
    

    I want to apologize already, this code is an amalgamation of what I could get from Chat GPT, old forum posts and my limited understanding of the Qt documentation. So it's defintely terrible in a lot of places, but at least it kinda works.

    For this specific problem the important part is the DisplayImage function.

    Right now the Scene gets scaled to the size of the current pixmap being displayed, then the View is fitted to the Scene. It gives the intended effect of having the image always filling the entire window while keeping it's AspectRatio, but, since it's the Scene itself being scaled, if I try to add something else to that scene, for example a text, it will also appear scaled and streched.

    So I would need the image itself to fit the Scene's size, since the Scene's size is by default the size of the largest item inside of it, smaller images won't fill the entire window. I tried to scale the QPixmap, the QImage or the QGraphicsPixmapItem but couldn't make it work. The images are displayed pixelated and uncentered.

    So that's it, I tried to figure it out but I'm giving up... Hope somebody can give me a hand. Thank you

    JonBJ JoeCFDJ 2 Replies Last reply
    0
    • M Mattik

      Hello, so I am very new to coding but wanna learn as a hobby. What I'm trying to do as a first project is an image viewer in python using pyside6.

      After hours of banging my head against walls for the last few days I managed to figure out some stuff but I can't figure out how to correctly do one of the most important thing for an image viewer, make it so the images always fit the entirety of the window.

      Here's my code so far :

      import sys
      import os
      from PySide6.QtCore import Qt, QSize
      from PySide6.QtGui import QPixmap, QAction, QColor, QShortcut, QKeySequence, QImage
      from PySide6.QtWidgets import QApplication, QGraphicsScene, QGraphicsView, QMainWindow, QVBoxLayout, QWidget, QFileDialog, QGraphicsTextItem, QGraphicsPixmapItem
      
      class ImageViewer(QMainWindow):
          def __init__(self):
              super().__init__()
      
              self.initUI()
      
          def initUI(self):
              self.setWindowTitle("Image Viewer")
              self.setGeometry(100, 100, 800, 600)
              
              background_color = QColor(3, 5, 15)
      
              # Create a central widget and set it as the main window's central widget
              central_widget = QWidget(self)
              self.setCentralWidget(central_widget)
      
              # Create a QGraphicsView and set it as the central widget
              layout = QVBoxLayout(central_widget)
              layout.setContentsMargins(0, 0, 0, 0)
      
              #layout.setSpacing(0)
              self.view = QGraphicsView(self)
              self.view.setBackgroundBrush(background_color)
              layout.addWidget(self.view)
      
              # Create a QGraphicsScene
              self.scene = QGraphicsScene(self)
              self.view.setScene(self.scene)
      
              # Create a QAction to open an image
              open_action = QAction("Open Image", self)
              open_action.triggered.connect(self.openImage)
              self.menuBar().addAction(open_action)
      
              self.grouped_images = {}  # Dictionary to store images in groups
              self.group_names = []  # List to store group names
              self.current_group_index = 0  # Index of the currently selected group
              self.current_image_index = 0  # Index of the currently displayed image within the group
      
              text_item = QGraphicsTextItem("Alice")
      
              font = text_item.font()
              font.setPointSize(150)  # Adjust the font size as needed
              text_item.setFont(font)
      
              text_item.setDefaultTextColor(Qt.red)
      
              text_item.setPos(100, 100)
      
              self.scene.addItem(text_item)
      
              self.setShortcuts()
          
          def setShortcuts(self):
              QShortcut(QKeySequence(Qt.Key_F11), self, self.toggleFullScreen)
      
              QShortcut(QKeySequence(Qt.Key_Right), self, self.nextImage)
      
              QShortcut(QKeySequence(Qt.Key_Left), self, self.previousImage)
      
              QShortcut(QKeySequence(Qt.Key_Up), self, self.switchGroupUp)
      
              QShortcut(QKeySequence(Qt.Key_Down), self, self.switchGroupDown)
      
          def openImage(self):
              folder_dialog = QFileDialog.getExistingDirectory(self, "Open Directory")
          
              if folder_dialog:
                  self.grouped_images, self.group_names = self.collectGroupedImages(folder_dialog)
                  self.current_group_index = 0  # Reset the current group index
                  self.current_image_index = 0  # Reset the current image index within the group
                  
                  if self.group_names:
                      self.displayImage()
      
          def collectGroupedImages(self, directory):
              grouped_images = {}
              group_names = []
              for root, _, files in os.walk(directory):
                  # Determine the group name (folder name)
                  group_name = os.path.basename(root)
                  if group_name not in grouped_images:
                      grouped_images[group_name] = []
                      group_names.append(group_name)
                  
                  for filename in files:
                      if filename.lower().endswith(('.jpg', '.jpeg', '.png', '.gif', '.bmp', '.tiff', '.tif')):
                          image_path = os.path.join(root, filename)
                          grouped_images[group_name].append(image_path)
              return grouped_images, group_names
      
          def switchGroupUp(self):
              if self.group_names:
                  self.current_group_index = (self.current_group_index - 1) % len(self.group_names)
                  self.current_image_index = 0  # Reset the current image index within the new group
                  self.displayImage()
      
          def switchGroupDown(self):
              if self.group_names:
                  self.current_group_index = (self.current_group_index + 1) % len(self.group_names)
                  self.current_image_index = 0  # Reset the current image index within the new group
                  self.displayImage()
      
          def nextImage(self):
              if self.group_names:
                  current_group_name = self.group_names[self.current_group_index]
                  current_group = self.grouped_images.get(current_group_name, [])
                  if current_group:
                      self.current_image_index = (self.current_image_index + 1) % len(current_group)
                      self.displayImage()
      
          def previousImage(self):
              if self.group_names:
                  current_group_name = self.group_names[self.current_group_index]
                  current_group = self.grouped_images.get(current_group_name, [])
                  if current_group:
                      self.current_image_index = (self.current_image_index - 1) % len(current_group)
                      self.displayImage()
      
          def displayImage(self):
              #self.timer.start(self.new_delay * 1000)
              if self.group_names:
                  current_group_name = self.group_names[self.current_group_index]
                  current_group = self.grouped_images.get(current_group_name, [])
                  if current_group:
                      image_path = current_group[self.current_image_index]
                      image = QImage(image_path)
                      pixmap = QPixmap(image)
                      pixmap_item = QGraphicsPixmapItem(pixmap)
      
                      self.scene.clear()
                      self.scene.addItem(pixmap_item)
      
                      self.scene.setSceneRect(0, 0, pixmap.width(), pixmap.height())
      
                      self.view.setScene(self.scene)
                      self.view.fitInView(self.scene.sceneRect(), Qt.KeepAspectRatio)
      
          def resizeEvent(self, event):
              self.view.fitInView(self.scene.sceneRect(), Qt.KeepAspectRatio)
      
          def toggleFullScreen(self):
              if self.isFullScreen():
                  self.showNormal()
                  self.menuBar().show()
              else:
                  self.showFullScreen()
                  self.menuBar().hide()
      
      def main():
          app = QApplication(sys.argv)
          viewer = ImageViewer()
          viewer.show()
          sys.exit(app.exec())
      
      if __name__ == '__main__':
          main()
      
      

      I want to apologize already, this code is an amalgamation of what I could get from Chat GPT, old forum posts and my limited understanding of the Qt documentation. So it's defintely terrible in a lot of places, but at least it kinda works.

      For this specific problem the important part is the DisplayImage function.

      Right now the Scene gets scaled to the size of the current pixmap being displayed, then the View is fitted to the Scene. It gives the intended effect of having the image always filling the entire window while keeping it's AspectRatio, but, since it's the Scene itself being scaled, if I try to add something else to that scene, for example a text, it will also appear scaled and streched.

      So I would need the image itself to fit the Scene's size, since the Scene's size is by default the size of the largest item inside of it, smaller images won't fill the entire window. I tried to scale the QPixmap, the QImage or the QGraphicsPixmapItem but couldn't make it work. The images are displayed pixelated and uncentered.

      So that's it, I tried to figure it out but I'm giving up... Hope somebody can give me a hand. Thank you

      JonBJ Offline
      JonBJ Offline
      JonB
      wrote on last edited by JonB
      #2

      @Mattik
      You do not want to scale the scene, since as you say that will affect other graphics items. If you are trying to use a QGraphicsPixmapItem you want only its image scaled. So see e.g. Resize QGraphicsPixmapItem, where you first scale a QPixmap and then use that for the item. Also maybe see QPixmap: How to increase the size of the picture in addPixmap?.

      There may be some pixelation, I don't know, that is in the nature of scaling.

      1 Reply Last reply
      2
      • M Mattik

        Hello, so I am very new to coding but wanna learn as a hobby. What I'm trying to do as a first project is an image viewer in python using pyside6.

        After hours of banging my head against walls for the last few days I managed to figure out some stuff but I can't figure out how to correctly do one of the most important thing for an image viewer, make it so the images always fit the entirety of the window.

        Here's my code so far :

        import sys
        import os
        from PySide6.QtCore import Qt, QSize
        from PySide6.QtGui import QPixmap, QAction, QColor, QShortcut, QKeySequence, QImage
        from PySide6.QtWidgets import QApplication, QGraphicsScene, QGraphicsView, QMainWindow, QVBoxLayout, QWidget, QFileDialog, QGraphicsTextItem, QGraphicsPixmapItem
        
        class ImageViewer(QMainWindow):
            def __init__(self):
                super().__init__()
        
                self.initUI()
        
            def initUI(self):
                self.setWindowTitle("Image Viewer")
                self.setGeometry(100, 100, 800, 600)
                
                background_color = QColor(3, 5, 15)
        
                # Create a central widget and set it as the main window's central widget
                central_widget = QWidget(self)
                self.setCentralWidget(central_widget)
        
                # Create a QGraphicsView and set it as the central widget
                layout = QVBoxLayout(central_widget)
                layout.setContentsMargins(0, 0, 0, 0)
        
                #layout.setSpacing(0)
                self.view = QGraphicsView(self)
                self.view.setBackgroundBrush(background_color)
                layout.addWidget(self.view)
        
                # Create a QGraphicsScene
                self.scene = QGraphicsScene(self)
                self.view.setScene(self.scene)
        
                # Create a QAction to open an image
                open_action = QAction("Open Image", self)
                open_action.triggered.connect(self.openImage)
                self.menuBar().addAction(open_action)
        
                self.grouped_images = {}  # Dictionary to store images in groups
                self.group_names = []  # List to store group names
                self.current_group_index = 0  # Index of the currently selected group
                self.current_image_index = 0  # Index of the currently displayed image within the group
        
                text_item = QGraphicsTextItem("Alice")
        
                font = text_item.font()
                font.setPointSize(150)  # Adjust the font size as needed
                text_item.setFont(font)
        
                text_item.setDefaultTextColor(Qt.red)
        
                text_item.setPos(100, 100)
        
                self.scene.addItem(text_item)
        
                self.setShortcuts()
            
            def setShortcuts(self):
                QShortcut(QKeySequence(Qt.Key_F11), self, self.toggleFullScreen)
        
                QShortcut(QKeySequence(Qt.Key_Right), self, self.nextImage)
        
                QShortcut(QKeySequence(Qt.Key_Left), self, self.previousImage)
        
                QShortcut(QKeySequence(Qt.Key_Up), self, self.switchGroupUp)
        
                QShortcut(QKeySequence(Qt.Key_Down), self, self.switchGroupDown)
        
            def openImage(self):
                folder_dialog = QFileDialog.getExistingDirectory(self, "Open Directory")
            
                if folder_dialog:
                    self.grouped_images, self.group_names = self.collectGroupedImages(folder_dialog)
                    self.current_group_index = 0  # Reset the current group index
                    self.current_image_index = 0  # Reset the current image index within the group
                    
                    if self.group_names:
                        self.displayImage()
        
            def collectGroupedImages(self, directory):
                grouped_images = {}
                group_names = []
                for root, _, files in os.walk(directory):
                    # Determine the group name (folder name)
                    group_name = os.path.basename(root)
                    if group_name not in grouped_images:
                        grouped_images[group_name] = []
                        group_names.append(group_name)
                    
                    for filename in files:
                        if filename.lower().endswith(('.jpg', '.jpeg', '.png', '.gif', '.bmp', '.tiff', '.tif')):
                            image_path = os.path.join(root, filename)
                            grouped_images[group_name].append(image_path)
                return grouped_images, group_names
        
            def switchGroupUp(self):
                if self.group_names:
                    self.current_group_index = (self.current_group_index - 1) % len(self.group_names)
                    self.current_image_index = 0  # Reset the current image index within the new group
                    self.displayImage()
        
            def switchGroupDown(self):
                if self.group_names:
                    self.current_group_index = (self.current_group_index + 1) % len(self.group_names)
                    self.current_image_index = 0  # Reset the current image index within the new group
                    self.displayImage()
        
            def nextImage(self):
                if self.group_names:
                    current_group_name = self.group_names[self.current_group_index]
                    current_group = self.grouped_images.get(current_group_name, [])
                    if current_group:
                        self.current_image_index = (self.current_image_index + 1) % len(current_group)
                        self.displayImage()
        
            def previousImage(self):
                if self.group_names:
                    current_group_name = self.group_names[self.current_group_index]
                    current_group = self.grouped_images.get(current_group_name, [])
                    if current_group:
                        self.current_image_index = (self.current_image_index - 1) % len(current_group)
                        self.displayImage()
        
            def displayImage(self):
                #self.timer.start(self.new_delay * 1000)
                if self.group_names:
                    current_group_name = self.group_names[self.current_group_index]
                    current_group = self.grouped_images.get(current_group_name, [])
                    if current_group:
                        image_path = current_group[self.current_image_index]
                        image = QImage(image_path)
                        pixmap = QPixmap(image)
                        pixmap_item = QGraphicsPixmapItem(pixmap)
        
                        self.scene.clear()
                        self.scene.addItem(pixmap_item)
        
                        self.scene.setSceneRect(0, 0, pixmap.width(), pixmap.height())
        
                        self.view.setScene(self.scene)
                        self.view.fitInView(self.scene.sceneRect(), Qt.KeepAspectRatio)
        
            def resizeEvent(self, event):
                self.view.fitInView(self.scene.sceneRect(), Qt.KeepAspectRatio)
        
            def toggleFullScreen(self):
                if self.isFullScreen():
                    self.showNormal()
                    self.menuBar().show()
                else:
                    self.showFullScreen()
                    self.menuBar().hide()
        
        def main():
            app = QApplication(sys.argv)
            viewer = ImageViewer()
            viewer.show()
            sys.exit(app.exec())
        
        if __name__ == '__main__':
            main()
        
        

        I want to apologize already, this code is an amalgamation of what I could get from Chat GPT, old forum posts and my limited understanding of the Qt documentation. So it's defintely terrible in a lot of places, but at least it kinda works.

        For this specific problem the important part is the DisplayImage function.

        Right now the Scene gets scaled to the size of the current pixmap being displayed, then the View is fitted to the Scene. It gives the intended effect of having the image always filling the entire window while keeping it's AspectRatio, but, since it's the Scene itself being scaled, if I try to add something else to that scene, for example a text, it will also appear scaled and streched.

        So I would need the image itself to fit the Scene's size, since the Scene's size is by default the size of the largest item inside of it, smaller images won't fill the entire window. I tried to scale the QPixmap, the QImage or the QGraphicsPixmapItem but couldn't make it work. The images are displayed pixelated and uncentered.

        So that's it, I tried to figure it out but I'm giving up... Hope somebody can give me a hand. Thank you

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

        @Mattik if you have svg images, you use QGraphicsSvgItem
        because QGraphicsPixmapItem can not preserve the resolution of the images.

        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