From ea70d9278ecb93e3d550f8cf66069d19ac52e729 Mon Sep 17 00:00:00 2001 From: Joeri Exelmans Date: Fri, 3 Mar 2023 15:53:07 +0100 Subject: [PATCH] Simplify abstract syntax further. Added OML exporter and test. --- default.nix | 9 ---- shell.nix | 15 ++++++ src/xopp2py/abstract_syntax.py | 18 ++++---- src/xopp2py/main.py | 17 ++++++- src/xopp2py/parser.py | 22 +++++---- src/xopp2py_oml/__init__.py | 0 src/xopp2py_oml/oml_writer.py | 18 ++++++++ src/xopp2py_oml/oml_writer.template | 68 ++++++++++++++++++++++++++++ tests/data/SmallXournalFile.xopp | Bin 0 -> 3570 bytes tests/data/TwoHiddenLayers.xopp | Bin 0 -> 15544 bytes tests/test_xopp2py.py | 17 +++++++ 11 files changed, 155 insertions(+), 29 deletions(-) delete mode 100644 default.nix create mode 100644 shell.nix create mode 100644 src/xopp2py_oml/__init__.py create mode 100644 src/xopp2py_oml/oml_writer.py create mode 100644 src/xopp2py_oml/oml_writer.template create mode 100644 tests/data/SmallXournalFile.xopp create mode 100644 tests/data/TwoHiddenLayers.xopp create mode 100644 tests/test_xopp2py.py diff --git a/default.nix b/default.nix deleted file mode 100644 index 172b408..0000000 --- a/default.nix +++ /dev/null @@ -1,9 +0,0 @@ -with import {}; -with pkgs.python3Packages; - -buildPythonPackage { - name = "xopp2py"; - src = ./.; - format = "pyproject"; # tell Nix to use pyproject.toml - propagatedBuildInputs = [ hatchling ]; -} \ No newline at end of file diff --git a/shell.nix b/shell.nix new file mode 100644 index 0000000..2416a4a --- /dev/null +++ b/shell.nix @@ -0,0 +1,15 @@ +# Generates a shell from where all the dependencies can be found. + +{ pkgs ? import {} }: + +let + SOURCE_DIR = builtins.toString ./src; +in + pkgs.mkShell { + buildInputs = [ + pkgs.python3 + pkgs.python3Packages.jinja2 + ]; + + PYTHONPATH = SOURCE_DIR; + } \ No newline at end of file diff --git a/src/xopp2py/abstract_syntax.py b/src/xopp2py/abstract_syntax.py index c627c6b..168ac86 100644 --- a/src/xopp2py/abstract_syntax.py +++ b/src/xopp2py/abstract_syntax.py @@ -3,20 +3,14 @@ from dataclasses import dataclass from decimal import Decimal -@dataclass -class Background: - type: str # could be enum - color: str # could be class - style: str # could be enum - @dataclass class Stroke: - values: str # Just the XML text in between the tags. Meaning: stroke positions. + text: str # Just the XML text in between the tags. Meaning: stroke positions. attributes: dict[str,str] # just the XML attributes as encountered @dataclass class Text: - text: str + text: str # Just the XML text between the tags. Meaning: the text contents of the text element attributes: dict[str,str] # just the XML attributes as encountered @dataclass @@ -27,7 +21,11 @@ class Layer: class Page: width: Decimal height: Decimal - background: Background + + background_type: str # could be enum + background_color: str # could be class + background_style: str # could be enum + layers: list[Layer] @dataclass @@ -35,5 +33,5 @@ class XournalFile: creator: str # e.g., "Xournal++ 1.1.2" fileversion: int # e.g., 4 title: str # obscure feature - preview: bytes # PNG-encoded preview of the (first page) of the file + preview: bytes | None # PNG-encoded preview of the (first page) of the file pages: list[Page] \ No newline at end of file diff --git a/src/xopp2py/main.py b/src/xopp2py/main.py index 2a44cae..f11d87c 100644 --- a/src/xopp2py/main.py +++ b/src/xopp2py/main.py @@ -6,7 +6,20 @@ if __name__ == "__main__": argparser = argparse.ArgumentParser( description = "Python interface for Xournal++ (.xopp) files.") argparser.add_argument('filename') + argparser.add_argument('--print-oml', action='store_true', help="Convert to OML and print") + argparser.add_argument('--write-oml', metavar='FILE', nargs=1, help="Convert to OML and write to file") args = argparser.parse_args() # exits on error - from parser import parseFile - print(parseFile(args.filename)) + print(args) + + from xopp2py import parser + + asyntax = parser.parseFile(args.filename) + if args.print_oml: + from xopp2py_oml import oml_writer + import sys + oml_writer.writeOML(asyntax, args.filename, "my_xopp", sys.stdout) + elif args.write_oml != None: + from xopp2py_oml import oml_writer + with open(args.write_oml[0], 'wt') as f: + oml_writer.writeOML(asyntax, args.filename, "my_xopp", f) \ No newline at end of file diff --git a/src/xopp2py/parser.py b/src/xopp2py/parser.py index 6b9649c..f73711b 100644 --- a/src/xopp2py/parser.py +++ b/src/xopp2py/parser.py @@ -1,4 +1,4 @@ -import abstract_syntax +from xopp2py import abstract_syntax def parseFile(path) -> abstract_syntax.XournalFile: """Parse a .xopp file.""" @@ -14,7 +14,7 @@ def parseFile(path) -> abstract_syntax.XournalFile: elif element.tag == "stroke": elements.append( abstract_syntax.Stroke( - values=element.text, attributes=element.attrib)) + text=element.text, attributes=element.attrib)) else: raise Error("Unsupported tag:" + element.tag) elif event == "end": @@ -29,10 +29,9 @@ def parseFile(path) -> abstract_syntax.XournalFile: for (event, element) in context: if event == "start": if element.tag == "background": - background = abstract_syntax.Background( - type=element.get("type"), - color=element.get("color"), - style=element.get("plain")) + background_type = element.get("type") + background_color = element.get("color") + background_style = element.get("style") elif element.tag == "layer": layers.append(parseLayer(context)) else: @@ -42,7 +41,9 @@ def parseFile(path) -> abstract_syntax.XournalFile: return abstract_syntax.Page( width=width, height=height, - background=background, + background_type=background_type, + background_color=background_color, + background_style=background_style, layers=layers) def parseXournal(context): @@ -56,7 +57,10 @@ def parseFile(path) -> abstract_syntax.XournalFile: title = element.text elif element.tag == "preview": import base64 - preview = base64.b64decode(element.text) + if element.text != None: + preview = base64.b64decode(element.text) + else: + preview = None elif element.tag == "page": pages.append(parsePage(element, context)) else: @@ -70,6 +74,8 @@ def parseFile(path) -> abstract_syntax.XournalFile: pages=pages) import gzip + # with gzip.open(path, mode='rt') as f: + # print(f.read()) with gzip.open(path, mode='rt') as f: from xml.etree import ElementTree context = ElementTree.iterparse(f, events=["start", "end"]) diff --git a/src/xopp2py_oml/__init__.py b/src/xopp2py_oml/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/xopp2py_oml/oml_writer.py b/src/xopp2py_oml/oml_writer.py new file mode 100644 index 0000000..d13ad1d --- /dev/null +++ b/src/xopp2py_oml/oml_writer.py @@ -0,0 +1,18 @@ +from xopp2py import abstract_syntax +import io + +def writeOML(xournalFile: abstract_syntax.XournalFile, inputfile:str, namespace:str, ostream: io.TextIOBase): + import jinja2 + import os + import base64 + + environment = jinja2.Environment( + loader=jinja2.FileSystemLoader(os.path.dirname(__file__))) + + template = environment.get_template("oml_writer.template") + for piece in template.generate( + file=xournalFile, + toBase64=base64.b64encode, + inputfile=inputfile, + namespace=namespace): + ostream.write(piece) diff --git a/src/xopp2py_oml/oml_writer.template b/src/xopp2py_oml/oml_writer.template new file mode 100644 index 0000000..ca636a5 --- /dev/null +++ b/src/xopp2py_oml/oml_writer.template @@ -0,0 +1,68 @@ +{%- macro attributes(pageindex, page, layerindex, layer, elementindex, element) -%} +{%- for key,value in element.attributes.items() %} + ci p{{pageindex}}l{{layerindex}}e{{elementindex}}a{{loop.index}} : xournalpp:XMLAttribute [ + xournalpp:hasKey "{{key}}" + xournalpp:hasValue "{{value}}" + xournalpp:ofLayerElement p{{pageindex}}l{{layerindex}}e{{elementindex}} + object_diagram:inModel model + ] +{% endfor %} +{%- endmacro -%} + +{%- macro elements(pageindex, page, layerindex, layer) -%} +{% for el in layer.elements %} + ci p{{pageindex}}l{{layerindex}}e{{loop.index}} : xournalpp:{{el.__class__.__name__}} [ + xournalpp:hasText "{{el.text}}" + xournalpp:inLayer p{{pageindex}}l{{layerindex}} + object_diagram:inModel model + ] + {{ attributes(pageindex, page, layerindex, layer, loop.index, el) -}} +{% endfor %} +{%- endmacro -%} + +{%- macro layers(pageindex, page) -%} +{% for layer in page.layers %} + ci p{{pageindex}}l{{loop.index}} : xournalpp:Layer [ + xournalpp:inPage p{{pageindex}} + object_diagram:inModel model + ] + {{ elements(pageindex, page, loop.index, layer) -}} +{% endfor %} +{%- endmacro -%} + +{%- macro pages(file) -%} +{% for page in file.pages -%} + ci p{{loop.index}} : xournalpp:Page [ + xournalpp:hasWidth {{ page.width }} + xournalpp:hasHeight {{ page.height }} + xournalpp:hasBackgroundType "{{ page.background_type }}" + xournalpp:hasBackgroundColor "{{ page.background_color }}" + xournalpp:hasBackgroundStyle "{{ page.background_style }}" + xournalpp:inFile file + object_diagram:inModel model + ] + {{ layers(loop.index, page) -}} +{%- endfor %} +{%- endmacro -%} +// Warning: Generated code! Do not edit! +// Input file: '{{inputfile}}' +// Generator: https://msdl.uantwerpen.be/git/jexelmans/xopp2py +description as {{namespace}} { + + uses as xournalpp + uses as object_diagram + + ci model : xournalpp:Model [] + + ci file : xournalpp:File [ + xournalpp:hasCreator "{{ file.creator }}" + xournalpp:hasFileVersion {{ file.fileversion }} + xournalpp:hasTitle "{{ file.title }}" + {%- if file.preview != None %} + xournalpp:hasPreview "{{ toBase64(file.preview).decode('utf-8') }}" + {%- endif %} + object_diagram:inModel model + ] + + {{ pages(file) }} +} diff --git a/tests/data/SmallXournalFile.xopp b/tests/data/SmallXournalFile.xopp new file mode 100644 index 0000000000000000000000000000000000000000..44e802ee8ee54cb0f66ba1b17d2adc00c26bad4c GIT binary patch literal 3570 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 literal 0 HcmV?d00001 diff --git a/tests/data/TwoHiddenLayers.xopp b/tests/data/TwoHiddenLayers.xopp new file mode 100644 index 0000000000000000000000000000000000000000..4d17d26e1df8477348885cd4982f03dcb6b00e97 GIT binary patch literal 15544 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