-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathorxport.py
executable file
·288 lines (219 loc) · 8.57 KB
/
orxport.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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
#!/usr/bin/env python3
import getopt
import os
import sys
import emoji
import export
import jsonutils
import log
import orx.manifest
import orx.params
from cache import Cache
VERSION = '0.5.0'
RENDERERS = ['inkscape', 'resvg', 'imagemagick']
DEF_INPUT = 'in'
DEF_MANIFEST = 'manifest.orx'
DEF_OUTPUT = 'out'
DEF_OUTPUT_NAMING = '%f/%s'
DEF_OUTPUT_FORMATS = ['svg']
DEF_LICENSE_ENABLED = True
DEF_PARAMS = 'parameters.orx'
DEF_NUM_THREADS = 1
DEF_RENDERER = 'inkscape'
DEF_MAX_BATCH = 1000
HELP = f'''orxporter {VERSION}
by Mutant Standard
(mutant.tech)
USAGE: orxport.py [options...]
HELP:
----------------------------------------------------
-h Prints this help message.
Also look at /docs for full documentation.
INPUT AND OUTPUT:
----------------------------------------------------
-i Input images (default: {DEF_INPUT})
-m Manifest file (default: {DEF_MANIFEST})
-o Output directory (default: {DEF_OUTPUT})
IMAGE BUILD:
----------------------------------------------------
-F Format (default: {DEF_OUTPUT_FORMATS[0]})
comma separated with no spaces (ie. 'svg,png-64,jxl-128')
- svg (SVG)
- png-SIZE (PNG)
- pngc-SIZE (Crushed PNG)
- jxl-SIZE (Lossless JPEG XL)
- webp-SIZE (Lossless WebP)
-f Directory/filename naming system for output (default: {DEF_OUTPUT_NAMING})
See the documentation for how this works.
-r SVG renderer (default: {DEF_RENDERER})
- resvg
- imagemagick
- inkscape
-l Do not embed license metadata given in manifest
-p Parameters file
You can attach a parameters file instead of doing the 4 flags above.
Adding this will overwrite anything entered in the previous 4 flags.
-t Number of threads working on export tasks (default: {DEF_NUM_THREADS})
-C Cache directory
Uses the argument as the directory for the export cache.
JSON BUILD:
----------------------------------------------------
-j <FILE> export JSON replica of directory structure
-J <FILE> export JSON metadata for mutstd website
Using JSON flags will override any image build flags, so run image and JSON builds separately.
OTHER OPTIONS:
----------------------------------------------------
-e <FILTER> emoji filter
-q <WIDTHxHEIGHT> ensure source images have certain size
-b <NUM> maximum files per exiftool call (default: {DEF_MAX_BATCH})
--force-desc ensure all emoji have a text description
TERMINAL OPTIONS:
----------------------------------------------------
-c disable ANSI color codes
--verbose verbose printing
'''
def main():
input_path = DEF_INPUT
manifest_path = DEF_MANIFEST
output_path = DEF_OUTPUT
output_naming = DEF_OUTPUT_NAMING
output_formats = DEF_OUTPUT_FORMATS
renderer = DEF_RENDERER
license_enabled = DEF_LICENSE_ENABLED
params_path = None
emoji_filter = []
emoji_filter_text = "" # for error messaging only
json_out = None
json_web_out = None
src_size = None
num_threads = DEF_NUM_THREADS
force_desc = False
max_batch = DEF_MAX_BATCH
cache = False
verbose = False
try:
opts, _ = getopt.getopt(sys.argv[1:],
'hm:i:o:f:F:ce:j:J:q:t:r:b:p:lC:',
['help', 'force-desc', 'verbose'])
for opt, arg in opts:
if opt in ['-h', '--help']:
print(HELP)
sys.exit()
# basics
elif opt == '-m':
manifest_path = arg
elif opt == '-i':
input_path = arg
elif opt == '-o':
output_path = arg
# images
elif opt == '-F':
output_formats = arg.split(',')
elif opt == '-f':
output_naming = arg
elif opt == '-r':
renderer = arg
elif opt == '-l':
license_enabled = False
elif opt == '-p':
params_path = arg
elif opt == '-t':
num_threads = int(arg)
if num_threads <= 0:
raise ValueError
elif opt == '-C':
cache = Cache(cache_dir=arg)
# JSON
elif opt == '-j':
json_out = arg
elif opt == '-J':
json_web_out = arg
# other emoji stuff
elif opt == '-e':
k, v = arg.split('=')
v = v.split(',')
emoji_filter.append((k, v))
emoji_filter_text = arg
elif opt == '-q':
t1, t2 = arg.split('x')
src_size = int(t1), int(t2)
elif opt == '-b':
max_batch = int(arg)
if max_batch <= 0:
raise ValueError
elif opt == '--force-desc':
force_desc = True
# terminal stuff
elif opt == '-c':
log.use_color = False
elif opt == '--verbose':
verbose = True
except Exception as e:
log.out(f'x∆∆x {e}\n', 31)
sys.exit(2)
# try to get all of the basic stuff and do the main execution
# -----------------------------------------------------------
try:
log.out(f'o∆∆o', 32) #hello
# validate basic input that can't be checked while in progress
if renderer not in RENDERERS:
raise Exception(f"There's a mistake in your command arguments. '{renderer}' is not a renderer you can use in orxporter.")
# create a Manifest
# ie. parse the manifest file and get the information we need from it
log.out(f'Loading manifest file...', 36)
m = orx.manifest.Manifest(os.path.dirname(manifest_path),
os.path.basename(manifest_path))
log.out(f'-> {len(m.emoji)} emoji defined.')
# filter emoji (if any filter is present)
filtered_emoji = [e for e in m.emoji if emoji.match(e, emoji_filter)]
if emoji_filter:
if filtered_emoji: # if more than 0
log.out(f'-> {len(filtered_emoji)} / {len(m.emoji)} emoji match the filter you gave.', 34)
else:
raise ValueError(f"Your filter ('{emoji_filter_text}') returned no results.")
# ensure that descriptions are present if --force-desc flag is there
if force_desc:
nondesc = [e.get('code', str(e)) for e in filtered_emoji if 'desc' not in e]
if nondesc:
raise ValueError('You have emoji without a description: ' +
', '.join(nondesc))
# JSON out or image out
if json_out:
jsonutils.write_emoji(filtered_emoji, json_out)
elif json_web_out:
jsonutils.write_web(filtered_emoji, json_web_out)
else:
if params_path:
log.out(f'Loading image export parameters...', 36)
p = orx.params.Parameters(os.path.dirname(params_path),
os.path.basename(params_path))
else:
# convert the non-parameter flags into an orx expression to be turned into a parameters object.
log.out(f'Compiling image export parameters...', 36)
license_text=""
if license_enabled == True:
license_text = "yes"
else:
license_text = "no"
makeshift_params = f"dest structure = {output_naming} format = {' '.join(output_formats)} license = {license_text}"
p = orx.params.Parameters(string = makeshift_params)
path = os.path.join(output_path, output_naming)
log.out(f'{len(p.dests)} destination(s) defined.', 32)
log.out(f"-> {', '.join(output_formats)}") # print formats
log.out(f"-> to '{path}'") # print out path
export.export(m, filtered_emoji, input_path, output_formats,
path, src_size,
num_threads, renderer, max_batch, verbose,
license_enabled, cache)
except (KeyboardInterrupt, SystemExit) as e:
log.out(f'>∆∆< Cancelled!\n{e}', 93)
sys.exit(1)
# Where all the exceptions eventually go~
except Exception as e:
log.out(f'x∆∆x {e}\n', 31)
raise e # TEMP: for developer stuff
sys.exit(1)
# yay! finished!
log.out('All done! ^∆∆^\n', 32) # goodbye
if __name__ == '__main__':
main()