labfreed 0.0.16__py2.py3-none-any.whl → 0.0.17__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,450 @@
1
+ #!/usr/bin/env python
2
+ import typer
3
+ import io
4
+ from rich import print
5
+ from typing_extensions import Annotated
6
+ import numpy as np
7
+ import segno
8
+ from segno import DataOverflowError, writers
9
+ from typing import List
10
+ from enum import Enum
11
+
12
+
13
+
14
+ class Direction(str, Enum):
15
+ LEFT_TO_RIGHT = "LTR"
16
+ TOP_TO_BOTTOM = "TTB"
17
+ RIGHT_TO_LEFT = "RTL"
18
+
19
+ # 5x5 block of bits that can be used to place decoration next to barcode.
20
+ class VisualMarker:
21
+ size = 5
22
+
23
+ def __init__(self, bits):
24
+ # true means 1 bit, false means 0 bit (eg: 1 means black, 0 means white)
25
+ self.bits = bits
26
+
27
+ marker_dict = {
28
+ 'A': bytearray([
29
+ 0x00, 0x01, 0x01, 0x01, 0x00, # preformatted
30
+ 0x01, 0x00, 0x00, 0x00, 0x01,
31
+ 0x01, 0x01, 0x01, 0x01, 0x01,
32
+ 0x01, 0x00, 0x00, 0x00, 0x01,
33
+ 0x01, 0x00, 0x00, 0x00, 0x01,
34
+ ]),
35
+ 'B': bytearray([
36
+ 0x01, 0x01, 0x01, 0x01, 0x00, # preformatted
37
+ 0x01, 0x00, 0x00, 0x00, 0x01,
38
+ 0x01, 0x01, 0x01, 0x01, 0x00,
39
+ 0x01, 0x00, 0x00, 0x00, 0x01,
40
+ 0x01, 0x01, 0x01, 0x01, 0x00,
41
+ ]),
42
+ 'C': bytearray([
43
+ 0x00, 0x01, 0x01, 0x01, 0x01, # preformatted
44
+ 0x01, 0x00, 0x00, 0x00, 0x00,
45
+ 0x01, 0x00, 0x00, 0x00, 0x00,
46
+ 0x01, 0x00, 0x00, 0x00, 0x00,
47
+ 0x00, 0x01, 0x01, 0x01, 0x01,
48
+ ]),
49
+ 'D': bytearray([
50
+ 0x01, 0x01, 0x01, 0x01, 0x00, # preformatted
51
+ 0x01, 0x00, 0x00, 0x00, 0x01,
52
+ 0x01, 0x00, 0x00, 0x00, 0x01,
53
+ 0x01, 0x00, 0x00, 0x00, 0x01,
54
+ 0x01, 0x01, 0x01, 0x01, 0x00,
55
+ ]),
56
+ 'E': bytearray([
57
+ 0x01, 0x01, 0x01, 0x01, 0x01, # preformatted
58
+ 0x01, 0x00, 0x00, 0x00, 0x00,
59
+ 0x01, 0x01, 0x01, 0x01, 0x01,
60
+ 0x01, 0x00, 0x00, 0x00, 0x00,
61
+ 0x01, 0x01, 0x01, 0x01, 0x01,
62
+ ]),
63
+ 'F': bytearray([
64
+ 0x01, 0x01, 0x01, 0x01, 0x01, # preformatted
65
+ 0x01, 0x00, 0x00, 0x00, 0x00,
66
+ 0x01, 0x01, 0x01, 0x01, 0x01,
67
+ 0x01, 0x00, 0x00, 0x00, 0x00,
68
+ 0x01, 0x00, 0x00, 0x00, 0x00,
69
+ ]),
70
+ 'G': bytearray([
71
+ 0x00, 0x01, 0x01, 0x01, 0x01, # preformatted
72
+ 0x01, 0x00, 0x00, 0x00, 0x00,
73
+ 0x01, 0x00, 0x01, 0x01, 0x00,
74
+ 0x01, 0x00, 0x00, 0x00, 0x01,
75
+ 0x00, 0x01, 0x01, 0x01, 0x01,
76
+ ]),
77
+ 'H': bytearray([
78
+ 0x01, 0x00, 0x00, 0x00, 0x01, # preformatted
79
+ 0x01, 0x00, 0x00, 0x00, 0x01,
80
+ 0x01, 0x01, 0x01, 0x01, 0x01,
81
+ 0x01, 0x00, 0x00, 0x00, 0x01,
82
+ 0x01, 0x00, 0x00, 0x00, 0x01,
83
+ ]),
84
+ 'I': bytearray([
85
+ 0x00, 0x00, 0x01, 0x00, 0x00, # preformatted
86
+ 0x00, 0x00, 0x01, 0x00, 0x00,
87
+ 0x00, 0x00, 0x01, 0x00, 0x00,
88
+ 0x00, 0x00, 0x01, 0x00, 0x00,
89
+ 0x00, 0x00, 0x01, 0x00, 0x00,
90
+ ]),
91
+ 'J': bytearray([
92
+ 0x00, 0x00, 0x01, 0x00, 0x00, # preformatted
93
+ 0x00, 0x00, 0x01, 0x00, 0x00,
94
+ 0x00, 0x00, 0x01, 0x00, 0x00,
95
+ 0x00, 0x00, 0x01, 0x00, 0x00,
96
+ 0x00, 0x01, 0x00, 0x00, 0x00,
97
+ ]),
98
+ 'K': bytearray([
99
+ 0x01, 0x00, 0x00, 0x00, 0x01, # preformatted
100
+ 0x01, 0x00, 0x00, 0x01, 0x00,
101
+ 0x01, 0x01, 0x01, 0x00, 0x00,
102
+ 0x01, 0x00, 0x00, 0x01, 0x00,
103
+ 0x01, 0x00, 0x00, 0x00, 0x01,
104
+ ]),
105
+ 'L': bytearray([
106
+ 0x01, 0x00, 0x00, 0x00, 0x00, # preformatted
107
+ 0x01, 0x00, 0x00, 0x00, 0x00,
108
+ 0x01, 0x00, 0x00, 0x00, 0x00,
109
+ 0x01, 0x00, 0x00, 0x00, 0x00,
110
+ 0x01, 0x01, 0x01, 0x01, 0x01,
111
+ ]),
112
+ 'M': bytearray([
113
+ 0x01, 0x01, 0x00, 0x01, 0x01, # preformatted
114
+ 0x01, 0x00, 0x01, 0x00, 0x01,
115
+ 0x01, 0x00, 0x00, 0x00, 0x01,
116
+ 0x01, 0x00, 0x00, 0x00, 0x01,
117
+ 0x01, 0x00, 0x00, 0x00, 0x01,
118
+ ]),
119
+ 'N': bytearray([
120
+ 0x01, 0x00, 0x00, 0x00, 0x01, # preformatted
121
+ 0x01, 0x01, 0x00, 0x00, 0x01,
122
+ 0x01, 0x00, 0x01, 0x00, 0x01,
123
+ 0x01, 0x00, 0x00, 0x01, 0x01,
124
+ 0x01, 0x00, 0x00, 0x00, 0x01,
125
+ ]),
126
+ 'O': bytearray([
127
+ 0x00, 0x01, 0x01, 0x01, 0x00, # preformatted
128
+ 0x01, 0x00, 0x00, 0x00, 0x01,
129
+ 0x01, 0x00, 0x00, 0x00, 0x01,
130
+ 0x01, 0x00, 0x00, 0x00, 0x01,
131
+ 0x00, 0x01, 0x01, 0x01, 0x00,
132
+ ]),
133
+ 'P': bytearray([
134
+ 0x01, 0x01, 0x01, 0x01, 0x00, # preformatted
135
+ 0x01, 0x00, 0x00, 0x00, 0x01,
136
+ 0x01, 0x01, 0x01, 0x01, 0x00,
137
+ 0x01, 0x00, 0x00, 0x00, 0x00,
138
+ 0x01, 0x00, 0x00, 0x00, 0x00,
139
+ ]),
140
+ 'Q': bytearray([
141
+ 0x00, 0x01, 0x01, 0x01, 0x00, # preformatted
142
+ 0x01, 0x00, 0x00, 0x00, 0x01,
143
+ 0x01, 0x00, 0x01, 0x00, 0x01,
144
+ 0x01, 0x00, 0x00, 0x01, 0x00,
145
+ 0x00, 0x01, 0x01, 0x00, 0x01,
146
+ ]),
147
+ 'R': bytearray([
148
+ 0x01, 0x01, 0x01, 0x01, 0x00, # preformatted
149
+ 0x01, 0x00, 0x00, 0x01, 0x00,
150
+ 0x01, 0x01, 0x01, 0x00, 0x00,
151
+ 0x01, 0x00, 0x00, 0x01, 0x00,
152
+ 0x01, 0x00, 0x00, 0x00, 0x01,
153
+ ]),
154
+ 'S': bytearray([
155
+ 0x00, 0x01, 0x01, 0x01, 0x01, # preformatted
156
+ 0x01, 0x00, 0x00, 0x00, 0x00,
157
+ 0x00, 0x01, 0x01, 0x01, 0x00,
158
+ 0x00, 0x00, 0x00, 0x00, 0x01,
159
+ 0x01, 0x01, 0x01, 0x01, 0x00,
160
+ ]),
161
+ 'T': bytearray([
162
+ 0x01, 0x01, 0x01, 0x01, 0x01, # preformatted
163
+ 0x00, 0x00, 0x01, 0x00, 0x00,
164
+ 0x00, 0x00, 0x01, 0x00, 0x00,
165
+ 0x00, 0x00, 0x01, 0x00, 0x00,
166
+ 0x00, 0x00, 0x01, 0x00, 0x00,
167
+ ]),
168
+ 'U': bytearray([
169
+ 0x01, 0x00, 0x00, 0x00, 0x01, # preformatted
170
+ 0x01, 0x00, 0x00, 0x00, 0x01,
171
+ 0x01, 0x00, 0x00, 0x00, 0x01,
172
+ 0x01, 0x00, 0x00, 0x00, 0x01,
173
+ 0x00, 0x01, 0x01, 0x01, 0x00,
174
+ ]),
175
+ 'V': bytearray([
176
+ 0x01, 0x00, 0x00, 0x00, 0x01, # preformatted
177
+ 0x01, 0x00, 0x00, 0x00, 0x01,
178
+ 0x00, 0x01, 0x00, 0x01, 0x00,
179
+ 0x00, 0x01, 0x01, 0x01, 0x00,
180
+ 0x00, 0x00, 0x01, 0x00, 0x00,
181
+ ]),
182
+ 'W': bytearray([
183
+ 0x01, 0x00, 0x00, 0x00, 0x01, # preformatted
184
+ 0x01, 0x00, 0x01, 0x00, 0x01,
185
+ 0x01, 0x00, 0x01, 0x00, 0x01,
186
+ 0x00, 0x01, 0x01, 0x01, 0x00,
187
+ 0x00, 0x01, 0x00, 0x01, 0x00,
188
+ ]),
189
+ 'X': bytearray([
190
+ 0x01, 0x00, 0x00, 0x00, 0x01, # preformatted
191
+ 0x00, 0x01, 0x00, 0x01, 0x00,
192
+ 0x00, 0x00, 0x01, 0x00, 0x00,
193
+ 0x00, 0x01, 0x00, 0x01, 0x00,
194
+ 0x01, 0x00, 0x00, 0x00, 0x01,
195
+ ]),
196
+ 'Y': bytearray([
197
+ 0x01, 0x00, 0x00, 0x00, 0x01, # preformatted
198
+ 0x01, 0x00, 0x00, 0x00, 0x01,
199
+ 0x00, 0x01, 0x01, 0x01, 0x00,
200
+ 0x00, 0x00, 0x01, 0x00, 0x00,
201
+ 0x00, 0x00, 0x01, 0x00, 0x00,
202
+ ]),
203
+ 'Z': bytearray([
204
+ 0x01, 0x01, 0x01, 0x01, 0x01, # preformatted
205
+ 0x00, 0x00, 0x00, 0x01, 0x00,
206
+ 0x00, 0x00, 0x01, 0x00, 0x00,
207
+ 0x00, 0x01, 0x00, 0x00, 0x00,
208
+ 0x01, 0x01, 0x01, 0x01, 0x01,
209
+ ]),
210
+ '0': bytearray([
211
+ 0x00, 0x00, 0x01, 0x00, 0x00, # preformatted
212
+ 0x00, 0x01, 0x00, 0x01, 0x00,
213
+ 0x00, 0x01, 0x00, 0x01, 0x00,
214
+ 0x00, 0x01, 0x00, 0x01, 0x00,
215
+ 0x00, 0x00, 0x01, 0x00, 0x00,
216
+ ]),
217
+ '1': bytearray([
218
+ 0x00, 0x00, 0x01, 0x00, 0x00, # preformatted
219
+ 0x00, 0x01, 0x01, 0x00, 0x00,
220
+ 0x01, 0x00, 0x01, 0x00, 0x00,
221
+ 0x00, 0x00, 0x01, 0x00, 0x00,
222
+ 0x00, 0x00, 0x01, 0x00, 0x00,
223
+ ]),
224
+ '2': bytearray([
225
+ 0x00, 0x01, 0x01, 0x01, 0x00, # preformatted
226
+ 0x01, 0x00, 0x00, 0x00, 0x01,
227
+ 0x00, 0x00, 0x01, 0x01, 0x00,
228
+ 0x00, 0x01, 0x00, 0x00, 0x00,
229
+ 0x01, 0x01, 0x01, 0x01, 0x01,
230
+ ]),
231
+ '3': bytearray([
232
+ 0x01, 0x01, 0x01, 0x01, 0x00, # preformatted
233
+ 0x00, 0x00, 0x00, 0x00, 0x01,
234
+ 0x01, 0x01, 0x01, 0x01, 0x00,
235
+ 0x00, 0x00, 0x00, 0x00, 0x01,
236
+ 0x01, 0x01, 0x01, 0x01, 0x00,
237
+ ]),
238
+ '4': bytearray([
239
+ 0x01, 0x00, 0x00, 0x00, 0x00, # preformatted
240
+ 0x01, 0x00, 0x00, 0x01, 0x00,
241
+ 0x01, 0x01, 0x01, 0x01, 0x01,
242
+ 0x00, 0x00, 0x00, 0x01, 0x00,
243
+ 0x00, 0x00, 0x00, 0x01, 0x00,
244
+ ]),
245
+ '5': bytearray([
246
+ 0x01, 0x01, 0x01, 0x01, 0x01, # preformatted
247
+ 0x01, 0x00, 0x00, 0x00, 0x00,
248
+ 0x01, 0x01, 0x01, 0x01, 0x00,
249
+ 0x00, 0x00, 0x00, 0x00, 0x01,
250
+ 0x01, 0x01, 0x01, 0x01, 0x00,
251
+ ]),
252
+ '6': bytearray([
253
+ 0x00, 0x01, 0x01, 0x01, 0x00, # preformatted
254
+ 0x01, 0x00, 0x00, 0x00, 0x00,
255
+ 0x01, 0x01, 0x01, 0x01, 0x00,
256
+ 0x01, 0x00, 0x00, 0x00, 0x01,
257
+ 0x00, 0x01, 0x01, 0x01, 0x00,
258
+ ]),
259
+ '7': bytearray([
260
+ 0x01, 0x01, 0x01, 0x01, 0x01, # preformatted
261
+ 0x00, 0x00, 0x00, 0x01, 0x00,
262
+ 0x00, 0x00, 0x01, 0x00, 0x00,
263
+ 0x00, 0x01, 0x00, 0x00, 0x00,
264
+ 0x01, 0x00, 0x00, 0x00, 0x00,
265
+ ]),
266
+ '8': bytearray([
267
+ 0x00, 0x01, 0x01, 0x01, 0x00, # preformatted
268
+ 0x01, 0x00, 0x00, 0x00, 0x01,
269
+ 0x00, 0x01, 0x01, 0x01, 0x00,
270
+ 0x01, 0x00, 0x00, 0x00, 0x01,
271
+ 0x00, 0x01, 0x01, 0x01, 0x00,
272
+ ]),
273
+ '9': bytearray([
274
+ 0x00, 0x01, 0x01, 0x01, 0x00, # preformatted
275
+ 0x01, 0x00, 0x00, 0x00, 0x01,
276
+ 0x00, 0x01, 0x01, 0x01, 0x01,
277
+ 0x00, 0x00, 0x00, 0x00, 0x01,
278
+ 0x00, 0x01, 0x01, 0x01, 0x00,
279
+ ]),
280
+ '.': bytearray([
281
+ 0x00, 0x00, 0x00, 0x00, 0x00, # preformatted
282
+ 0x00, 0x00, 0x00, 0x00, 0x00,
283
+ 0x00, 0x00, 0x01, 0x00, 0x00,
284
+ 0x00, 0x00, 0x00, 0x00, 0x00,
285
+ 0x00, 0x00, 0x00, 0x00, 0x00,
286
+ ]),
287
+ ',': bytearray([
288
+ 0x00, 0x00, 0x00, 0x00, 0x00, # preformatted
289
+ 0x00, 0x00, 0x00, 0x00, 0x00,
290
+ 0x00, 0x00, 0x00, 0x00, 0x00,
291
+ 0x00, 0x00, 0x01, 0x00, 0x00,
292
+ 0x00, 0x00, 0x01, 0x00, 0x00,
293
+ ]),
294
+ ':': bytearray([
295
+ 0x00, 0x00, 0x00, 0x00, 0x00, # preformatted
296
+ 0x00, 0x00, 0x01, 0x00, 0x00,
297
+ 0x00, 0x00, 0x00, 0x00, 0x00,
298
+ 0x00, 0x00, 0x00, 0x00, 0x00,
299
+ 0x00, 0x00, 0x01, 0x00, 0x00,
300
+ ]),
301
+ ';': bytearray([
302
+ 0x00, 0x00, 0x00, 0x00, 0x00, # preformatted
303
+ 0x00, 0x00, 0x01, 0x00, 0x00,
304
+ 0x00, 0x00, 0x00, 0x00, 0x00,
305
+ 0x00, 0x00, 0x01, 0x00, 0x00,
306
+ 0x00, 0x00, 0x01, 0x00, 0x00,
307
+ ]),
308
+ '-': bytearray([
309
+ 0x00, 0x00, 0x00, 0x00, 0x00, # preformatted
310
+ 0x00, 0x00, 0x00, 0x00, 0x00,
311
+ 0x00, 0x01, 0x01, 0x01, 0x00,
312
+ 0x00, 0x00, 0x00, 0x00, 0x00,
313
+ 0x00, 0x00, 0x00, 0x00, 0x00,
314
+ ])
315
+ }
316
+
317
+ def generate_from_text(chars: str, direction:Direction, size_in_modules: int):
318
+ # fill up with "."
319
+ squares_cnt = (size_in_modules + 1) // (VisualMarker.size+1)
320
+ leftover = (size_in_modules + 1) % (VisualMarker.size+1)
321
+ if len(chars) < squares_cnt:
322
+ chars = chars + '.' * (squares_cnt - len(chars))
323
+ result: List[bytearray] = []
324
+ for char in chars[:squares_cnt]:
325
+ if char in VisualMarker.marker_dict:
326
+ marker = VisualMarker.marker_dict[char]
327
+ else:
328
+ marker = VisualMarker.marker_dict['.']
329
+ result.append(marker)
330
+ return VisualMarker.generate_from_squares(result, direction, leftover)
331
+
332
+ def generate_from_squares(marker_squares: List[bytearray], direction:Direction, padding_at_end: int):
333
+ # spacer is a column of zeros if RTL/LTR, or a row if TTB/BTT
334
+ axis = 0 if direction == Direction.TOP_TO_BOTTOM else 1
335
+ spacer_dim = (1, VisualMarker.size) if axis==0 else (VisualMarker.size, 1)
336
+ spacer = np.zeros(spacer_dim, dtype=np.uint8)
337
+ result = np.array([])
338
+ for marker in marker_squares:
339
+ if len(marker) != VisualMarker.size*VisualMarker.size:
340
+ raise ValueError("All markers must be 5x5")
341
+
342
+ np_marker = np.array(marker).reshape(VisualMarker.size, VisualMarker.size)
343
+ if result.size == 0:
344
+ # the first item doesn't need a spacer
345
+ result = np_marker
346
+ else:
347
+ # append in direction specified
348
+ if direction == Direction.RIGHT_TO_LEFT:
349
+ result = np.concatenate((np_marker, spacer, result), axis=1)
350
+ else:
351
+ result = np.concatenate((result, spacer, np_marker), axis=axis)
352
+ if(padding_at_end > 0):
353
+ padding_dim = (padding_at_end, VisualMarker.size) if axis==0 else (VisualMarker.size, padding_at_end)
354
+ padding= np.zeros(padding_dim, dtype=np.uint8)
355
+
356
+ # append in direction specified
357
+ if direction == Direction.RIGHT_TO_LEFT:
358
+ result = np.concatenate((padding, result), axis=1)
359
+ else:
360
+ result = np.concatenate((result, padding), axis=axis)
361
+ return result
362
+
363
+
364
+ app = typer.Typer()
365
+
366
+
367
+ def generate_qr_with_markers(url, text="PAC", title=None, direction = Direction.LEFT_TO_RIGHT):
368
+ if title:
369
+ #try to use standard size 10. Go bigger if 10 does not fit the data
370
+ try:
371
+ qr = segno.make_qr(url, error="L", version=10)
372
+ except DataOverflowError as e:
373
+ qr = segno.make_qr(url, error="L")
374
+ v = qr.version
375
+ else:
376
+ qr = segno.make_qr(url, error="L")
377
+ v = qr.version
378
+
379
+ if(qr.mode != "alphanumeric"):
380
+ print("[bold yellow]Large QR:[/bold yellow] Provided URL is not alphanumeric!")
381
+ block_count = len(qr.matrix)
382
+ print(f"[bold]Size:[/bold] {block_count}")
383
+ print(f"[bold]Version:[/bold] {qr.version}")
384
+ print(f"[bold]Error Level:[/bold] {qr.error}")
385
+
386
+
387
+ qr_matrix = np.array(qr.matrix)
388
+ visual_marker = VisualMarker.generate_from_text(text.upper(), direction, block_count)
389
+ if title:
390
+ title_marker = VisualMarker.generate_from_text(title.upper(), direction, block_count)
391
+
392
+ append_axis = 1 if direction == Direction.TOP_TO_BOTTOM else 0
393
+ padding_dim = (4, block_count) if append_axis==0 else (block_count, qr.default_border_size)
394
+ padding= np.zeros(padding_dim, dtype=np.uint8)
395
+ if title:
396
+ combined_matrix = np.concatenate((title_marker, padding, qr_matrix, padding, visual_marker), axis=append_axis)
397
+ else:
398
+ combined_matrix = np.concatenate((qr_matrix, padding, visual_marker), axis=append_axis)
399
+
400
+ return combined_matrix
401
+
402
+ def generate_qr_with_markers_file(url, text="PAC", title=None, direction = Direction.LEFT_TO_RIGHT, fmt='svg', path=str):
403
+ combined_matrix = generate_qr_with_markers(url, text="PAC", title=None, direction = Direction.LEFT_TO_RIGHT)
404
+ outfile = f'{path}.{fmt}'
405
+ match fmt:
406
+ case 'png':
407
+ segno.writers.write_png(combined_matrix, combined_matrix.shape[::-1], out=outfile, border=9)
408
+ case 'svg':
409
+ segno.writers.write_svg(combined_matrix, combined_matrix.shape[::-1], out=outfile, border=9)
410
+
411
+
412
+ def generate_qr_with_markers_uri(url, text="PAC", title=None, direction = Direction.LEFT_TO_RIGHT, fmt='svg'):
413
+ combined_matrix = generate_qr_with_markers(url, text="PAC", title=None, direction = Direction.LEFT_TO_RIGHT)
414
+ match fmt:
415
+ case 'png':
416
+ out = segno.writers.as_png_data_uri(combined_matrix, combined_matrix.shape[::-1], border=9)
417
+ case 'svg':
418
+ out = segno.writers.as_svg_data_uri(combined_matrix, combined_matrix.shape[::-1], border=9)
419
+ return out
420
+
421
+ def generate_qr_with_markers_svg(url, text="PAC", title=None, direction = Direction.LEFT_TO_RIGHT, width=None, height=None, border=9, svg_omitsize=False):
422
+ combined_matrix = generate_qr_with_markers(url, text="PAC", title=None, direction = Direction.LEFT_TO_RIGHT)
423
+ with io.BytesIO() as out:
424
+ version = combined_matrix.shape[::-1]
425
+ scalex = width / (version[0] + 2*border) if width else 1
426
+ scaley = height / (version[1] + 2*border) if height else 1
427
+ scale = min(scalex, scaley)
428
+ segno.writers.write_svg(combined_matrix, version, out, border=border,
429
+ xmldecl=False, svgns=True, scale=scale, omitsize=svg_omitsize
430
+ )
431
+ s = out.getvalue().decode()
432
+ return s
433
+
434
+
435
+
436
+
437
+
438
+ def main(url: Annotated[str, typer.Argument(help="The PAC-ID to be rendered as QR.")],
439
+ outfile: Annotated[typer.FileBinaryWrite, typer.Option(help="The file the qr will be written to.")] = "qr.svg",
440
+ text: Annotated[str, typer.Option(help="The text of the PAC decoration.")] = "PAC",
441
+ direction: Annotated[Direction, typer.Option(help="The position/direction of the PAC decoration.")] = Direction.TOP_TO_BOTTOM):
442
+
443
+ img = generate_qr_with_markers(url, text=text, direction=direction)
444
+ img.save('generated_codes', f"{outfile}.svg", format='svg')
445
+
446
+
447
+
448
+ if __name__ == "__main__":
449
+ typer.run(main)
450
+
labfreed/__init__.py CHANGED
@@ -2,4 +2,4 @@
2
2
  Python implementation of LabFREED building blocks
3
3
  '''
4
4
 
5
- __version__ = "0.0.16"
5
+ __version__ = "0.0.17"
@@ -1,11 +1,15 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: labfreed
3
- Version: 0.0.16
3
+ Version: 0.0.17
4
4
  Summary: Python implementation of LabFREED building blocks
5
5
  Author-email: Reto Thürer <thuerer.r@buchi.com>
6
6
  Description-Content-Type: text/markdown
7
7
  License-Expression: MIT
8
8
  License-File: LICENSE
9
+ Requires-Dist: numpy>=2.2.4
10
+ Requires-Dist: pydantic>=2.11.3
11
+ Requires-Dist: segno>=1.6.6
12
+ Requires-Dist: typer>=0.15.2
9
13
 
10
14
  # LabFREED for Python
11
15
 
@@ -46,10 +50,10 @@ pac_id = PAC_Parser().parse(pac_str).pac_id
46
50
  # Check validity of this PAC-ID
47
51
  pac_id = PAC_Parser().parse(pac_str).pac_id
48
52
  is_valid = pac_id.is_valid()
49
- print('PAC-ID is valid: {is_valid}')
53
+ print(f'PAC-ID is valid: {is_valid}')
50
54
  ```
51
55
  ```text
52
- >> PAC-ID is valid: {is_valid}
56
+ >> [Error during execution: No module named 'quantities']
53
57
  ```
54
58
  ### Show recommendations:
55
59
  Note that the PAC-ID -- while valid -- uses characters which are not recommended (results in larger QR code).
@@ -59,21 +63,7 @@ There is a nice function to highlight problems
59
63
  pac_id.print_validation_messages()
60
64
  ```
61
65
  ```text
62
- >> =======================================
63
- >> Validation Results
64
- >> ---------------------------------------
65
- >>
66
- >> Recommendation in id segment value bal500
67
- >> HTTPS://PAC.METTORIUS.COM/-MD/bal500/@1234
68
- >> Characters a b l should not be used.
69
- >>
70
- >> Recommendation in id segment value @1234
71
- >> HTTPS://PAC.METTORIUS.COM/-MD/bal500/@1234
72
- >> Characters @ should not be used.
73
- >>
74
- >> Warning in Category -MD
75
- >> HTTPS://PAC.METTORIUS.COM/-MD/bal500/@1234
76
- >> Category key -MD is not a well known key. It is recommended to use well known keys only
66
+ >> [Error during execution: name 'pac_id' is not defined]
77
67
  ```
78
68
  ### PAC-CAT
79
69
 
@@ -85,15 +75,7 @@ if isinstance(pac_id, PAC_CAT):
85
75
  pac_id.print_categories()
86
76
  ```
87
77
  ```text
88
- >> Main Category
89
- >> ----------
90
- >> key (): -DR
91
- >> id (21): XQ908756
92
- >> Category
93
- >> ------
94
- >> key (): -MD
95
- >> model_number (240): bal500
96
- >> serial_number (21): @1234
78
+ >> [Error during execution: name 'PAC_Parser' is not defined]
97
79
  ```
98
80
  ### Parse a PAC-ID with extensions
99
81
  PAC-ID can have extensions. Here we parse a PAC-ID with attached display names and summary.
@@ -107,7 +89,7 @@ display_names = pac_id.get_extension('N') # display name has name 'N'
107
89
  print(display_names)
108
90
  ```
109
91
  ```text
110
- >> Display names: My Balance ❤️
92
+ >> [Error during execution: name 'PAC_Parser' is not defined]
111
93
  ```
112
94
  ```python
113
95
  # TREX
@@ -117,7 +99,7 @@ v = trex.get_segment('WEIGHT').to_python_type()
117
99
  print(f'WEIGHT = {v}')
118
100
  ```
119
101
  ```text
120
- >> WEIGHT = 67.89 g
102
+ >> [Error during execution: name 'pac_id' is not defined]
121
103
  ```
122
104
  ### Create a PAC-ID with Extensions
123
105
 
@@ -171,6 +153,9 @@ if trex.get_nested_validation_messages():
171
153
  # Side Note: The TREX can be turned back into a dict
172
154
  d = trex.dict()
173
155
  ```
156
+ ```text
157
+ >> [Error during execution: No module named 'quantities']
158
+ ```
174
159
  #### Combine PAC-ID and TREX and serialize
175
160
 
176
161
  ```python
@@ -181,7 +166,7 @@ pac_str = pac_with_trex.serialize()
181
166
  print(pac_str)
182
167
  ```
183
168
  ```text
184
- >> HTTPS://PAC.METTORIUS:COM/21:1234*DEMO$TREX/STOP$T.D:20240505T1306+TEMP$KEL:10.15+OK$T.B:F+COMMENT$T.A:FOO+COMMENT2$T.T:12G3+TABLE$$DURATION$HUR:DATE$T.D:OK$T.B:COMMENT$T.A::1:20250408T204437.738:T:FOO::1.1:20250408T204437.739:T:BAR::1.3:20250408T204437.739:F:BLUBB
169
+ >> [Error during execution: No module named 'quantities']
185
170
  ```
186
171
  <!-- END EXAMPLES -->
187
172
 
@@ -189,6 +174,9 @@ print(pac_str)
189
174
 
190
175
  ## Change Log
191
176
 
177
+ ### v0.0.17
178
+ - dependencies are installed automatically
179
+
192
180
  ### v0.0.16
193
181
  - supports PAC-ID, PAC-CAT, TREX and DisplayName
194
182
  - ok-ish test coverage
@@ -1,4 +1,4 @@
1
- labfreed/__init__.py,sha256=Bx3Ykihdaac7BJzcEOfffIQE93gFlCOZ5gbFfrusCx8,88
1
+ labfreed/__init__.py,sha256=TAfTqh4FzJOWk9Der7lfe4jqVigI9K9DjkkqD_IkbRk,88
2
2
  labfreed/parse_pac.py,sha256=7y65HO1A3OEr5zftiEtrCaiLLI_8LoRPtQpPcKUNVik,6251
3
3
  labfreed/validation.py,sha256=QwkZWJhAjWbPUZtJJwjVYsw9TxeFhdbZaKjrPPIpuAA,5937
4
4
  labfreed/DisplayNameExtension/DisplayNameExtension.py,sha256=l9JZY2eRS0V-H5h3-WXIHiiBJuljns-_e_t9Bp84_CU,1155
@@ -7,6 +7,7 @@ labfreed/PAC_CAT/data_model.py,sha256=dGwcQGLy1Dk6SFbs9utxKQKm_4ROZrXdv618APlQg7
7
7
  labfreed/PAC_ID/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
8
  labfreed/PAC_ID/data_model.py,sha256=g09qgC-TV6fjJw9VyDF6mTJ6co2i2RKZc0Z-BmiiUIQ,7483
9
9
  labfreed/PAC_ID/extensions.py,sha256=bvuZnlNKUdwsDLrPm8fyifqPn_PR4wCVkkScFnvRiuM,1158
10
+ labfreed/QR_Generator/generate_qr.py,sha256=A4Bw_UESaB_igTDV2Y7a5T7vdz2Sb3yZCfHM0qKnu0M,18091
10
11
  labfreed/TREX/UneceUnits.json,sha256=kwfQSp_nTuWbADfBBgqTWrvPl6XtM5SedEVLbMJrM7M,898953
11
12
  labfreed/TREX/data_model.py,sha256=neKYBc5_S4t-v86DSaWLq81VJF4oS6eFUch3ChPTYJA,29705
12
13
  labfreed/TREX/parse.py,sha256=86962VEJpkrTcT436iFIB5dNed5WHABzpjxRjkA3PXo,2043
@@ -15,7 +16,7 @@ labfreed/utilities/base36.py,sha256=_yX8aQ1OwrK5tnJU1NUEzQSFGr9xAVnNvPObpNzCPYs,
15
16
  labfreed/utilities/extension_intertpreters.py,sha256=B3IFJLfVMJQuPfBBtX6ywlDUZEi7_x6tY4g8V7SpWSs,124
16
17
  labfreed/utilities/utility_types.py,sha256=Zhk8Mu4hHjkn1gs8oh7vOxxaT7L7wLMVG40ZOWCKGK4,2865
17
18
  labfreed/utilities/well_known_keys.py,sha256=nqk66kHdSwJTJfMKlP-xQbBglS8F_NoWsGkfOVITFN0,331
18
- labfreed-0.0.16.dist-info/licenses/LICENSE,sha256=gHFOv9FRKHxO8cInP3YXyPoJnuNeqrvcHjaE_wPSsQ8,1100
19
- labfreed-0.0.16.dist-info/WHEEL,sha256=BXjIu84EnBiZ4HkNUBN93Hamt5EPQMQ6VkF7-VZ_Pu0,100
20
- labfreed-0.0.16.dist-info/METADATA,sha256=XNosyku7BkYyTkg7p1gFADu7xRdp7yWQ1VOucTdODck,5883
21
- labfreed-0.0.16.dist-info/RECORD,,
19
+ labfreed-0.0.17.dist-info/licenses/LICENSE,sha256=gHFOv9FRKHxO8cInP3YXyPoJnuNeqrvcHjaE_wPSsQ8,1100
20
+ labfreed-0.0.17.dist-info/WHEEL,sha256=Dyt6SBfaasWElUrURkknVFAZDHSTwxg3PaTza7RSbkY,100
21
+ labfreed-0.0.17.dist-info/METADATA,sha256=7KTV5v3dGse4ZRIZ6PVMc3fCB3j_Plooq--v9cgKjas,5382
22
+ labfreed-0.0.17.dist-info/RECORD,,
@@ -1,5 +1,5 @@
1
1
  Wheel-Version: 1.0
2
- Generator: flit 3.11.0
2
+ Generator: flit 3.12.0
3
3
  Root-Is-Purelib: true
4
4
  Tag: py2-none-any
5
5
  Tag: py3-none-any