فهرست منبع

Add support for zooming and make fit optional

Refactor image resizing code in the process.
Michael Pitidis 13 سال پیش
والد
کامیت
e55ca64af6
2فایلهای تغییر یافته به همراه70 افزوده شده و 19 حذف شده
  1. 56 19
      labelme.py
  2. 14 0
      zoomwidget.py

+ 56 - 19
labelme.py

@@ -12,6 +12,7 @@ from PyQt4.QtGui import *
 from PyQt4.QtCore import *
 
 from canvas import Canvas
+from zoomwidget import ZoomWidget
 
 __appname__ = 'labelme'
 
@@ -74,14 +75,15 @@ class MainWindow(QMainWindow, WindowMixin):
         self.dock = QDockWidget(u'Label', parent=self)
         self.dock.setObjectName(u'Label')
         self.dock.setWidget(self.label)
+        self.zoom_widget = ZoomWidget()
         #self.dock.setFeatures(QDockWidget.DockWidgetMovable|QDockWidget.DockWidgetFloatable)
 
-        self.imageWidget = Canvas()
-        self.imageWidget.setAlignment(Qt.AlignCenter)
-        self.imageWidget.setContextMenuPolicy(Qt.ActionsContextMenu)
+        self.canvas = Canvas()
+        self.canvas.setAlignment(Qt.AlignCenter)
+        self.canvas.setContextMenuPolicy(Qt.ActionsContextMenu)
 
         self.addDockWidget(Qt.BottomDockWidgetArea, self.dock)
-        self.setCentralWidget(self.imageWidget)
+        self.setCentralWidget(self.canvas)
 
         # Actions
         quit = action(self, '&Quit', self.close, 'Ctrl+Q', u'Exit application')
@@ -90,8 +92,22 @@ class MainWindow(QMainWindow, WindowMixin):
         labl = self.dock.toggleViewAction()
         labl.setShortcut('Ctrl+L')
 
-        add_actions(self.menu('&File'), (open, color, None, labl, None, quit))
-        add_actions(self.toolbar('Tools'), (open, color, None, labl, None, quit))
+        zoom = QWidgetAction(self)
+        zoom.setDefaultWidget(self.zoom_widget)
+        fit_window = action(self, '&Fit Window', self.setFitWindow,
+                'Ctrl+F', u'Fit image to window', checkable=True)
+
+        self.menus = struct(
+                file=self.menu('&File'),
+                edit=self.menu('&Image'),
+                view=self.menu('&View'))
+        add_actions(self.menus.file, (open, quit))
+        add_actions(self.menus.edit, (color, fit_window))
+        add_actions(self.menus.view, (labl,))
+
+        self.tools = self.toolbar('Tools')
+        add_actions(self.tools, (open, color, None, zoom, fit_window, None, quit))
+
 
         self.statusBar().showMessage('%s started.' % __appname__)
         self.statusBar().show()
@@ -101,6 +117,8 @@ class MainWindow(QMainWindow, WindowMixin):
         self.filename = filename
         self.recent_files = []
         self.color = None
+        self.zoom_level = 100
+        self.fit_window = False
 
         # TODO: Could be completely declarative.
         # Restore application settings.
@@ -129,6 +147,16 @@ class MainWindow(QMainWindow, WindowMixin):
         # Since loading the file may take some time, make sure it runs in the background.
         self.queueEvent(partial(self.loadFile, self.filename))
 
+        # Callbacks:
+        self.zoom_widget.valueChanged.connect(self.showImage)
+
+
+    ## Callback functions:
+    def setFitWindow(self, value=True):
+        self.zoom_widget.setEnabled(not value)
+        self.fit_window = value
+        self.showImage()
+
     def queueEvent(self, function):
         QTimer.singleShot(0, function)
 
@@ -149,22 +177,27 @@ class MainWindow(QMainWindow, WindowMixin):
                 self.showImage()
             self.statusBar().showMessage(message)
 
-    def showImage(self):
-        if self.image.isNull():
-            return
-        self.imageWidget.setPixmap(self.scaled(QPixmap.fromImage(self.image)))
-        self.imageWidget.show()
-
     def resizeEvent(self, event):
-        if self.imageWidget and self.imageWidget.pixmap():
-            self.imageWidget.setPixmap(self.scaled(self.imageWidget.pixmap()))
+        if self.fit_window and self.canvas and not self.image.isNull():
+            self.showImage()
         super(MainWindow, self).resizeEvent(event)
 
-    def scaled(self, pixmap):
-        width = self.centralWidget().width()
-        height = self.centralWidget().height()
-        return pixmap.scaled(width, height,
-          Qt.KeepAspectRatio, Qt.SmoothTransformation)
+    def showImage(self):
+        if self.image.isNull():
+            return
+        size = self.imageSize()
+        self.canvas.setPixmap(QPixmap.fromImage(self.image.scaled(
+                size, Qt.KeepAspectRatio, Qt.SmoothTransformation)))
+        self.canvas.show()
+
+    def imageSize(self):
+        """Calculate the size of the image based on current settings."""
+        if self.fit_window:
+            width, height = self.canvas.width(), self.canvas.height()
+        else: # Follow zoom:
+            s = self.zoom_widget.value() / 100.0
+            width, height = s * self.image.width(), s * self.image.height()
+        return QSize(width, height)
 
     def closeEvent(self, event):
         # TODO: Make sure changes are saved.
@@ -227,6 +260,10 @@ class Settings(object):
         return value
 
 
+class struct(object):
+    def __init__(self, **kwargs):
+        self.__dict__.update(kwargs)
+
 
 def main(argv):
     """Standard boilerplate Qt application code."""

+ 14 - 0
zoomwidget.py

@@ -0,0 +1,14 @@
+
+from PyQt4.QtGui import *
+from PyQt4.QtCore import *
+
+class ZoomWidget(QSpinBox):
+    def __init__(self, value=100):
+        super(ZoomWidget, self).__init__()
+        self.setButtonSymbols(QAbstractSpinBox.PlusMinus)
+        self.setRange(1, 500)
+        self.setSuffix(' %')
+        self.setValue(value)
+        self.setToolTip(u'Image zoom')
+        self.setStatusTip(self.toolTip())
+