source: orange/orange/OrangeWidgets/Data/OWImageViewer.py @ 9509:c9d61a6e0172

Revision 9509:c9d61a6e0172, 16.3 KB checked in by mitar, 2 years ago (diff)

New icons for widgets.

Line 
1"""<name>Image Viewer</name>
2<description>View images embeded in example table</description>
3<contact>Ales Erjavec (ales.erjavec(@at@)fri.uni-lj.si)</contact>
4<priority>4050</priority>
5<icon>icons/ImageViewer.png</icon>
6"""
7
8from OWWidget import *
9
10import OWGUI
11
12
13#def setupShadow(widget):
14#    if qVersion() >= "4.6":
15#        ge = QGraphicsDropShadowEffect(widget)
16#        ge.setBlurRadius(4)
17#        ge.setOffset(QPointF(2, 2))
18#        ge.setColor(QColor(0, 0, 0, 100))
19#        widget.setGraphicsEffect(ge)
20       
21
22class GraphicsPixmapWidget(QGraphicsWidget):
23    def __init__(self, pixmap, parent=None, scene=None):
24        QGraphicsWidget.__init__(self, parent)
25        self.setCacheMode(QGraphicsItem.ItemCoordinateCache)
26        self.pixmap = pixmap
27        self.pixmapSize = QSizeF(100, 100)
28        self.setSizePolicy(QSizePolicy.Fixed, QSizePolicy.Fixed)
29        if scene is not None:
30            scene.addItem(self)
31       
32       
33    def sizeHint(self, which, contraint=QSizeF()):
34        return self.pixmapSize
35   
36   
37    def paint(self, painter, option, widget=0):
38        painter.save()
39        painter.setPen(QPen(QColor(0, 0, 0, 50), 3))
40        painter.drawRoundedRect(self.boundingRect(), 2, 2)
41        painter.setRenderHint(QPainter.SmoothPixmapTransform)
42        pixmapRect = QRectF(QPointF(0,0), self.pixmapSize)
43        painter.drawPixmap(pixmapRect, self.pixmap, QRectF(QPointF(0, 0), QSizeF(self.pixmap.size())))
44        painter.restore()
45       
46       
47    def setPixmapSize(self, size):
48        self.pixmapSize = size
49        self.updateGeometry()
50         
51           
52class GraphicsTextWidget(QGraphicsWidget):
53    def __init__(self, text, parent=None):
54        QGraphicsWidget.__init__(self, parent)
55        self.labelItem = QGraphicsTextItem(self)
56        self.setHtml(text)
57       
58        self.connect(self.labelItem.document().documentLayout(),
59                     SIGNAL("documentSizeChanged(QSizeF)"), self.onLayoutChanged)
60       
61       
62    def onLayoutChanged(self, *args):
63        self.updateGeometry()
64       
65       
66    def sizeHint(self, which, constraint=QSizeF()):
67        if which == Qt.MinimumSize:
68            return self.labelItem.boundingRect().size()
69        else:
70            return self.labelItem.boundingRect().size()
71       
72       
73    def setTextWidth(self, width):
74        self.labelItem.setTextWidth(width)
75       
76       
77    def setHtml(self, text):
78        self.labelItem.setHtml(text)
79       
80       
81#    def paint(self, painter, *args):
82#        painter.drawRect(self.boundingRect())
83       
84           
85class GraphicsThumbnailWidget(QGraphicsWidget):
86    def __init__(self, pixmap, title="Image", parent=None, scene=None):
87        QGraphicsWidget.__init__(self, parent)
88        #self.setCacheMode(QGraphicsItem.ItemCoordinateCache)
89        layout = QGraphicsLinearLayout(Qt.Vertical, self)
90        layout.setSpacing(2)
91        layout.setContentsMargins(5, 5, 5, 5)
92       
93        self.pixmapWidget = GraphicsPixmapWidget(pixmap, self)
94        self.labelWidget = GraphicsTextWidget(title, self)
95        layout.addItem(self.pixmapWidget)
96        layout.addItem(self.labelWidget)
97        layout.setAlignment(self.pixmapWidget, Qt.AlignCenter)
98        layout.setAlignment(self.labelWidget, Qt.AlignCenter)
99        self.setLayout(layout)
100       
101        self.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
102       
103        self.setFlag(QGraphicsItem.ItemIsSelectable, True)
104        self.setTitle(title)
105        self.setTitleWidth(150)
106        self.setThumbnailSize(QSizeF(150, 150))
107       
108       
109    def setTitle(self, text):
110        self.labelWidget.setHtml('<center>' + text + '</center>')
111        self.layout().invalidate()
112       
113       
114    def setThumbnailSize(self, size):
115        self.pixmapWidget.setPixmapSize(size)
116        self.labelWidget.setTextWidth(max(100, size.width()))
117       
118       
119    def setTitleWidth(self, width):
120        self.labelWidget.setTextWidth(width)
121        self.layout().invalidate()
122       
123       
124    def setGeometry(self, rect):
125        QGraphicsWidget.setGeometry(self, rect)
126
127
128    def paint(self, painter, option, widget=0):
129        contents = self.contentsRect()
130        if self.isSelected():
131            painter.save()
132            pen = painter.pen()
133            painter.setPen(QPen(QColor(125, 162, 206, 192)))
134            painter.setBrush(QBrush(QColor(217, 232, 252, 192)))
135            painter.drawRoundedRect(QRectF(contents.topLeft(), self.geometry().size()), 3, 3)
136            painter.restore()
137           
138
139class ThumbnailWidget(QGraphicsWidget):
140    def __init__(self, parent=None):
141        QGraphicsWidget.__init__(self, parent)
142        self.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum)
143       
144       
145class GraphicsScene(QGraphicsScene):
146    def __init__(self, *args):
147        QGraphicsScene.__init__(self, *args)
148        self.selectionRect = None
149       
150       
151    def mousePressEvent(self, event):
152        QGraphicsScene.mousePressEvent(self, event)
153       
154       
155    def mouseMoveEvent(self, event):
156        if event.buttons() & Qt.LeftButton:
157            screenPos = event.screenPos()
158            buttonDown = event.buttonDownScreenPos(Qt.LeftButton)
159            if (screenPos - buttonDown).manhattanLength() > 2.0:
160                self.updateSelectionRect(event)
161        QGraphicsScene.mouseMoveEvent(self, event)
162       
163       
164    def mouseReleaseEvent(self, event):
165        if event.button() == Qt.LeftButton:
166            if self.selectionRect:
167                self.removeItem(self.selectionRect)
168                self.selectionRect = None
169        QGraphicsScene.mouseReleaseEvent(self, event)
170       
171       
172    def updateSelectionRect(self, event):
173        pos = event.scenePos()
174        buttonDownPos = event.buttonDownScenePos(Qt.LeftButton)
175        rect = QRectF(pos, buttonDownPos).normalized()
176        rect = rect.intersected(self.sceneRect())
177        if not self.selectionRect:
178            self.selectionRect = QGraphicsRectItem()
179            self.selectionRect.setBrush(QColor(10, 10, 10, 20))
180            self.selectionRect.setPen(QPen(QColor(200, 200, 200, 200)))
181            self.addItem(self.selectionRect)
182        self.selectionRect.setRect(rect)
183        if event.modifiers() & Qt.ControlModifier or event.modifiers() & Qt.ShiftModifier: 
184            path = self.selectionArea()
185        else:
186            path = QPainterPath()
187        path.addRect(rect)
188        self.setSelectionArea(path)
189        self.emit(SIGNAL("selectionRectPointChanged(QPointF)"), pos)
190
191
192class OWImageViewer(OWWidget):
193    contextHandlers = {"": DomainContextHandler("", ["imageAttr", "titleAttr"])}
194    settingsList = ["zoom"]
195    def __init__(self, parent=None, signalManager=None, name="Image viewer"):
196        OWWidget.__init__(self, parent, signalManager, name, wantGraph=True)
197       
198        self.inputs = [("Example Table", ExampleTable, self.setData)]
199        self.outputs = [("Example Table", ExampleTable)]
200       
201        self.imageAttr = 0
202        self.titleAttr = 0
203        self.zoom = 25
204        self.autoCommit = False
205        self.selectionChangedFlag = False
206       
207        # ###
208        # GUI
209        # ###
210       
211        self.loadSettings()
212       
213        self.imageAttrCB = OWGUI.comboBox(self.controlArea, self, "imageAttr",
214                                          box="Image Filename Attribute",
215                                          tooltip="Attribute with image filenames",
216                                          callback=self.setupScene,
217                                          addSpace=True
218                                          )
219       
220        self.titleAttrCB = OWGUI.comboBox(self.controlArea, self, "titleAttr",
221                                          box="Title Attribute",
222                                          tooltip="Attribute with image title",
223                                          callback=self.updateTitles,
224                                          addSpace=True
225                                          )
226       
227        OWGUI.hSlider(self.controlArea, self, "zoom",
228                      box="Zoom", minValue=1, maxValue=100, step=1,
229                      callback=self.updateZoom,
230                      createLabel=False
231                      )
232       
233        OWGUI.separator(self.controlArea)
234       
235        box = OWGUI.widgetBox(self.controlArea, "Selection")
236        b = OWGUI.button(box, self, "Commit", callback=self.commit)
237        cb = OWGUI.checkBox(box, self, "autoCommit", "Commit on any change",
238                            tooltip="Send selections on any change",
239                            callback=self.commitIf
240                            )
241        OWGUI.setStopper(self, b, cb, "selectionChangedFlag", callback=self.commit)
242       
243        OWGUI.rubber(self.controlArea)
244       
245        self.scene = GraphicsScene()
246        self.sceneView = QGraphicsView(self.scene, self)
247        self.sceneView.setAlignment(Qt.AlignTop | Qt.AlignLeft)
248        self.sceneView.setRenderHint(QPainter.Antialiasing, True)
249        self.sceneView.setRenderHint(QPainter.TextAntialiasing, True)
250        self.sceneView.setFocusPolicy(Qt.WheelFocus)
251        self.mainArea.layout().addWidget(self.sceneView)
252       
253        self.connect(self.scene, SIGNAL("selectionChanged()"), self.onSelectionChanged)
254        self.connect(self.scene, SIGNAL("selectionRectPointChanged(QPointF)"), self.onSelectionRectPointChanged, Qt.QueuedConnection)
255        self.connect(self.graphButton, SIGNAL("clicked()"), self.saveScene)
256        self.resize(800, 600)
257       
258        self.sceneLayout = None
259        self.selectedExamples = []
260        self.hasTypeImageHint = False
261       
262        self.updateZoom()
263       
264       
265    def setData(self, data):
266        self.data = data
267        self.closeContext("")
268        self.information(0)
269        self.error(0)
270        if data is not None:
271            self.imageAttrCB.clear()
272            self.titleAttrCB.clear()
273            self.allAttrs = data.domain.variables + data.domain.getmetas().values()
274            self.stringAttrs = [attr for attr in self.allAttrs if attr.varType == orange.VarTypes.String]
275            self.hasTypeImageHint = any("type" in attr.attributes for attr in self.stringAttrs)
276            self.stringAttrs = sorted(self.stringAttrs, key=lambda  attr: 0 if "type" in attr.attributes else 1)
277            icons = OWGUI.getAttributeIcons()
278            for attr in self.stringAttrs:
279                self.imageAttrCB.addItem(icons[attr.varType], attr.name)
280            for attr in self.allAttrs:
281                self.titleAttrCB.addItem(icons[attr.varType], attr.name)
282           
283            self.openContext("", data)
284            self.imageAttr = max(min(self.imageAttr, len(self.stringAttrs) - 1), 0)
285            self.titleAttr = max(min(self.titleAttr, len(self.allAttrs) - 1), 0)
286           
287            if self.stringAttrs:
288                self.setupScene()
289            else:
290                self.clearScene()
291        else:
292            self.imageAttrCB.clear()
293            self.titleAttrCB.clear()
294            self.clearScene()
295           
296           
297    def setupScene(self):
298        self.clearScene()
299        self.scene.blockSignals(True)
300        thumbnailSize = self.zoom / 25.0 * 150.0
301        self.information(0)
302        self.error(0)
303        if self.data:
304            attr = self.stringAttrs[self.imageAttr]
305            titleAttr = self.allAttrs[self.titleAttr]
306            examples = [ex for ex in self.data if not ex[attr].isSpecial()]
307            widget = ThumbnailWidget()
308            layout = QGraphicsGridLayout()
309            layout.setSpacing(10)
310            widget.setLayout(layout)
311            widget.setPos(10, 10)
312            self.scene.addItem(widget)
313            fileExistsCount = 0
314            for i, ex in enumerate(examples):
315                filename = self.filenameFromValue(ex[attr])
316                if os.path.exists(filename):
317                    fileExistsCount += 1
318                title = str(ex[titleAttr])
319                pixmap = self.pixmapFromFile(filename)
320                thumbnail = GraphicsThumbnailWidget(pixmap, title=title, parent=widget)
321                thumbnail.setToolTip(filename)
322                thumbnail.setThumbnailSize(QSizeF(thumbnailSize, thumbnailSize))
323                thumbnail.example = ex
324                layout.addItem(thumbnail, i/5, i%5)
325            widget.show()
326            layout.invalidate()
327            self.sceneLayout = layout
328            if fileExistsCount == 0 and not "type" in attr.attributes:
329                self.error(0, "No images found!\nMake sure the '%s' attribute is tagged with 'type=image'" % attr.name) 
330            elif fileExistsCount < len(examples):
331                self.information(0, "Only %i out of %i images found." % (fileExistsCount, len(examples)))
332           
333               
334               
335        self.scene.blockSignals(False)
336       
337        qApp.processEvents()
338        self.scene.setSceneRect(self.scene.itemsBoundingRect())
339           
340    def filenameFromValue(self, value):
341        variable = value.variable
342        if isinstance(variable, orange.StringVariable):
343            origin = variable.attributes.get("origin", "")
344            name = str(value)
345            return os.path.join(origin, name)
346        elif isinstance(variable, URIVariable):
347            return str(value)
348           
349    def pixmapFromFile(self, filename):
350        pixmap = QPixmap(filename)
351        if pixmap.isNull():
352            try:
353                import Image, ImageQt
354                img = Image.open(filename)
355#                print img.format, img.mode, img.size
356#                data = img.tostring()
357#                pixmap = QPixmap.loadFromData(data)
358                pixmap = QPixmap.fromImage(ImageQt.ImageQt(img))
359            except Exception, ex:
360                print ex
361        return pixmap
362   
363    def clearScene(self):
364        self.scene.clear()
365        self.sceneLayout = None
366        qApp.processEvents()
367       
368       
369    def thumbnailItems(self):
370        for item in self.scene.items():
371            if isinstance(item, GraphicsThumbnailWidget):
372                yield item
373               
374    def updateZoom(self):
375        self.scene.blockSignals(True)
376        scale = self.zoom / 25.0 
377        for item in self.thumbnailItems():
378            item.setThumbnailSize(QSizeF(scale * 150, scale * 150))
379           
380        if self.sceneLayout:
381            self.sceneLayout.activate()
382        qApp.processEvents()
383        self.scene.blockSignals(False)
384       
385        self.scene.setSceneRect(self.scene.itemsBoundingRect())
386       
387       
388    def updateTitles(self):
389        titleAttr = self.allAttrs[self.titleAttr]
390        for item in self.scene.items():
391            if isinstance(item, GraphicsThumbnailWidget):
392                item.setTitle(str(item.example[titleAttr]))
393               
394        qApp.processEvents()
395        self.scene.setSceneRect(self.scene.itemsBoundingRect())
396       
397           
398    def onSelectionChanged(self):
399        try:
400            items = self.scene.selectedItems()
401            items = [item for item in items if isinstance(item, GraphicsThumbnailWidget)]
402            self.selectedExamples = [item.example for item in items]
403            self.commitIf()
404        except RuntimeError, err:
405            pass
406       
407    def onSelectionRectPointChanged(self, point):
408        self.sceneView.ensureVisible(QRectF(point , QSizeF(1, 1)), 5, 5)
409       
410    def commitIf(self):
411        if self.autoCommit:
412            self.commit()
413        else:
414            self.selectionChangedFlag = True
415           
416    def commit(self):
417        if self.data:
418            if self.selectedExamples:
419                selected = orange.ExampleTable(self.data.domain, self.selectedExamples)
420            else:
421                selected = None
422            self.send("Example Table", selected)
423        else:
424            self.send("Example Table", None)
425        self.selectionChangedFlag = False
426           
427    def saveScene(self):
428        from OWDlgs import OWChooseImageSizeDlg
429        sizeDlg = OWChooseImageSizeDlg(self.scene, parent=self)
430        sizeDlg.exec_()
431       
432       
433if __name__ == "__main__":
434    app = QApplication([])
435    w = OWImageViewer()
436    w.show()
437#    data = orange.ExampleTable(os.path.expanduser("~/Desktop/images.tab"))
438#    os.chdir(os.path.expanduser("~/Desktop/"))
439    data = orange.ExampleTable(os.path.expanduser("~/Downloads/pex11_orng_sample/pex11_sample.tab"))
440    os.chdir(os.path.expanduser("~/Downloads/pex11_orng_sample/"))
441    w.setData(data)
442    app.exec_()
443    w.saveSettings()
444     
445       
Note: See TracBrowser for help on using the repository browser.