source: orange/Orange/OrangeWidgets/Data/OWImageViewer.py @ 11748:467f952c108d

Revision 11748:467f952c108d, 16.4 KB checked in by blaz <blaz.zupan@…>, 6 months ago (diff)

Changes in headers, widget descriptions text.

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