mirror of https://github.com/tuhiproject/tuhi.git
svg: use our Json SVG converter from kete
A few minor changes like passing in a filename and fixing the different spellings of the orientations. In order to use it from kete though we have to mess with the PYTHONPATH. But since it's a in-tree tool only anyway... meh. This loses the ability to disable pressure on tablets. I think that's just a leftover from before we knew how to handle pressure in SVG exports. We should just fix that properly instead of having a config option here. Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>pull/170/head
parent
ac811920b8
commit
64fcf04e32
|
@ -25,11 +25,19 @@ import readline
|
||||||
import struct
|
import struct
|
||||||
import threading
|
import threading
|
||||||
import time
|
import time
|
||||||
import svgwrite
|
|
||||||
import xdg.BaseDirectory
|
import xdg.BaseDirectory
|
||||||
import configparser
|
import configparser
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
|
try:
|
||||||
|
from tuhi.svg import JsonSvg
|
||||||
|
except ModuleNotFoundError:
|
||||||
|
# If PYTHONPATH isn't set up or we never installed Tuhi, the module
|
||||||
|
# isn't available. And since we don't install kete, we can assume that
|
||||||
|
# we're still in the git repo, so messing with the path is "fine".
|
||||||
|
sys.path.insert(0, os.path.dirname(os.path.realpath(__file__)) + '/..') # noqa
|
||||||
|
from tuhi.svg import JsonSvg
|
||||||
|
|
||||||
|
|
||||||
CONFIG_PATH = Path(xdg.BaseDirectory.xdg_data_home, 'tuhi-kete')
|
CONFIG_PATH = Path(xdg.BaseDirectory.xdg_data_home, 'tuhi-kete')
|
||||||
|
|
||||||
|
@ -582,7 +590,6 @@ class Fetcher(Worker):
|
||||||
config[address] = {}
|
config[address] = {}
|
||||||
|
|
||||||
self.orientation = config[address].get('Orientation', 'Landscape')
|
self.orientation = config[address].get('Orientation', 'Landscape')
|
||||||
self.handle_pressure = config[address].getboolean('HandlePressure', False)
|
|
||||||
|
|
||||||
for d in manager.devices:
|
for d in manager.devices:
|
||||||
if d.address == address:
|
if d.address == address:
|
||||||
|
@ -614,74 +621,9 @@ class Fetcher(Worker):
|
||||||
t = time.localtime(data['timestamp'])
|
t = time.localtime(data['timestamp'])
|
||||||
t = time.strftime('%Y-%m-%d-%H-%M', t)
|
t = time.strftime('%Y-%m-%d-%H-%M', t)
|
||||||
path = f'{data["devicename"]}-{t}.svg'
|
path = f'{data["devicename"]}-{t}.svg'
|
||||||
self.json_to_svg(data, path)
|
JsonSvg(data, self.orientation, filename=path)
|
||||||
logger.info(f'{data["devicename"]}: saved file "{path}"')
|
logger.info(f'{data["devicename"]}: saved file "{path}"')
|
||||||
|
|
||||||
def json_to_svg(self, js, filename):
|
|
||||||
dimensions = js['dimensions']
|
|
||||||
if dimensions == [0, 0]:
|
|
||||||
width, height = 100, 100
|
|
||||||
else:
|
|
||||||
# Original dimensions are too big for SVG Standard
|
|
||||||
# so we normalize them to mm
|
|
||||||
width, height = dimensions[0] / 1000, dimensions[1] / 1000
|
|
||||||
|
|
||||||
if self.orientation in ['Portrait', 'Reverse-Portrait']:
|
|
||||||
svg = svgwrite.Drawing(filename=filename, size=(height, width))
|
|
||||||
else:
|
|
||||||
svg = svgwrite.Drawing(filename=filename, size=(width, height))
|
|
||||||
|
|
||||||
g = svgwrite.container.Group(id='layer0')
|
|
||||||
for stroke_num, s in enumerate(js['strokes']):
|
|
||||||
|
|
||||||
points_with_sk_width = []
|
|
||||||
|
|
||||||
for p in s['points']:
|
|
||||||
|
|
||||||
x, y = p['position']
|
|
||||||
# Normalize coordinates too
|
|
||||||
x, y = x / 1000, y / 1000
|
|
||||||
|
|
||||||
if self.orientation == 'Reverse-Portrait':
|
|
||||||
x, y = y, width - x
|
|
||||||
elif self.orientation == 'Portrait':
|
|
||||||
x, y = height - y, x
|
|
||||||
elif self.orientation == 'Reverse-Landscape':
|
|
||||||
x, y = width - x, height - y
|
|
||||||
|
|
||||||
# Pressure normalized range is [0, 0xffff]
|
|
||||||
delta = (p['pressure'] - 0x8000) / 0x8000
|
|
||||||
stroke_width = 0.4 + 0.20 * delta
|
|
||||||
points_with_sk_width.append((x, y, stroke_width))
|
|
||||||
|
|
||||||
if self.handle_pressure:
|
|
||||||
lines = svgwrite.container.Group(id=f'strokes_{stroke_num}', stroke='black')
|
|
||||||
for i, (x, y, stroke_width) in enumerate(points_with_sk_width):
|
|
||||||
if i != 0:
|
|
||||||
xp, yp, stroke_width_p = points_with_sk_width[i - 1]
|
|
||||||
lines.add(
|
|
||||||
svg.line(
|
|
||||||
start=(xp, yp),
|
|
||||||
end=(x, y),
|
|
||||||
stroke_width=stroke_width,
|
|
||||||
style='fill:none'
|
|
||||||
)
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
lines = svgwrite.path.Path(
|
|
||||||
d="M",
|
|
||||||
stroke='black',
|
|
||||||
stroke_width=0.2,
|
|
||||||
style='fill:none'
|
|
||||||
)
|
|
||||||
for x, y, stroke_width in points_with_sk_width:
|
|
||||||
lines.push(x, y)
|
|
||||||
|
|
||||||
g.add(lines)
|
|
||||||
|
|
||||||
svg.add(g)
|
|
||||||
svg.save()
|
|
||||||
|
|
||||||
|
|
||||||
class LiveChanger(Worker):
|
class LiveChanger(Worker):
|
||||||
def __init__(self, manager, args):
|
def __init__(self, manager, args):
|
||||||
|
|
|
@ -14,12 +14,17 @@
|
||||||
from gettext import gettext as _
|
from gettext import gettext as _
|
||||||
from gi.repository import GObject, Gtk, GdkPixbuf, Gdk
|
from gi.repository import GObject, Gtk, GdkPixbuf, Gdk
|
||||||
|
|
||||||
|
import xdg.BaseDirectory
|
||||||
|
import os
|
||||||
|
from pathlib import Path
|
||||||
from .config import Config
|
from .config import Config
|
||||||
from tuhi.svg import JsonSvg
|
from tuhi.svg import JsonSvg
|
||||||
|
|
||||||
import gi
|
import gi
|
||||||
gi.require_version("Gtk", "3.0")
|
gi.require_version("Gtk", "3.0")
|
||||||
|
|
||||||
|
DATA_PATH = Path(xdg.BaseDirectory.xdg_cache_home, 'tuhi', 'svg')
|
||||||
|
|
||||||
|
|
||||||
@Gtk.Template(resource_path='/org/freedesktop/Tuhi/ui/Drawing.ui')
|
@Gtk.Template(resource_path='/org/freedesktop/Tuhi/ui/Drawing.ui')
|
||||||
class Drawing(Gtk.EventBox):
|
class Drawing(Gtk.EventBox):
|
||||||
|
@ -34,6 +39,7 @@ class Drawing(Gtk.EventBox):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.orientation = Config.instance().orientation
|
self.orientation = Config.instance().orientation
|
||||||
Config.instance().connect('notify::orientation', self._on_orientation_changed)
|
Config.instance().connect('notify::orientation', self._on_orientation_changed)
|
||||||
|
DATA_PATH.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
self.json_data = json_data
|
self.json_data = json_data
|
||||||
self._zoom = 0
|
self._zoom = 0
|
||||||
|
@ -47,7 +53,8 @@ class Drawing(Gtk.EventBox):
|
||||||
self.refresh()
|
self.refresh()
|
||||||
|
|
||||||
def refresh(self):
|
def refresh(self):
|
||||||
self.svg = JsonSvg(self.json_data, self.orientation)
|
path = os.fspath(Path(DATA_PATH, f'{self.json_data["timestamp"]}.svg'))
|
||||||
|
self.svg = JsonSvg(self.json_data, self.orientation, path)
|
||||||
width, height = -1, -1
|
width, height = -1, -1
|
||||||
if 'portrait' in self.orientation:
|
if 'portrait' in self.orientation:
|
||||||
height = 1000
|
height = 1000
|
||||||
|
|
15
tuhi/svg.py
15
tuhi/svg.py
|
@ -13,24 +13,17 @@
|
||||||
|
|
||||||
from gi.repository import GObject
|
from gi.repository import GObject
|
||||||
|
|
||||||
import xdg.BaseDirectory
|
|
||||||
import svgwrite
|
import svgwrite
|
||||||
import os
|
|
||||||
from pathlib import Path
|
|
||||||
from svgwrite import mm
|
from svgwrite import mm
|
||||||
|
|
||||||
DATA_PATH = Path(xdg.BaseDirectory.xdg_cache_home, 'tuhi', 'svg')
|
|
||||||
|
|
||||||
|
|
||||||
class JsonSvg(GObject.Object):
|
class JsonSvg(GObject.Object):
|
||||||
def __init__(self, json, orientation, *args, **kwargs):
|
def __init__(self, json, orientation, filename, *args, **kwargs):
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
self.json = json
|
self.json = json
|
||||||
DATA_PATH.mkdir(parents=True, exist_ok=True)
|
|
||||||
|
|
||||||
self.timestamp = json['timestamp']
|
self.timestamp = json['timestamp']
|
||||||
self.filename = os.fspath(Path(DATA_PATH, f'{self.timestamp}.svg'))
|
self.filename = filename
|
||||||
self.orientation = orientation
|
self.orientation = orientation.lower()
|
||||||
self._convert()
|
self._convert()
|
||||||
|
|
||||||
def _convert(self):
|
def _convert(self):
|
||||||
|
@ -43,7 +36,7 @@ class JsonSvg(GObject.Object):
|
||||||
# so we normalize them
|
# so we normalize them
|
||||||
width, height = dimensions[0] / 1000, dimensions[1] / 1000
|
width, height = dimensions[0] / 1000, dimensions[1] / 1000
|
||||||
|
|
||||||
if self.orientation in ['portrait', 'reverse-Portrait']:
|
if self.orientation in ['portrait', 'reverse-portrait']:
|
||||||
size = (height * mm, width * mm)
|
size = (height * mm, width * mm)
|
||||||
else:
|
else:
|
||||||
size = (width * mm, height * mm)
|
size = (width * mm, height * mm)
|
||||||
|
|
Loading…
Reference in New Issue