-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsvgtemplate.py
138 lines (115 loc) · 4.56 KB
/
svgtemplate.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
#!/usr/bin/env python3
import os
from itertools import zip_longest
import xml.etree.ElementTree as ET
import subprocess
from collections import namedtuple
class SVGTemplate:
"""Template SVG customizing some fields."""
def __init__(self, tpl, outdir):
self.tpl = ET.parse(tpl)
self.outdir = outdir
def patch(self, record, modifier):
"""Patch SVG using modifier function."""
self.record = record
for f, v in zip(record._fields, record):
tag = self.tpl.find('.//*[@id="{}"]'.format(f))
modifier(tag, v)
def write(self, outfname=None):
"""
Write patched SVG either to outfname if set, or to file name
generated by fnamegen class property.
Return outfname.
"""
fname = outfname if outfname else self.fnamegen(self.record)
with open(os.path.join(self.outdir, fname), 'wb') as outf:
self.tpl.write(outf, encoding='utf-8', xml_declaration=True)
return fname
def template(self, record, modifier, outfname=None):
"""
Template SVG using modifier function.
Write it either to outfname if set, or to file name
generated by fnamegen class property.
Return outfname.
"""
self.patch(record, modifier)
return self.write(outfname)
@staticmethod
def textmodifier(tag, v):
tag.text = v
@staticmethod
def xlinkmodifier(tag, v):
tag.set('{http://www.w3.org/1999/xlink}href', v)
def templatetext(self, record, outfname=None):
"""Template SVG text"""
return self.template(record, self.textmodifier, outfname)
def templatexlink(self, record, outfname=None):
"""Template SVG xlink"""
return self.template(record, self.xlinkmodifier, outfname)
def reordercards(cards, rows=4, sheetrows=9, sheetcols=3, dummycard=""):
"""
Reorder items in a way their ordering
spans across ROWS rows of paper sheets.
Fill empty positions with dummy cards.
[0:8] [36:44] [72:80] <- first sheet
[9:17] [45:53] [81:89] <- second sheet
[18:26] [54:62] [90:98]
[27:35] [63:71] [99:107]
"""
module = rows * sheetrows * sheetcols
cardsets = zip_longest(*[iter(cards)] * module, fillvalue=dummycard)
for s in cardsets:
for row in range(rows):
rowoffset = row * sheetrows
for sheetcol in range(sheetcols):
coloffset = sheetcol * sheetrows * rows
for sheetrow in range(sheetrows):
yield s[rowoffset + coloffset + sheetrow]
def gensheets(cards, layout, dummycard="", rows=4, ncards=27):
"""Put ncards cards on a sheet. Fill the rest of sheet with dummy cards.
Align cards into column, considering rows of subsequent sheets.
Arguments:
cards -- an array of SVG file names of cards
layout -- SVGTemplate() instance of the form layout
dummycard -- name of card to fill empty spaces with
rows -- number of sheet rows (used just for annotation)
ncards -- number of cards per sheet
"""
Sheet = namedtuple('Sheet', ['pos{}'.format(x) for x in range(ncards)])
Annotation = namedtuple('Annotation', 'annotation')
sheets = []
cardsets = zip_longest(*[iter(cards)] * ncards, fillvalue=dummycard)
for i, cardset in enumerate(cardsets):
fname = "sheet{:02d}.svg".format(i+1)
annotation = "Row: {} Col: {:02}".format(i % rows + 1, i // rows + 1)
sheet = Sheet(*[c + "#layer1" for c in cardset])
layout.patch(sheet, SVGTemplate.xlinkmodifier)
layout.patch(Annotation(annotation), SVGTemplate.textmodifier)
layout.write(fname)
sheets.append(fname)
return sheets
def pdfsheets(sheets):
"""Convert SVG sheets to PDF using Inkscape batch mode.
Arguments:
sheets -- list of SVG file names
"""
isscript = []
for fname in sheets:
isscript.append(f'file-open:{fname}')
isscript.append('export-type:pdf')
isscript.append(f'export-filename:{fname[:-3]}pdf')
isscript.append('export-do')
isscript.append('file-close')
isscript.append("quit\n")
isscript = "\n".join(isscript).encode("utf-8")
subprocess.check_output(['inkscape', '--shell'], input=isscript)
def pdfunite(sheets, output):
"""Unite PDF files into one.
Arguments:
sheets -- list of SVG file names (.pdf files are expected instead)
output -- name of output file
"""
cmd = ['pdfunite']
cmd.extend(s.replace('.svg', '.pdf') for s in sheets)
cmd.append(output)
subprocess.check_output(cmd)