프로젝트

일반

사용자정보

개정판 f7940a95

IDf7940a95bf1ec38d1e1372a06e3e88499f95003d
상위 8fa58e02
하위 abbd75be, 43c380f8

백흠경이(가) 약 5년 전에 추가함

issue #1363: implemented class to export svg

Change-Id: Ic3a8c972612a7db2f5b78034e423b64bbb7f8860

차이점 보기:

DTI_PID/DTI_PID/Commands/ExportCommand.py
3 3
import os.path
4 4
import sys
5 5
from enum import Enum
6
import AbstractCommand
6 7
from PyQt5.QtCore import *
7 8
from PyQt5.QtGui import *
8 9
from PyQt5.QtWidgets import *
9 10

  
10 11

  
11
class ExportCommand(QThread):
12
class ExportCommand(AbstractCommand.AbstractCommand):
12 13
    display_message = pyqtSignal(Enum, str)
13 14
    show_progress = pyqtSignal(int)
14 15

  
15
    def __init__(self, format):
16
        QThread.__init__(self)
16
    def __init__(self, scene, format):
17
        super(ExportCommand, self).__init__(None)
17 18

  
19
        self._scene = scene
18 20
        self._format = format  # xml, svg, image
19 21

  
20
    def __del__(self):
21
        self.wait()
22

  
23
    def run(self):
22
    def execute(self, param) -> bool:
24 23
        """ do given work"""
25 24
        from AppDocData import AppDocData
26 25
        from AppDocData import MessageType
27 26

  
28 27
        try:
29 28
            app_doc_data = AppDocData.instance()
29
            if self._format == 'svg':
30
                self.export_as_svg(param)
31
            elif self._format == 'xml':
32
                pass
33
            elif self._format == 'image':
34
                self.export_as_image(param)
35

  
36
            return True
30 37
        except Exception as ex:
31 38
            from AppDocData import MessageType
32 39

  
......
34 41
                                                           sys.exc_info()[-1].tb_lineno)
35 42
            self.display_message.emit(MessageType.Error, message)
36 43

  
44
        return False
45

  
46
    def prettify(self, elem):
47
        """Return a pretty-printed XML string for the Element."""
48
        from xml.etree import ElementTree
49
        from xml.dom import minidom
50

  
51
        rough_string = ElementTree.tostring(elem, 'utf-8')
52
        reparsed = minidom.parseString(rough_string)
53
        return reparsed.toprettyxml(indent="  ")
54

  
55
    def export_as_svg(self, file_path):
56
        """export to svg file"""
57
        from xml.etree.ElementTree import Element, tostring, SubElement, dump, ElementTree, parse
58

  
59
        if not file_path:
60
            options = QFileDialog.Options()
61
            options |= QFileDialog.DontUseNativeDialog
62
            file_path, _ = QFileDialog.getSaveFileName(self, "Export as svg", os.getcwd(), "svg file(*.svg)",
63
                                                       options=options)
64
        if file_path:
65
            file_name, ext = os.path.splitext(file_path)
66
            save_file_path = file_name + ext if ext.upper() == '.SVG' else file_name + '.svg'
67

  
68
            rect = self._scene.sceneRect()
69

  
70
            svg = Element('svg')
71
            svg.attrib['width'] = f"{rect.width()}"
72
            svg.attrib['height'] = f"{rect.height()}"
73
            svg.attrib['viewBox'] = f"{0} {0} {rect.width()} {rect.height()}"
74
            svg.attrib['xmlns'] = 'http://www.w3.org/2000/svg'
75
            svg.attrib['xmlns:xlink'] = "http://www.w3.org/1999/xlink"
76
            svg.attrib['version'] = "1.2"
77
            svg.attrib['baseProfile'] = "tiny"
78
            for item in self._scene.items():
79
                if hasattr(item, 'to_svg'):
80
                    node = item.to_svg()
81
                    if node:
82
                        svg.append(node)
83

  
84
            with open(save_file_path, 'w', encoding='utf-8') as output_file:
85
                output_file.write(self.prettify(svg))
86

  
87
    def export_as_image(self, file_path):
88
        """export to image file"""
89

  
90
        if not file_path:
91
            options = QFileDialog.Options()
92
            options |= QFileDialog.DontUseNativeDialog
93
            file_path, _ = QFileDialog.getSaveFileName(self, "Export as png", os.getcwd(), "png file(*.png)",
94
                                                       options=options)
95
        if file_path:
96
            file_name, ext = os.path.splitext(file_path)
97
            save_file_path = file_name + ext if ext.upper() == '.PNG' else file_name + '.png'
98

  
99
            rect = self._scene.sceneRect()
100
            size = QSize(rect.width(), rect.height())
101
            image = QImage(size, QImage.Format_ARGB32_Premultiplied)
102

  
103
            painter = QPainter(image)
104
            # render the scene
105
            self._scene.render(painter)
106
            painter.end()
107

  
108
            # save the image to a given file
109
            image.save(save_file_path)
DTI_PID/DTI_PID/MainWindow.py
1342 1342
            self.graphicsView.scene.update(self.graphicsView.sceneRect())
1343 1343
            DisplayColors.instance().save_data()
1344 1344

  
1345
    '''
1346
        @brief      Open image drawing file and then display it
1347
        @author     humkyung
1348
        @date       2018.??.??
1349
        @history    18.04.23 Jeongwoo    Add AppDocData.instance().setCurrentPidSource
1350
                    18.04.23 Jeongwoo    Add Store Set Current Pid Image on AppDocData
1351
                    18.05.02 Jeongwoo    Add useDefaultCommand()
1352
                    humkyung 2018.05.24 load recognition result file if exists
1353
                    Jeongwoo 2018.05.29 load data on xml if xml file exist
1354
                    humkyung 2018.08.22 clear scene before loading xml file
1355
    '''
1356

  
1357 1345
    def open_image_drawing(self, drawing):
1346
        """open and display image drawing file"""
1358 1347
        from Drawing import Drawing
1359 1348

  
1360 1349
        try:
......
1400 1389
                    if self.graphicsView.scene.receivers(self.graphicsView.scene.contents_changed) > 0:
1401 1390
                        self.graphicsView.scene.contents_changed.disconnect()
1402 1391

  
1392
                    SymbolSvgItem.DOCUMENTS.clear()
1393

  
1403 1394
                    # Load data
1404 1395
                    path = os.path.join(app_doc_data.getCurrentProject().getTempPath(), app_doc_data.imgName + '.xml')
1405 1396
                    configs = app_doc_data.getConfigs('Data Load', 'Xml First')
......
1425 1416

  
1426 1417
        return self.path
1427 1418

  
1428
    def prettify(self, elem):
1429
        """Return a pretty-printed XML string for the Element."""
1430
        from xml.etree import ElementTree
1431
        from xml.dom import minidom
1432

  
1433
        rough_string = ElementTree.tostring(elem, 'utf-8')
1434
        reparsed = minidom.parseString(rough_string)
1435
        return reparsed.toprettyxml(indent="  ")
1436

  
1437 1419
    def export_as_svg(self):
1438 1420
        """export scene to svg file"""
1439
        from xml.etree.ElementTree import Element, tostring, SubElement, dump, ElementTree, parse
1421
        from ExportCommand import ExportCommand
1440 1422

  
1441 1423
        options = QFileDialog.Options()
1442 1424
        options |= QFileDialog.DontUseNativeDialog
1443 1425
        file_path, _ = QFileDialog.getSaveFileName(self, "Export as svg", os.getcwd(), "svg file(*.svg)",
1444 1426
                                                   options=options)
1445 1427
        if file_path:
1446
            try:
1447
                file_name, ext = os.path.splitext(file_path)
1448
                save_file_path = file_name + ext if ext.upper() == '.SVG' else file_name + '.svg'
1449

  
1450
                # hide image drawing
1451
                self.onViewImageDrawing(False)
1452

  
1453
                rect = self.graphicsView.scene.sceneRect()
1454

  
1455
                svg = Element('svg')
1456
                svg.attrib['width'] = f"{rect.width()}"
1457
                svg.attrib['height'] = f"{rect.height()}"
1458
                svg.attrib['viewBox'] = f"{0} {0} {rect.width()} {rect.height()}"
1459
                svg.attrib['xmlns'] = 'http://www.w3.org/2000/svg'
1460
                svg.attrib['xmlns:xlink'] = "http://www.w3.org/1999/xlink"
1461
                svg.attrib['version'] = "1.2"
1462
                svg.attrib['baseProfile'] = "tiny"
1463
                for item in self.graphicsView.scene.items():
1464
                    if hasattr(item, 'to_svg'):
1465
                        node = item.to_svg()
1466
                        if node:
1467
                            svg.append(node)
1468

  
1469
                with open(save_file_path, 'w', encoding='utf-8') as output_file:
1470
                    output_file.write(self.prettify(svg))
1471

  
1472
                """ create a svg file by using QSvgGenerator of pyqt5
1473
                svg_gen = QSvgGenerator()
1474

  
1475
                svg_gen.setFileName(save_file_path)
1476
                rect = self.graphicsView.scene.sceneRect()
1477
                svg_gen.setSize(QSize(rect.width(), rect.height()))
1478
                svg_gen.setViewBox(QRect(0, 0, rect.width(), rect.height()))
1479
                svg_gen.setTitle(self.tr("SVG Generator for ID2"))
1480
                svg_gen.setDescription(self.tr("An SVG drawing created by the SVG Generator."))
1481

  
1482
                painter = QPainter(svg_gen)
1483
                self.graphicsView.scene.render(painter)
1484
                painter.end()
1485
                """
1486

  
1487
                QMessageBox.information(None, self.tr('Information'), self.tr('Successfully export to svg file'))
1488
            finally:
1489
                if self.actionImage_Drawing.isChecked():
1490
                    self.onViewImageDrawing(True)
1491
                    self.actionImage_Drawing.setChecked(True)
1428
            cmd = ExportCommand(self.graphicsView.scene, 'svg')
1429
            cmd.display_message.connect(self.onAddMessage)
1430
            if cmd.execute(file_path):
1431
                QMessageBox.information(self, self.tr('Information'), self.tr('Successfully export to svg file'))
1432
            else:
1433
                QMessageBox.information(self, self.tr('Error'), self.tr('Fail to export to svg file'))
1492 1434

  
1493 1435
    def export_as_xml(self):
1494 1436
        pass
1495 1437

  
1496 1438
    def export_as_image(self):
1497 1439
        """export scene to image file"""
1440
        from ExportCommand import ExportCommand
1498 1441

  
1499 1442
        options = QFileDialog.Options()
1500 1443
        options |= QFileDialog.DontUseNativeDialog
......
1502 1445
                                                   options=options)
1503 1446
        if file_path:
1504 1447
            try:
1505
                file_name, ext = os.path.splitext(file_path)
1506
                save_file_path = file_name + ext if ext.upper() == '.PNG' else file_name + '.png'
1507

  
1508 1448
                # hide image drawing
1509 1449
                self.onViewImageDrawing(False)
1510 1450

  
1511
                rect = self.graphicsView.scene.sceneRect()
1512
                size = QSize(rect.width(), rect.height())
1513
                image = QImage(size, QImage.Format_ARGB32_Premultiplied)
1514
                painter = QPainter(image)
1515

  
1516
                # render the scene
1517
                self.graphicsView.scene.render(painter)
1518
                painter.end()
1451
                cmd = ExportCommand(self.graphicsView.scene, 'image')
1452
                cmd.display_message.connect(self.onAddMessage)
1519 1453

  
1520
                # save the image to a given file
1521
                image.save(save_file_path)
1522

  
1523
                QMessageBox.information(None, self.tr('Information'), self.tr('Successfully export to image file'))
1454
                if cmd.execute(file_path):
1455
                    QMessageBox.information(self, self.tr('Information'), self.tr('Successfully export to image file'))
1456
                else:
1457
                    QMessageBox.information(self, self.tr('Error'), self.tr('Fail to export to image file'))
1524 1458
            finally:
1525 1459
                if self.actionImage_Drawing.isChecked():
1526 1460
                    self.onViewImageDrawing(True)
DTI_PID/DTI_PID/Shapes/SymbolSvgItem.py
26 26
    ZVALUE = 50
27 27
    HOVER_COLOR = 'url(#hover)'
28 28

  
29
    DOCUMENTS = {}  # store documents and renders for symbols
30

  
29 31
    '''
30 32
        @history    18.04.11    Jeongwoo    Add Variable (Name, Type)
31 33
                    18.05.11    Jeongwoo    Declare variable self.color
......
80 82
        try:
81 83
            app_doc_data = AppDocData.instance()
82 84
            svg = None
83
            if self.name:
84
                _, svg = app_doc_data.read_symbol_shape(self.name)
85

  
86
            if not svg and path and os.path.isfile(path):
87
                f = QFile(path)
88
                f.open(QIODevice.ReadOnly)
89
                svg = f.readAll()
90
                f.close()
91

  
92
            self._document = QDomDocument()
93
            self._document.setContent(svg)
94
            self._renderer = QSvgRenderer(self._document.toByteArray())
85

  
86
            if path not in SymbolSvgItem.DOCUMENTS:
87
                if self.name:
88
                    _, svg = app_doc_data.read_symbol_shape(self.name)
89

  
90
                if not svg and path and os.path.isfile(path):
91
                    f = QFile(path)
92
                    f.open(QIODevice.ReadOnly)
93
                    svg = f.readAll()
94
                    f.close()
95

  
96
                self._document = QDomDocument()
97
                self._document.setContent(svg)
98
                self._renderer = QSvgRenderer(self._document.toByteArray())
99
                SymbolSvgItem.DOCUMENTS[path] = [self._document, self._renderer]
100
            else:
101
                self._document, self._renderer = SymbolSvgItem.DOCUMENTS[path]
102

  
95 103
            self.setSharedRenderer(self._renderer)
96
            #self.setCacheMode(QGraphicsItem.NoCache)
97 104

  
98 105
            self._color = self.get_attribute('fill')
99 106
        except Exception as ex:
DTI_PID/DTI_PID/SymbolEditorDialog.py
620 620
        else:
621 621
            return newName
622 622

  
623
    def makeSymbolData(self, width, height):
623
    def make_symbol_data(self, width, height):
624 624
        """make a symbol object to save to database"""
625 625

  
626 626
        uid = -1
......
631 631

  
632 632
        index = self.ui.treeViewSymbolCategory.currentIndex()
633 633
        item = self.ui.treeViewSymbolCategory.model().itemFromIndex(index)
634
        category = item.parent().text()
635
        self.FILE_NUMBER = 0
636
        lastName = ""
637
        if self.selectedSymbol is not None:
638
            lastName = self.selectedSymbol.getName()
639
        fileName = ""
640
        if name == lastName:
641
            fileName = name
634
        if item:
635
            category = item.parent().text()
636
            self.FILE_NUMBER = 0
637
            lastName = ""
638
            if self.selectedSymbol is not None:
639
                lastName = self.selectedSymbol.getName()
640
            fileName = ""
641
            if name == lastName:
642
                fileName = name
643
            else:
644
                fileName = self.makeFileName(category, name, name)
645
            threshold = str(self.ui.spinBoxThreshold.value())
646
            minMatchPoint = self.ui.minMatchPointLineEdit.text()
647
            rotationCount = int(self.ui.rotationCountSpinBox.value() / 90)
648
            ocrOption = 0
649
            isContainChild = 1 if self.ui.isContainChildCheckBox.isChecked() else 0
650
            originalPoint = self.ui.originalPointLineEdit.text()
651
            connectionPoint = self.makeConnectionPointListString()
652
            baseSymbol = item.text()  # self.ui.baseSymbolComboBox.currentText()
653
            additionalSymbol = self.makeAdditionalSymbolListString()
654
            isExceptDetect = 1 if self.ui.isExceptDetectCheckBox.isChecked() else 0
655

  
656
            hasInstrumentLabel = self.ui.spinBoxhasInstrumentLabel.value()
657

  
658
            detectFlip = 1 if self.ui.makeFlipCheckBox.isChecked() else 0
659

  
660
            convertedThreshold = int(threshold) / 100.0
661

  
662
            imageWidth = width
663
            iamgeHeight = height
664

  
665
            text_areas = []
666
            for row in range(self.ui.textAreaTableWidget.rowCount()):
667
                area = Area('Text Area')
668
                area.parse(self.ui.textAreaTableWidget.item(row, 0).text())
669
                text_areas.append(area)
670

  
671
            self.newSym = symbol.SymbolBase(fileName, category, convertedThreshold, int(minMatchPoint), True,
672
                                            rotationCount, ocrOption, isContainChild, originalPoint, connectionPoint,
673
                                            baseSymbol, additionalSymbol, isExceptDetect, hasInstrumentLabel, uid,
674
                                            imageWidth, iamgeHeight, detectFlip=detectFlip, text_area=text_areas)
675

  
676
            return self.newSym
642 677
        else:
643
            fileName = self.makeFileName(category, name, name)
644
        threshold = str(self.ui.spinBoxThreshold.value())
645
        minMatchPoint = self.ui.minMatchPointLineEdit.text()
646
        rotationCount = int(self.ui.rotationCountSpinBox.value() / 90)
647
        ocrOption = 0
648
        isContainChild = 1 if self.ui.isContainChildCheckBox.isChecked() else 0
649
        originalPoint = self.ui.originalPointLineEdit.text()
650
        connectionPoint = self.makeConnectionPointListString()
651
        baseSymbol = item.text()  # self.ui.baseSymbolComboBox.currentText()
652
        additionalSymbol = self.makeAdditionalSymbolListString()
653
        isExceptDetect = 1 if self.ui.isExceptDetectCheckBox.isChecked() else 0
654

  
655
        hasInstrumentLabel = self.ui.spinBoxhasInstrumentLabel.value()
656

  
657
        detectFlip = 1 if self.ui.makeFlipCheckBox.isChecked() else 0
658

  
659
        convertedThreshold = int(threshold) / 100.0
660

  
661
        imageWidth = width
662
        iamgeHeight = height
663

  
664
        text_areas = []
665
        for row in range(self.ui.textAreaTableWidget.rowCount()):
666
            area = Area('Text Area')
667
            area.parse(self.ui.textAreaTableWidget.item(row, 0).text())
668
            text_areas.append(area)
669

  
670
        self.newSym = symbol.SymbolBase(fileName, category, convertedThreshold, int(minMatchPoint), True,
671
                                        rotationCount, ocrOption, isContainChild, originalPoint, connectionPoint,
672
                                        baseSymbol, additionalSymbol, isExceptDetect, hasInstrumentLabel, uid,
673
                                        imageWidth, iamgeHeight, detectFlip=detectFlip, text_area=text_areas)
674

  
675
        return self.newSym
678
            QMessageBox.warning(self, self.tr('Warning'), self.tr('Please select symbol category'))
679
            return None
676 680

  
677 681
    '''
678 682
        @brief  Make AdditionalSymbol String
......
726 730
    '''
727 731

  
728 732
    def accept(self):
733
        from SymbolSvgItem import SymbolSvgItem
734

  
729 735
        valid, exceptionMsg = self.isValidSymbolInfo()
730 736
        app_doc_data = AppDocData.instance()
731 737
        if valid:
738
            symbol_data = self.make_symbol_data(self.ui.imageView.image().width(), self.ui.imageView.image().height())
739
            if not symbol_data:
740
                return
741

  
732 742
            if self.selectedSymbol is None:
733
                isSuccess, fileType, SymName, image_file_path = app_doc_data.insertSymbol(
734
                    self.makeSymbolData(self.ui.imageView.image().width(), self.ui.imageView.image().height()))
743
                isSuccess, fileType, SymName, image_file_path = app_doc_data.insertSymbol(symbol_data)
735 744
            else:
736
                isSuccess, fileType, SymName, image_file_path = app_doc_data.updateSymbol(
737
                    self.makeSymbolData(self.ui.imageView.image().width(), self.ui.imageView.image().height()))
745
                isSuccess, fileType, SymName, image_file_path = app_doc_data.updateSymbol(symbol_data)
738 746

  
739 747
            if isSuccess and not self.display:
740 748
                try:
......
759 767
                        potrace.convertImageToSvg(image_file_path, svg_file_path, normalColor=normal_color,
760 768
                                                  hoverColor=hover_color)
761 769

  
770
                        # del document for symbol
771
                        if svg_file_path in SymbolSvgItem.DOCUMENTS:
772
                            del SymbolSvgItem.DOCUMENTS[svg_file_path]
773
                        # up to here
774

  
762 775
                        app_doc_data.update_symbol_shape(SymName, image_file_path, svg_file_path, None)
763 776
                        self.isAccepted = True
764 777
                        if self.ui.checkBoxChange.isChecked():
DTI_PID/DTI_PID/potrace.py
75 75
        svg.append(defs)
76 76
        
77 77
        ''' remove ns0 from xml '''
78
        svgFile = open(destFilePath, 'w')
79
        svgFile.write(ET.tostring(svg, encoding='utf-8').decode('utf-8').replace('ns0:', '').replace(':ns0', ''))
80
        svgFile.close()
78
        with open(destFilePath, 'w') as svgFile:
79
            svgFile.write(ET.tostring(svg, encoding='utf-8').decode('utf-8').replace('ns0:', '').replace(':ns0', ''))
81 80
    except Exception as ex:
82 81
        from App import App
83 82
        from AppDocData import MessageType

내보내기 Unified diff

클립보드 이미지 추가 (최대 크기: 500 MB)