Created
July 28, 2013 15:43
-
-
Save waspinator/6099012 to your computer and use it in GitHub Desktop.
dataset_tool
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
dataset_tool |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="UTF-8"?> | |
<module type="PYTHON_MODULE" version="4"> | |
<component name="NewModuleRootManager"> | |
<content url="file://$MODULE_DIR$" /> | |
<orderEntry type="jdk" jdkName="Python 2.7.2 (/System/Library/Frameworks/Python.framework/Versions/2.7/bin/python)" jdkType="Python SDK" /> | |
<orderEntry type="sourceFolder" forTests="false" /> | |
</component> | |
</module> | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="UTF-8"?> | |
<project version="4"> | |
<component name="Encoding" useUTFGuessing="true" native2AsciiForPropertiesFiles="false" /> | |
</project> | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="UTF-8"?> | |
<project version="4"> | |
<component name="ProjectRootManager" version="2" project-jdk-name="Python 2.7.2 (/System/Library/Frameworks/Python.framework/Versions/2.7/bin/python)" project-jdk-type="Python SDK" /> | |
</project> | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="UTF-8"?> | |
<project version="4"> | |
<component name="ProjectModuleManager"> | |
<modules> | |
<module fileurl="file://$PROJECT_DIR$/.idea/dataset_tool.iml" filepath="$PROJECT_DIR$/.idea/dataset_tool.iml" /> | |
</modules> | |
</component> | |
</project> | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="UTF-8"?> | |
<project version="4"> | |
<component name="PyDocumentationSettings"> | |
<option name="myDocStringFormat" value="Plain" /> | |
</component> | |
</project> | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<component name="DependencyValidationManager"> | |
<state> | |
<option name="SKIP_IMPORT_STATEMENTS" value="false" /> | |
</state> | |
</component> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="UTF-8"?> | |
<project version="4"> | |
<component name="TestRunnerService"> | |
<option name="projectConfiguration" value="Unittests" /> | |
<option name="PROJECT_TEST_RUNNER" value="Unittests" /> | |
</component> | |
</project> | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="UTF-8"?> | |
<project version="4"> | |
<component name="VcsDirectoryMappings"> | |
<mapping directory="" vcs="" /> | |
</component> | |
</project> | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="UTF-8"?> | |
<ui version="4.0"> | |
<class>MainWindow</class> | |
<widget class="QMainWindow" name="MainWindow"> | |
<property name="geometry"> | |
<rect> | |
<x>0</x> | |
<y>0</y> | |
<width>1251</width> | |
<height>588</height> | |
</rect> | |
</property> | |
<property name="windowTitle"> | |
<string>MainWindow</string> | |
</property> | |
<widget class="QWidget" name="centralwidget"> | |
<layout class="QHBoxLayout" name="horizontalLayout_2" stretch="3,1"> | |
<item> | |
<widget class="QGraphicsView" name="graphicsView"/> | |
</item> | |
<item> | |
<layout class="QVBoxLayout" name="verticalLayout"> | |
<item> | |
<widget class="QPushButton" name="pickDirectoryButton"> | |
<property name="text"> | |
<string>Choose Image Directory (jpg)</string> | |
</property> | |
</widget> | |
</item> | |
<item> | |
<widget class="QLineEdit" name="directoryLable"> | |
<property name="enabled"> | |
<bool>false</bool> | |
</property> | |
</widget> | |
</item> | |
<item> | |
<widget class="QListWidget" name="fileList"> | |
<property name="enabled"> | |
<bool>false</bool> | |
</property> | |
</widget> | |
</item> | |
<item> | |
<layout class="QHBoxLayout" name="horizontalLayout_3"> | |
<item> | |
<widget class="QPushButton" name="undoButton"> | |
<property name="enabled"> | |
<bool>false</bool> | |
</property> | |
<property name="text"> | |
<string>Undo</string> | |
</property> | |
</widget> | |
</item> | |
<item> | |
<widget class="QPushButton" name="saveAndNextButton"> | |
<property name="enabled"> | |
<bool>false</bool> | |
</property> | |
<property name="text"> | |
<string>Save and Continue</string> | |
</property> | |
</widget> | |
</item> | |
</layout> | |
</item> | |
</layout> | |
</item> | |
</layout> | |
</widget> | |
<widget class="QMenuBar" name="menubar"> | |
<property name="geometry"> | |
<rect> | |
<x>0</x> | |
<y>0</y> | |
<width>1251</width> | |
<height>22</height> | |
</rect> | |
</property> | |
</widget> | |
<widget class="QStatusBar" name="statusbar"/> | |
</widget> | |
<resources/> | |
<connections/> | |
</ui> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
__author__ = 'Patrick' | |
import sys | |
from PyQt4 import QtCore, QtGui, uic | |
import Image | |
import ImageQt | |
import ImageEnhance | |
import glob | |
from threading import Thread | |
import subprocess | |
import os | |
class graphicsScene(QtGui.QGraphicsScene): | |
def __init__ (self, parent=None): | |
super(graphicsScene, self).__init__ (parent) | |
self.parent = parent | |
def mousePressEvent(self, event): | |
#super(graphicsScene, self).mousePressEvent(event) | |
position = QtCore.QPointF(event.scenePos()) | |
print "pressed here: " + str(position.x()) + ", " + str(position.y()) | |
print self.parent.picture_dimensions | |
if position.x() < 0 or position.y() < 0: | |
position.setX(0) | |
position.setY(0) | |
print "here" | |
elif position.x() > self.parent.picture_dimensions[2] or position.y() > self.parent.picture_dimensions[3]: | |
position.setX(self.parent.picture_dimensions[2]) | |
position.setY(self.parent.picture_dimensions[3]) | |
print "there" | |
self.start_pos = position | |
self.update() | |
def contextMenuEvent(self, event): | |
print "right click" | |
self.update() | |
def mouseMoveEvent(self, event): | |
position = QtCore.QPointF(event.scenePos()) | |
print "moved here: " + str(position.x()) + ", " + str(position.y()) | |
pen = QtGui.QPen(QtCore.Qt.red) | |
brush = QtGui.QBrush(QtGui.QColor(255,100,100,100)) | |
width = position.x() - self.start_pos.x() | |
height = position.y() - self.start_pos.y() | |
select_rect = QtCore.QRectF(self.start_pos.x(), self.start_pos.y(), width, height) | |
temp_rect = self.addRect(select_rect, pen, brush) | |
self.parent.temp_selection_rectangles.append(temp_rect) | |
for i in range(len(self.parent.temp_selection_rectangles) - 1): | |
self.removeItem(self.parent.temp_selection_rectangles[i]) | |
del self.parent.temp_selection_rectangles[i] | |
self.update() | |
def wheelEvent(self, QGraphicsSceneWheelEvent): | |
print "wheel!" | |
def mouseReleaseEvent(self, event): | |
position = QtCore.QPointF(event.scenePos()) | |
print "released here: " + str(position.x()) + ", " + str(position.y()) | |
pen = QtGui.QPen(QtCore.Qt.red) | |
brush = QtGui.QBrush(QtGui.QColor(255,100,100,100)) | |
width = position.x() - self.start_pos.x() | |
height = position.y() - self.start_pos.y() | |
area = abs(width * height) | |
if area > 100 and position.x() >= 0 and position.y() >= 0 \ | |
and position.x() <= self.parent.picture_dimensions[2] \ | |
and position.y() <= self.parent.picture_dimensions[3]: | |
select_rect = QtCore.QRectF(self.start_pos.x(), self.start_pos.y(), width, height) | |
crop_rect = self.addRect(select_rect, pen, brush) | |
self.parent.selection_rectangles.append(crop_rect) | |
self.parent.ui.undoButton.setEnabled(True) | |
for temp_selection in self.parent.temp_selection_rectangles: | |
self.removeItem(temp_selection) | |
del self.parent.temp_selection_rectangles[:] | |
self.update() | |
class dataSetMaker(QtGui.QMainWindow): | |
def __init__(self): | |
QtGui.QMainWindow.__init__(self) | |
self.ui = uic.loadUi('dataset_crop.ui', self) | |
self.temp_selection_rectangles = [] | |
self.selection_rectangles = [] | |
self.number_of_images = 0 | |
self.current_image_index = 0 | |
self.picture_dimensions = (0,0,0,0) | |
self.scene = graphicsScene(self) | |
self.ui.graphicsView.setScene(self.scene) | |
self.connect(self.ui.pickDirectoryButton, QtCore.SIGNAL("clicked()"), self.pickDirectory) | |
self.connect(self.ui.saveAndNextButton, QtCore.SIGNAL("clicked()"), self.saveAndNext) | |
self.connect(self.ui.undoButton, QtCore.SIGNAL("clicked()"), self.undo) | |
self.ui.show() | |
def pickDirectory(self): | |
image_directory_name = str(QtGui.QFileDialog.getExistingDirectory(self, "Select Directory")) | |
self.ui.directoryLable.setText(image_directory_name) | |
self.image_names = glob.glob(image_directory_name + "/*.jpg") | |
self.number_of_images = len(self.image_names) | |
self.ui.fileList.clear() | |
for image in self.image_names: | |
self.ui.fileList.addItem(os.path.basename(image)) | |
if len(self.image_names) > 0: | |
img = QtGui.QPixmap(self.image_names[self.current_image_index]) | |
self.display_image(img) | |
self.ui.saveAndNextButton.setEnabled(True) | |
def saveAndNext(self): | |
# save each cropped rectangle | |
for crop in self.selection_rectangles: | |
print crop | |
# save a mask | |
# next | |
self.current_image_index += 1 | |
#img = Image.open(self.image_names[self.current_image_index]) | |
img = QtGui.QPixmap(self.image_names[self.current_image_index]) | |
self.display_image(img) | |
def display_image(self, img): | |
self.scene.clear() | |
picture = self.scene.addPixmap(img) | |
self.pil_pic = Image.open(img) | |
self.picture_dimensions = picture.boundingRect().getCoords() | |
del self.temp_selection_rectangles[:] | |
def undo(self): | |
self.scene.removeItem(self.selection_rectangles[-1]) | |
del self.selection_rectangles[-1] | |
self.scene.update() | |
if len(self.selection_rectangles) < 1: | |
self.ui.undoButton.setEnabled(False) | |
class cropRect: | |
p1 = QtCore.QPoint() | |
p2 = QtCore.QPoint() | |
def main(): | |
app = QtGui.QApplication(sys.argv) | |
ui = dataSetMaker() | |
sys.exit(app.exec_()) | |
if __name__ == '__main__': | |
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import sys | |
from PyQt4 import QtCore, QtGui, uic | |
class graphicsScene(QtGui.QGraphicsScene): | |
def __init__ (self, parent=None): | |
super(graphicsScene, self).__init__ (parent) | |
def mousePressEvent(self, event): | |
#super(graphicsScene, self).mousePressEvent(event) | |
position = QtCore.QPointF(event.scenePos()) | |
print "pressed here: " + str(position.x()) + ", " + str(position.y()) | |
self.update() | |
def mouseMoveEvent(self, event): | |
position = QtCore.QPointF(event.scenePos()) | |
print "moved here: " + str(position.x()) + ", " + str(position.y()) | |
self.update() | |
def mouseReleaseEvent(self, event): | |
position = QtCore.QPointF(event.scenePos()) | |
print "released here: " + str(position.x()) + ", " + str(position.y()) | |
self.update() | |
def contextMenuEvent(self, event): | |
print "right click" | |
self.update() | |
def wheelEvent(self, event): | |
print "wheel!" | |
class test(QtGui.QMainWindow): | |
def __init__(self): | |
QtGui.QMainWindow.__init__(self) | |
self.ui = uic.loadUi('test.ui', self) | |
self.scene = graphicsScene() | |
self.ui.graphicsView.setScene(self.scene) | |
pen = QtGui.QPen(QtCore.Qt.blue) | |
brush = QtGui.QBrush(QtCore.Qt.red) | |
e = self.scene.addEllipse(10,10,100,100, pen, brush) | |
e.setFlag(QtGui.QGraphicsItem.ItemIsMovable, True) | |
self.ui.show() | |
def main(): | |
app = QtGui.QApplication(sys.argv) | |
ui = test() | |
sys.exit(app.exec_()) | |
if __name__ == '__main__': | |
main() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="UTF-8"?> | |
<ui version="4.0"> | |
<class>MainWindow</class> | |
<widget class="QMainWindow" name="MainWindow"> | |
<property name="geometry"> | |
<rect> | |
<x>0</x> | |
<y>0</y> | |
<width>865</width> | |
<height>688</height> | |
</rect> | |
</property> | |
<property name="windowTitle"> | |
<string>MainWindow</string> | |
</property> | |
<widget class="QWidget" name="centralwidget"> | |
<layout class="QVBoxLayout" name="verticalLayout"> | |
<item> | |
<widget class="QGraphicsView" name="graphicsView"/> | |
</item> | |
</layout> | |
</widget> | |
<widget class="QMenuBar" name="menubar"> | |
<property name="geometry"> | |
<rect> | |
<x>0</x> | |
<y>0</y> | |
<width>865</width> | |
<height>22</height> | |
</rect> | |
</property> | |
</widget> | |
<widget class="QStatusBar" name="statusbar"/> | |
</widget> | |
<resources/> | |
<connections/> | |
</ui> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# Copyright (c) 2007-8 Qtrac Ltd. All rights reserved. | |
# This program or module is free software: you can redistribute it and/or | |
# modify it under the terms of the GNU General Public License as published | |
# by the Free Software Foundation, either version 2 of the License, or | |
# version 3 of the License, or (at your option) any later version. It is | |
# provided for educational purposes and is distributed in the hope that | |
# it will be useful, but WITHOUT ANY WARRANTY; without even the implied | |
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See | |
# the GNU General Public License for more details. | |
from __future__ import division | |
import functools | |
import random | |
import sys | |
from PyQt4.QtCore import * | |
from PyQt4.QtGui import * | |
MAC = "qt_mac_set_native_menubar" in dir() | |
# A4 in points | |
#PageSize = (595, 842) | |
# US Letter in points | |
PageSize = (612, 792) | |
PointSize = 10 | |
MagicNumber = 0x70616765 | |
FileVersion = 1 | |
Dirty = False | |
class TextItemDlg(QDialog): | |
def __init__(self, item=None, position=None, scene=None, | |
parent=None): | |
super(QDialog, self).__init__(parent) | |
self.item = item | |
self.position = position | |
self.scene = scene | |
self.editor = QTextEdit() | |
self.editor.setAcceptRichText(False) | |
self.editor.setTabChangesFocus(True) | |
editorLabel = QLabel("&Text:") | |
editorLabel.setBuddy(self.editor) | |
self.fontComboBox = QFontComboBox() | |
self.fontComboBox.setCurrentFont(QFont("Times", PointSize)) | |
fontLabel = QLabel("&Font:") | |
fontLabel.setBuddy(self.fontComboBox) | |
self.fontSpinBox = QSpinBox() | |
self.fontSpinBox.setAlignment(Qt.AlignRight|Qt.AlignVCenter) | |
self.fontSpinBox.setRange(6, 280) | |
self.fontSpinBox.setValue(PointSize) | |
fontSizeLabel = QLabel("&Size:") | |
fontSizeLabel.setBuddy(self.fontSpinBox) | |
self.buttonBox = QDialogButtonBox(QDialogButtonBox.Ok| | |
QDialogButtonBox.Cancel) | |
self.buttonBox.button(QDialogButtonBox.Ok).setEnabled(False) | |
if self.item is not None: | |
self.editor.setPlainText(self.item.toPlainText()) | |
self.fontComboBox.setCurrentFont(self.item.font()) | |
self.fontSpinBox.setValue(self.item.font().pointSize()) | |
layout = QGridLayout() | |
layout.addWidget(editorLabel, 0, 0) | |
layout.addWidget(self.editor, 1, 0, 1, 6) | |
layout.addWidget(fontLabel, 2, 0) | |
layout.addWidget(self.fontComboBox, 2, 1, 1, 2) | |
layout.addWidget(fontSizeLabel, 2, 3) | |
layout.addWidget(self.fontSpinBox, 2, 4, 1, 2) | |
layout.addWidget(self.buttonBox, 3, 0, 1, 6) | |
self.setLayout(layout) | |
self.connect(self.fontComboBox, | |
SIGNAL("currentFontChanged(QFont)"), self.updateUi) | |
self.connect(self.fontSpinBox, | |
SIGNAL("valueChanged(int)"), self.updateUi) | |
self.connect(self.editor, SIGNAL("textChanged()"), | |
self.updateUi) | |
self.connect(self.buttonBox, SIGNAL("accepted()"), self.accept) | |
self.connect(self.buttonBox, SIGNAL("rejected()"), self.reject) | |
self.setWindowTitle("Page Designer - %s Text Item" % ( | |
"Add" if self.item is None else "Edit")) | |
self.updateUi() | |
def updateUi(self): | |
font = self.fontComboBox.currentFont() | |
font.setPointSize(self.fontSpinBox.value()) | |
self.editor.document().setDefaultFont(font) | |
self.buttonBox.button(QDialogButtonBox.Ok).setEnabled( | |
not self.editor.toPlainText().isEmpty()) | |
def accept(self): | |
if self.item is None: | |
self.item = TextItem("", self.position, self.scene) | |
font = self.fontComboBox.currentFont() | |
font.setPointSize(self.fontSpinBox.value()) | |
self.item.setFont(font) | |
self.item.setPlainText(self.editor.toPlainText()) | |
self.item.update() | |
global Dirty | |
Dirty = True | |
QDialog.accept(self) | |
class TextItem(QGraphicsTextItem): | |
def __init__(self, text, position, scene, | |
font=QFont("Times", PointSize), matrix=QMatrix()): | |
super(TextItem, self).__init__(text) | |
self.setFlags(QGraphicsItem.ItemIsSelectable| | |
QGraphicsItem.ItemIsMovable) | |
self.setFont(font) | |
self.setPos(position) | |
self.setMatrix(matrix) | |
scene.clearSelection() | |
scene.addItem(self) | |
self.setSelected(True) | |
global Dirty | |
Dirty = True | |
def parentWidget(self): | |
return self.scene().views()[0] | |
def itemChange(self, change, variant): | |
if change != QGraphicsItem.ItemSelectedChange: | |
global Dirty | |
Dirty = True | |
return QGraphicsTextItem.itemChange(self, change, variant) | |
def mouseDoubleClickEvent(self, event): | |
dialog = TextItemDlg(self, self.parentWidget()) | |
dialog.exec_() | |
class BoxItem(QGraphicsItem): | |
def __init__(self, position, scene, style=Qt.SolidLine, | |
rect=None, matrix=QMatrix()): | |
super(BoxItem, self).__init__() | |
self.setFlags(QGraphicsItem.ItemIsSelectable| | |
QGraphicsItem.ItemIsMovable| | |
QGraphicsItem.ItemIsFocusable) | |
if rect is None: | |
rect = QRectF(-10 * PointSize, -PointSize, | |
20 * PointSize, 2 * PointSize) | |
self.rect = rect | |
self.style = style | |
self.setPos(position) | |
self.setMatrix(matrix) | |
scene.clearSelection() | |
scene.addItem(self) | |
self.setSelected(True) | |
self.setFocus() | |
global Dirty | |
Dirty = True | |
def parentWidget(self): | |
return self.scene().views()[0] | |
def boundingRect(self): | |
return self.rect.adjusted(-2, -2, 2, 2) | |
def paint(self, painter, option, widget): | |
pen = QPen(self.style) | |
pen.setColor(Qt.black) | |
pen.setWidth(1) | |
if option.state & QStyle.State_Selected: | |
pen.setColor(Qt.blue) | |
painter.setPen(pen) | |
painter.drawRect(self.rect) | |
def itemChange(self, change, variant): | |
if change != QGraphicsItem.ItemSelectedChange: | |
global Dirty | |
Dirty = True | |
return QGraphicsItem.itemChange(self, change, variant) | |
def contextMenuEvent(self, event): | |
wrapped = [] | |
menu = QMenu(self.parentWidget()) | |
for text, param in ( | |
("&Solid", Qt.SolidLine), | |
("&Dashed", Qt.DashLine), | |
("D&otted", Qt.DotLine), | |
("D&ashDotted", Qt.DashDotLine), | |
("DashDo&tDotted", Qt.DashDotDotLine)): | |
wrapper = functools.partial(self.setStyle, param) | |
wrapped.append(wrapper) | |
menu.addAction(text, wrapper) | |
menu.exec_(event.screenPos()) | |
def setStyle(self, style): | |
self.style = style | |
self.update() | |
global Dirty | |
Dirty = True | |
def keyPressEvent(self, event): | |
factor = PointSize / 4 | |
changed = False | |
if event.modifiers() & Qt.ShiftModifier: | |
if event.key() == Qt.Key_Left: | |
self.rect.setRight(self.rect.right() - factor) | |
changed = True | |
elif event.key() == Qt.Key_Right: | |
self.rect.setRight(self.rect.right() + factor) | |
changed = True | |
elif event.key() == Qt.Key_Up: | |
self.rect.setBottom(self.rect.bottom() - factor) | |
changed = True | |
elif event.key() == Qt.Key_Down: | |
self.rect.setBottom(self.rect.bottom() + factor) | |
changed = True | |
if changed: | |
self.update() | |
global Dirty | |
Dirty = True | |
else: | |
QGraphicsItem.keyPressEvent(self, event) | |
class GraphicsView(QGraphicsView): | |
def __init__(self, parent=None): | |
super(GraphicsView, self).__init__(parent) | |
self.setDragMode(QGraphicsView.RubberBandDrag) | |
self.setRenderHint(QPainter.Antialiasing) | |
self.setRenderHint(QPainter.TextAntialiasing) | |
def wheelEvent(self, event): | |
factor = 1.41 ** (-event.delta() / 240.0) | |
self.scale(factor, factor) | |
class MainForm(QDialog): | |
def __init__(self, parent=None): | |
super(MainForm, self).__init__(parent) | |
self.filename = QString() | |
self.copiedItem = QByteArray() | |
self.pasteOffset = 5 | |
self.prevPoint = QPoint() | |
self.addOffset = 5 | |
self.borders = [] | |
self.printer = QPrinter(QPrinter.HighResolution) | |
self.printer.setPageSize(QPrinter.Letter) | |
self.view = GraphicsView() | |
self.scene = QGraphicsScene(self) | |
self.scene.setSceneRect(0, 0, PageSize[0], PageSize[1]) | |
self.addBorders() | |
self.view.setScene(self.scene) | |
buttonLayout = QVBoxLayout() | |
for text, slot in ( | |
("Add &Text", self.addText), | |
("Add &Box", self.addBox), | |
("Add Pi&xmap", self.addPixmap), | |
("&Copy", self.copy), | |
("C&ut", self.cut), | |
("&Paste", self.paste), | |
("&Delete...", self.delete), | |
("&Rotate", self.rotate), | |
("Pri&nt...", self.print_), | |
("&Open...", self.open), | |
("&Save", self.save), | |
("&Quit", self.accept)): | |
button = QPushButton(text) | |
if not MAC: | |
button.setFocusPolicy(Qt.NoFocus) | |
self.connect(button, SIGNAL("clicked()"), slot) | |
if text == "Pri&nt...": | |
buttonLayout.addStretch(5) | |
if text == "&Quit": | |
buttonLayout.addStretch(1) | |
buttonLayout.addWidget(button) | |
buttonLayout.addStretch() | |
layout = QHBoxLayout() | |
layout.addWidget(self.view, 1) | |
layout.addLayout(buttonLayout) | |
self.setLayout(layout) | |
fm = QFontMetrics(self.font()) | |
self.resize(self.scene.width() + fm.width(" Delete... ") + 50, | |
self.scene.height() + 50) | |
self.setWindowTitle("Page Designer") | |
def addBorders(self): | |
self.borders = [] | |
rect = QRectF(0, 0, PageSize[0], PageSize[1]) | |
self.borders.append(self.scene.addRect(rect, Qt.yellow)) | |
margin = 5.25 * PointSize | |
self.borders.append(self.scene.addRect( | |
rect.adjusted(margin, margin, -margin, -margin), | |
Qt.yellow)) | |
def removeBorders(self): | |
while self.borders: | |
item = self.borders.pop() | |
self.scene.removeItem(item) | |
del item | |
def reject(self): | |
self.accept() | |
def accept(self): | |
self.offerSave() | |
QDialog.accept(self) | |
def offerSave(self): | |
if Dirty and QMessageBox.question(self, | |
"Page Designer - Unsaved Changes", | |
"Save unsaved changes?", | |
QMessageBox.Yes|QMessageBox.No) == \ | |
QMessageBox.Yes: | |
self.save() | |
def position(self): | |
point = self.mapFromGlobal(QCursor.pos()) | |
if not self.view.geometry().contains(point): | |
coord = random.randint(36, 144) | |
point = QPoint(coord, coord) | |
else: | |
if point == self.prevPoint: | |
point += QPoint(self.addOffset, self.addOffset) | |
self.addOffset += 5 | |
else: | |
self.addOffset = 5 | |
self.prevPoint = point | |
return self.view.mapToScene(point) | |
def addText(self): | |
dialog = TextItemDlg(position=self.position(), | |
scene=self.scene, parent=self) | |
dialog.exec_() | |
def addBox(self): | |
BoxItem(self.position(), self.scene) | |
def addPixmap(self): | |
path = QFileInfo(self.filename).path() \ | |
if not self.filename.isEmpty() else "." | |
fname = QFileDialog.getOpenFileName(self, | |
"Page Designer - Add Pixmap", path, | |
"Pixmap Files (*.bmp *.jpg *.png *.xpm)") | |
if fname.isEmpty(): | |
return | |
self.createPixmapItem(QPixmap(fname), self.position()) | |
def createPixmapItem(self, pixmap, position, matrix=QMatrix()): | |
item = QGraphicsPixmapItem(pixmap) | |
item.setFlags(QGraphicsItem.ItemIsSelectable| | |
QGraphicsItem.ItemIsMovable) | |
item.setPos(position) | |
item.setMatrix(matrix) | |
self.scene.clearSelection() | |
self.scene.addItem(item) | |
item.setSelected(True) | |
global Dirty | |
Dirty = True | |
def selectedItem(self): | |
items = self.scene.selectedItems() | |
if len(items) == 1: | |
return items[0] | |
return None | |
def copy(self): | |
item = self.selectedItem() | |
if item is None: | |
return | |
self.copiedItem.clear() | |
self.pasteOffset = 5 | |
stream = QDataStream(self.copiedItem, QIODevice.WriteOnly) | |
self.writeItemToStream(stream, item) | |
def cut(self): | |
item = self.selectedItem() | |
if item is None: | |
return | |
self.copy() | |
self.scene.removeItem(item) | |
del item | |
def paste(self): | |
if self.copiedItem.isEmpty(): | |
return | |
stream = QDataStream(self.copiedItem, QIODevice.ReadOnly) | |
self.readItemFromStream(stream, self.pasteOffset) | |
self.pasteOffset += 5 | |
def rotate(self): | |
for item in self.scene.selectedItems(): | |
item.rotate(30) | |
def delete(self): | |
items = self.scene.selectedItems() | |
if len(items) and QMessageBox.question(self, | |
"Page Designer - Delete", | |
"Delete %d item%s?" % (len(items), | |
"s" if len(items) != 1 else ""), | |
QMessageBox.Yes|QMessageBox.No) == QMessageBox.Yes: | |
while items: | |
item = items.pop() | |
self.scene.removeItem(item) | |
del item | |
global Dirty | |
Dirty = True | |
def print_(self): | |
dialog = QPrintDialog(self.printer) | |
if dialog.exec_(): | |
painter = QPainter(self.printer) | |
painter.setRenderHint(QPainter.Antialiasing) | |
painter.setRenderHint(QPainter.TextAntialiasing) | |
self.scene.clearSelection() | |
self.removeBorders() | |
self.scene.render(painter) | |
self.addBorders() | |
def open(self): | |
self.offerSave() | |
path = QFileInfo(self.filename).path() \ | |
if not self.filename.isEmpty() else "." | |
fname = QFileDialog.getOpenFileName(self, | |
"Page Designer - Open", path, | |
"Page Designer Files (*.pgd)") | |
if fname.isEmpty(): | |
return | |
self.filename = fname | |
fh = None | |
try: | |
fh = QFile(self.filename) | |
if not fh.open(QIODevice.ReadOnly): | |
raise IOError, unicode(fh.errorString()) | |
items = self.scene.items() | |
while items: | |
item = items.pop() | |
self.scene.removeItem(item) | |
del item | |
self.addBorders() | |
stream = QDataStream(fh) | |
stream.setVersion(QDataStream.Qt_4_2) | |
magic = stream.readInt32() | |
if magic != MagicNumber: | |
raise IOError, "not a valid .pgd file" | |
fileVersion = stream.readInt16() | |
if fileVersion != FileVersion: | |
raise IOError, "unrecognised .pgd file version" | |
while not fh.atEnd(): | |
self.readItemFromStream(stream) | |
except IOError, e: | |
QMessageBox.warning(self, "Page Designer -- Open Error", | |
"Failed to open %s: %s" % (self.filename, e)) | |
finally: | |
if fh is not None: | |
fh.close() | |
global Dirty | |
Dirty = False | |
def save(self): | |
if self.filename.isEmpty(): | |
path = "." | |
fname = QFileDialog.getSaveFileName(self, | |
"Page Designer - Save As", path, | |
"Page Designer Files (*.pgd)") | |
if fname.isEmpty(): | |
return | |
self.filename = fname | |
fh = None | |
try: | |
fh = QFile(self.filename) | |
if not fh.open(QIODevice.WriteOnly): | |
raise IOError, unicode(fh.errorString()) | |
self.scene.clearSelection() | |
stream = QDataStream(fh) | |
stream.setVersion(QDataStream.Qt_4_2) | |
stream.writeInt32(MagicNumber) | |
stream.writeInt16(FileVersion) | |
for item in self.scene.items(): | |
self.writeItemToStream(stream, item) | |
except IOError, e: | |
QMessageBox.warning(self, "Page Designer -- Save Error", | |
"Failed to save %s: %s" % (self.filename, e)) | |
finally: | |
if fh is not None: | |
fh.close() | |
global Dirty | |
Dirty = False | |
def readItemFromStream(self, stream, offset=0): | |
type = QString() | |
position = QPointF() | |
matrix = QMatrix() | |
stream >> type >> position >> matrix | |
if offset: | |
position += QPointF(offset, offset) | |
if type == "Text": | |
text = QString() | |
font = QFont() | |
stream >> text >> font | |
TextItem(text, position, self.scene, font, matrix) | |
elif type == "Box": | |
rect = QRectF() | |
stream >> rect | |
style = Qt.PenStyle(stream.readInt16()) | |
BoxItem(position, self.scene, style, rect, matrix) | |
elif type == "Pixmap": | |
pixmap = QPixmap() | |
stream >> pixmap | |
self.createPixmapItem(pixmap, position, matrix) | |
def writeItemToStream(self, stream, item): | |
if isinstance(item, QGraphicsTextItem): | |
stream << QString("Text") << item.pos() << item.matrix() \ | |
<< item.toPlainText() << item.font() | |
elif isinstance(item, QGraphicsPixmapItem): | |
stream << QString("Pixmap") << item.pos() \ | |
<< item.matrix() << item.pixmap() | |
elif isinstance(item, BoxItem): | |
stream << QString("Box") << item.pos() << item.matrix() \ | |
<< item.rect | |
stream.writeInt16(item.style) | |
app = QApplication(sys.argv) | |
form = MainForm() | |
rect = QApplication.desktop().availableGeometry() | |
form.resize(int(rect.width() * 0.6), int(rect.height() * 0.9)) | |
form.show() | |
app.exec_() | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment