pybarcodes 1.0.2__tar.gz → 1.2.1__tar.gz
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.
- {pybarcodes-1.0.2 → pybarcodes-1.2.1}/PKG-INFO +13 -15
- {pybarcodes-1.0.2 → pybarcodes-1.2.1}/README.rst +2 -2
- {pybarcodes-1.0.2 → pybarcodes-1.2.1}/pybarcodes/__init__.py +1 -1
- pybarcodes-1.2.1/pybarcodes/barcode.py +311 -0
- {pybarcodes-1.0.2 → pybarcodes-1.2.1}/pybarcodes/codes.py +70 -61
- {pybarcodes-1.0.2 → pybarcodes-1.2.1}/pybarcodes/ean.py +41 -35
- pybarcodes-1.2.1/pybarcodes.egg-info/PKG-INFO +135 -0
- pybarcodes-1.2.1/pybarcodes.egg-info/SOURCES.txt +19 -0
- pybarcodes-1.2.1/pybarcodes.egg-info/dependency_links.txt +1 -0
- pybarcodes-1.2.1/pybarcodes.egg-info/requires.txt +1 -0
- pybarcodes-1.2.1/pybarcodes.egg-info/top_level.txt +1 -0
- {pybarcodes-1.0.2 → pybarcodes-1.2.1}/pyproject.toml +12 -13
- pybarcodes-1.2.1/setup.cfg +4 -0
- pybarcodes-1.2.1/tests/test_codes.py +35 -0
- pybarcodes-1.2.1/tests/test_ean.py +188 -0
- pybarcodes-1.2.1/tests/test_images.py +101 -0
- pybarcodes-1.0.2/pybarcodes/barcode.py +0 -159
- pybarcodes-1.0.2/pybarcodes/fonts/arial.ttf +0 -0
- {pybarcodes-1.0.2 → pybarcodes-1.2.1}/LICENSE +0 -0
- {pybarcodes-1.0.2 → pybarcodes-1.2.1}/pybarcodes/codings/__init__.py +0 -0
- {pybarcodes-1.0.2 → pybarcodes-1.2.1}/pybarcodes/codings/codex.py +0 -0
- {pybarcodes-1.0.2 → pybarcodes-1.2.1}/pybarcodes/codings/ean.py +0 -0
- {pybarcodes-1.0.2 → pybarcodes-1.2.1}/pybarcodes/exceptions.py +0 -0
|
@@ -1,15 +1,16 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: pybarcodes
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.2.1
|
|
4
4
|
Summary: A Python package for barcode generation
|
|
5
|
+
Author-email: atbuy <buy@atbuy.dev>
|
|
5
6
|
License-Expression: MIT
|
|
6
|
-
|
|
7
|
+
Project-URL: Homepage, https://github.com/atbuy/pybarcodes
|
|
8
|
+
Project-URL: Repository, https://github.com/atbuy/pybarcodes
|
|
9
|
+
Project-URL: Bug Tracker, https://github.com/atbuy/pybarcodes/issues
|
|
10
|
+
Project-URL: Source Code, https://github.com/atbuy/pybarcodes
|
|
11
|
+
Project-URL: CI/CD, https://github.com/atbuy/pybarcodes/actions
|
|
7
12
|
Keywords: barcode,scanner,generator,ean13,code39,jan,python
|
|
8
|
-
Author: atbuy
|
|
9
|
-
Author-email: buy@atbuy.dev
|
|
10
|
-
Requires-Python: >=3.10
|
|
11
13
|
Classifier: Development Status :: 5 - Production/Stable
|
|
12
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
13
14
|
Classifier: Intended Audience :: Developers
|
|
14
15
|
Classifier: Natural Language :: English
|
|
15
16
|
Classifier: Operating System :: OS Independent
|
|
@@ -23,13 +24,11 @@ Classifier: Topic :: Multimedia :: Graphics
|
|
|
23
24
|
Classifier: Topic :: Software Development :: Libraries
|
|
24
25
|
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
25
26
|
Classifier: Topic :: Utilities
|
|
26
|
-
Requires-
|
|
27
|
-
Project-URL: Bug Tracker, https://github.com/atbuy/pybarcodes/issues
|
|
28
|
-
Project-URL: CI/CD, https://github.com/atbuy/pybarcodes/actions
|
|
29
|
-
Project-URL: Homepage, https://github.com/atbuy/pybarcodes
|
|
30
|
-
Project-URL: Repository, https://github.com/atbuy/pybarcodes
|
|
31
|
-
Project-URL: Source Code, https://github.com/atbuy/pybarcodes
|
|
27
|
+
Requires-Python: >=3.10
|
|
32
28
|
Description-Content-Type: text/x-rst
|
|
29
|
+
License-File: LICENSE
|
|
30
|
+
Requires-Dist: pillow<13,>8
|
|
31
|
+
Dynamic: license-file
|
|
33
32
|
|
|
34
33
|
pybarcodes
|
|
35
34
|
==========
|
|
@@ -49,7 +48,7 @@ pybarcodes
|
|
|
49
48
|
:alt: PyPI supported Python versions
|
|
50
49
|
|
|
51
50
|
|
|
52
|
-
This is a
|
|
51
|
+
This is a Python package to create barcodes.
|
|
53
52
|
You can create file-like objects, text files and images from just a barcode number.
|
|
54
53
|
Image generation is fast so it can be used to create images in bulk.
|
|
55
54
|
|
|
@@ -70,7 +69,7 @@ PRs are welcome :)
|
|
|
70
69
|
Installing
|
|
71
70
|
-----------
|
|
72
71
|
|
|
73
|
-
**Python 3.
|
|
72
|
+
**Python 3.10 or higher is required**
|
|
74
73
|
|
|
75
74
|
To install the library you can run the following command:
|
|
76
75
|
|
|
@@ -134,4 +133,3 @@ Links
|
|
|
134
133
|
|
|
135
134
|
- `Documentation <https://pybarcodes.readthedocs.io/en/latest/index.html>`_
|
|
136
135
|
- `PyPi <https://pypi.org/project/pybarcodes/>`_
|
|
137
|
-
|
|
@@ -16,7 +16,7 @@ pybarcodes
|
|
|
16
16
|
:alt: PyPI supported Python versions
|
|
17
17
|
|
|
18
18
|
|
|
19
|
-
This is a
|
|
19
|
+
This is a Python package to create barcodes.
|
|
20
20
|
You can create file-like objects, text files and images from just a barcode number.
|
|
21
21
|
Image generation is fast so it can be used to create images in bulk.
|
|
22
22
|
|
|
@@ -37,7 +37,7 @@ PRs are welcome :)
|
|
|
37
37
|
Installing
|
|
38
38
|
-----------
|
|
39
39
|
|
|
40
|
-
**Python 3.
|
|
40
|
+
**Python 3.10 or higher is required**
|
|
41
41
|
|
|
42
42
|
To install the library you can run the following command:
|
|
43
43
|
|
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
from collections import namedtuple
|
|
2
|
+
from io import BytesIO
|
|
3
|
+
from typing import Union
|
|
4
|
+
|
|
5
|
+
from PIL import Image, ImageDraw, ImageFont
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Barcode:
|
|
9
|
+
"""A base class for all barcode types"""
|
|
10
|
+
|
|
11
|
+
def __init__(self, barcode: Union[str, int]):
|
|
12
|
+
self.code = self.normalize(barcode)
|
|
13
|
+
|
|
14
|
+
@classmethod
|
|
15
|
+
def validate(cls, barcode: Union[str, int]) -> None:
|
|
16
|
+
"""Validate barcode input."""
|
|
17
|
+
|
|
18
|
+
@classmethod
|
|
19
|
+
def normalize(cls, barcode: Union[str, int]) -> str:
|
|
20
|
+
"""Return the normalized barcode value used by the instance."""
|
|
21
|
+
|
|
22
|
+
cls.validate(barcode)
|
|
23
|
+
return str(barcode)
|
|
24
|
+
|
|
25
|
+
@property
|
|
26
|
+
def image(self) -> Image.Image:
|
|
27
|
+
"""Retrieves and returns the PIL.Image object with the barcode
|
|
28
|
+
|
|
29
|
+
Returns
|
|
30
|
+
-------
|
|
31
|
+
PIl.Image.Image:
|
|
32
|
+
The barcode image
|
|
33
|
+
"""
|
|
34
|
+
|
|
35
|
+
return self.render()
|
|
36
|
+
|
|
37
|
+
def render(
|
|
38
|
+
self,
|
|
39
|
+
size: tuple = None,
|
|
40
|
+
module_width: int = None,
|
|
41
|
+
bar_height: int = None,
|
|
42
|
+
quiet_zone: int = None,
|
|
43
|
+
font_size: int = None,
|
|
44
|
+
draw_text: bool = True,
|
|
45
|
+
) -> Image.Image:
|
|
46
|
+
"""Create a PIL Image object for the barcode."""
|
|
47
|
+
|
|
48
|
+
img = self._get_barcode_image(
|
|
49
|
+
module_width=module_width,
|
|
50
|
+
bar_height=bar_height,
|
|
51
|
+
quiet_zone=quiet_zone,
|
|
52
|
+
font_size=font_size,
|
|
53
|
+
draw_text=draw_text,
|
|
54
|
+
)
|
|
55
|
+
if size is not None:
|
|
56
|
+
resampling = getattr(Image, "Resampling", Image)
|
|
57
|
+
img = img.resize(size, resampling.NEAREST)
|
|
58
|
+
return img
|
|
59
|
+
|
|
60
|
+
def save(
|
|
61
|
+
self,
|
|
62
|
+
path: str,
|
|
63
|
+
size: tuple = None,
|
|
64
|
+
module_width: int = None,
|
|
65
|
+
bar_height: int = None,
|
|
66
|
+
quiet_zone: int = None,
|
|
67
|
+
font_size: int = None,
|
|
68
|
+
draw_text: bool = True,
|
|
69
|
+
**save_kwargs,
|
|
70
|
+
) -> Image.Image:
|
|
71
|
+
"""Create a PIL Image object and save it to the path given.
|
|
72
|
+
|
|
73
|
+
It also returns that image object to the caller.
|
|
74
|
+
|
|
75
|
+
Parameters
|
|
76
|
+
----------
|
|
77
|
+
path: str
|
|
78
|
+
The path to save the image to
|
|
79
|
+
|
|
80
|
+
Returns
|
|
81
|
+
-------
|
|
82
|
+
Returns a PIL Image object to the caller
|
|
83
|
+
"""
|
|
84
|
+
|
|
85
|
+
img = self.render(
|
|
86
|
+
size=size,
|
|
87
|
+
module_width=module_width,
|
|
88
|
+
bar_height=bar_height,
|
|
89
|
+
quiet_zone=quiet_zone,
|
|
90
|
+
font_size=font_size,
|
|
91
|
+
draw_text=draw_text,
|
|
92
|
+
)
|
|
93
|
+
img.save(path, **save_kwargs)
|
|
94
|
+
return img
|
|
95
|
+
|
|
96
|
+
def show(self) -> None:
|
|
97
|
+
"""Shows the barcode image"""
|
|
98
|
+
|
|
99
|
+
self.render().show()
|
|
100
|
+
|
|
101
|
+
def to_text_bytes(self, encoding: str = "ascii") -> bytes:
|
|
102
|
+
"""Return the normalized barcode text as bytes."""
|
|
103
|
+
|
|
104
|
+
return self.code.encode(encoding)
|
|
105
|
+
|
|
106
|
+
def to_text_bytesio(self, encoding: str = "ascii") -> BytesIO:
|
|
107
|
+
"""
|
|
108
|
+
Write the barcode to a BytesIO object
|
|
109
|
+
|
|
110
|
+
Returns
|
|
111
|
+
-------
|
|
112
|
+
Returns the BytesIO object created
|
|
113
|
+
"""
|
|
114
|
+
|
|
115
|
+
obj = BytesIO(self.to_text_bytes(encoding=encoding))
|
|
116
|
+
obj.seek(0)
|
|
117
|
+
return obj
|
|
118
|
+
|
|
119
|
+
def to_bytesio(self, encoding: str = "ascii") -> BytesIO:
|
|
120
|
+
"""Return the normalized barcode text in a BytesIO object."""
|
|
121
|
+
|
|
122
|
+
return self.to_text_bytesio(encoding=encoding)
|
|
123
|
+
|
|
124
|
+
def to_image_bytesio(
|
|
125
|
+
self,
|
|
126
|
+
format: str = "PNG",
|
|
127
|
+
size: tuple = None,
|
|
128
|
+
module_width: int = None,
|
|
129
|
+
bar_height: int = None,
|
|
130
|
+
quiet_zone: int = None,
|
|
131
|
+
font_size: int = None,
|
|
132
|
+
draw_text: bool = True,
|
|
133
|
+
**save_kwargs,
|
|
134
|
+
) -> BytesIO:
|
|
135
|
+
"""Return the rendered barcode image in a BytesIO object."""
|
|
136
|
+
|
|
137
|
+
obj = BytesIO()
|
|
138
|
+
self.render(
|
|
139
|
+
size=size,
|
|
140
|
+
module_width=module_width,
|
|
141
|
+
bar_height=bar_height,
|
|
142
|
+
quiet_zone=quiet_zone,
|
|
143
|
+
font_size=font_size,
|
|
144
|
+
draw_text=draw_text,
|
|
145
|
+
).save(obj, format=format, **save_kwargs)
|
|
146
|
+
obj.seek(0)
|
|
147
|
+
return obj
|
|
148
|
+
|
|
149
|
+
def to_image_bytes(
|
|
150
|
+
self,
|
|
151
|
+
format: str = "PNG",
|
|
152
|
+
size: tuple = None,
|
|
153
|
+
module_width: int = None,
|
|
154
|
+
bar_height: int = None,
|
|
155
|
+
quiet_zone: int = None,
|
|
156
|
+
font_size: int = None,
|
|
157
|
+
draw_text: bool = True,
|
|
158
|
+
**save_kwargs,
|
|
159
|
+
) -> bytes:
|
|
160
|
+
"""Return the rendered barcode image as bytes."""
|
|
161
|
+
|
|
162
|
+
return self.to_image_bytesio(
|
|
163
|
+
format=format,
|
|
164
|
+
size=size,
|
|
165
|
+
module_width=module_width,
|
|
166
|
+
bar_height=bar_height,
|
|
167
|
+
quiet_zone=quiet_zone,
|
|
168
|
+
font_size=font_size,
|
|
169
|
+
draw_text=draw_text,
|
|
170
|
+
**save_kwargs,
|
|
171
|
+
).getvalue()
|
|
172
|
+
|
|
173
|
+
def write(self, path: str, encoding: str = "ascii") -> None:
|
|
174
|
+
"""
|
|
175
|
+
Tries to save the barcode to a text file
|
|
176
|
+
|
|
177
|
+
Parameters
|
|
178
|
+
----------
|
|
179
|
+
path: str
|
|
180
|
+
The path of the file
|
|
181
|
+
"""
|
|
182
|
+
with open(path, "w", encoding=encoding) as file:
|
|
183
|
+
file.write(self.code)
|
|
184
|
+
|
|
185
|
+
@staticmethod
|
|
186
|
+
def _positive_int(value: int, name: str) -> int:
|
|
187
|
+
value = int(value)
|
|
188
|
+
if value <= 0:
|
|
189
|
+
raise ValueError(f"{name} must be greater than 0.")
|
|
190
|
+
return value
|
|
191
|
+
|
|
192
|
+
def _get_render_options(
|
|
193
|
+
self,
|
|
194
|
+
module_width: int = None,
|
|
195
|
+
bar_height: int = None,
|
|
196
|
+
quiet_zone: int = None,
|
|
197
|
+
font_size: int = None,
|
|
198
|
+
draw_text: bool = True,
|
|
199
|
+
):
|
|
200
|
+
padding = self.BARCODE_PADDING
|
|
201
|
+
selected_size, default_font_size = self.BARCODE_SIZE, self.BARCODE_FONT_SIZE
|
|
202
|
+
|
|
203
|
+
module_width = (
|
|
204
|
+
self._get_column_size()
|
|
205
|
+
if module_width is None
|
|
206
|
+
else self._positive_int(module_width, "module_width")
|
|
207
|
+
)
|
|
208
|
+
bar_height = (
|
|
209
|
+
selected_size[1]
|
|
210
|
+
if bar_height is None
|
|
211
|
+
else self._positive_int(bar_height, "bar_height")
|
|
212
|
+
)
|
|
213
|
+
quiet_zone = (
|
|
214
|
+
padding.width // 2
|
|
215
|
+
if quiet_zone is None
|
|
216
|
+
else self._positive_int(quiet_zone, "quiet_zone")
|
|
217
|
+
)
|
|
218
|
+
font_size = (
|
|
219
|
+
default_font_size
|
|
220
|
+
if font_size is None
|
|
221
|
+
else self._positive_int(font_size, "font_size")
|
|
222
|
+
)
|
|
223
|
+
text_padding = padding.height if draw_text else 0
|
|
224
|
+
|
|
225
|
+
return module_width, bar_height, quiet_zone, font_size, text_padding
|
|
226
|
+
|
|
227
|
+
def _get_default_font(self, font_size: int) -> ImageFont.ImageFont:
|
|
228
|
+
try:
|
|
229
|
+
return ImageFont.load_default(size=font_size)
|
|
230
|
+
except TypeError:
|
|
231
|
+
return ImageFont.load_default()
|
|
232
|
+
|
|
233
|
+
def _get_barcode_image(
|
|
234
|
+
self,
|
|
235
|
+
module_width: int = None,
|
|
236
|
+
bar_height: int = None,
|
|
237
|
+
quiet_zone: int = None,
|
|
238
|
+
font_size: int = None,
|
|
239
|
+
draw_text: bool = True,
|
|
240
|
+
) -> Image.Image:
|
|
241
|
+
"""Creates a PIL Image from the binary string of the barcode
|
|
242
|
+
|
|
243
|
+
Returns
|
|
244
|
+
-------
|
|
245
|
+
A PIL Image with the barcode is returned to the caller.
|
|
246
|
+
"""
|
|
247
|
+
|
|
248
|
+
module_width, bar_height, quiet_zone, font_size, text_padding = (
|
|
249
|
+
self._get_render_options(
|
|
250
|
+
module_width=module_width,
|
|
251
|
+
bar_height=bar_height,
|
|
252
|
+
quiet_zone=quiet_zone,
|
|
253
|
+
font_size=font_size,
|
|
254
|
+
draw_text=draw_text,
|
|
255
|
+
)
|
|
256
|
+
)
|
|
257
|
+
|
|
258
|
+
binary_string = self.get_binary_string
|
|
259
|
+
|
|
260
|
+
# Create the image for the barcode
|
|
261
|
+
img = Image.new(
|
|
262
|
+
"RGB",
|
|
263
|
+
(module_width * len(binary_string), bar_height),
|
|
264
|
+
(255, 255, 255),
|
|
265
|
+
)
|
|
266
|
+
|
|
267
|
+
index = 0
|
|
268
|
+
for digit in binary_string:
|
|
269
|
+
color = (0, 0, 0) if digit == "1" else (255, 255, 255)
|
|
270
|
+
column = Image.new("RGB", (module_width, img.height), color)
|
|
271
|
+
img.paste(column, (index, 0))
|
|
272
|
+
index += module_width
|
|
273
|
+
|
|
274
|
+
base = Image.new(
|
|
275
|
+
"RGB",
|
|
276
|
+
(img.width + quiet_zone * 2, bar_height + text_padding),
|
|
277
|
+
(255, 255, 255),
|
|
278
|
+
)
|
|
279
|
+
|
|
280
|
+
# Paste the barcode on the center of the padded base
|
|
281
|
+
Point = namedtuple("Point", "x y")
|
|
282
|
+
base_center = Point(base.width // 2, base.height // 2)
|
|
283
|
+
|
|
284
|
+
base.paste(img, (quiet_zone, text_padding // 2))
|
|
285
|
+
|
|
286
|
+
if not draw_text:
|
|
287
|
+
return base
|
|
288
|
+
|
|
289
|
+
draw = ImageDraw.Draw(base)
|
|
290
|
+
font = self._get_default_font(font_size)
|
|
291
|
+
|
|
292
|
+
text_width = draw.textlength(self.code, font)
|
|
293
|
+
x = base_center.x - text_width // 2
|
|
294
|
+
y = text_padding // 2 + img.height
|
|
295
|
+
|
|
296
|
+
draw.text((x, y), self.code, (0, 0, 0), font=font)
|
|
297
|
+
return base
|
|
298
|
+
|
|
299
|
+
def __eq__(self, other):
|
|
300
|
+
if isinstance(other, self.__class__):
|
|
301
|
+
return self.code == other.code
|
|
302
|
+
elif isinstance(other, str):
|
|
303
|
+
return self.code == other
|
|
304
|
+
|
|
305
|
+
return False
|
|
306
|
+
|
|
307
|
+
def __str__(self) -> str:
|
|
308
|
+
return f"<{self.__class__.__name__}(code={self.code})>"
|
|
309
|
+
|
|
310
|
+
def __repr__(self):
|
|
311
|
+
return self.__str__()
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
from collections import namedtuple
|
|
2
|
-
from pathlib import Path
|
|
3
2
|
from typing import Union
|
|
4
3
|
|
|
5
|
-
from PIL import Image, ImageDraw
|
|
4
|
+
from PIL import Image, ImageDraw
|
|
6
5
|
|
|
7
6
|
from .barcode import Barcode
|
|
8
7
|
from .codings import codex as CODEXCoding
|
|
@@ -15,7 +14,7 @@ class Code(Barcode):
|
|
|
15
14
|
def __init__(self, barcode: Union[str, int]):
|
|
16
15
|
super().__init__(barcode)
|
|
17
16
|
|
|
18
|
-
self.
|
|
17
|
+
self.checksum = self.code[-1]
|
|
19
18
|
|
|
20
19
|
# Calculate the variable width of the barcod
|
|
21
20
|
# 6 pixels for each character
|
|
@@ -36,6 +35,39 @@ class Code(Barcode):
|
|
|
36
35
|
# Calculate how many character will have to be written
|
|
37
36
|
self.BARCODE_COLUMN_NUMBER = column_size
|
|
38
37
|
|
|
38
|
+
@classmethod
|
|
39
|
+
def validate(cls, barcode: Union[str, int]) -> None:
|
|
40
|
+
code = str(barcode).upper()
|
|
41
|
+
|
|
42
|
+
for char in code:
|
|
43
|
+
if char not in CODEXCoding.CODES or char == "_":
|
|
44
|
+
raise IncorrectFormat(
|
|
45
|
+
f"Character {char} is not supported by {cls.__name__}"
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
@classmethod
|
|
49
|
+
def normalize(cls, barcode: Union[str, int]) -> str:
|
|
50
|
+
cls.validate(barcode)
|
|
51
|
+
code = str(barcode).upper()
|
|
52
|
+
reference = cls._calculate_checksum(code)
|
|
53
|
+
checkchar = CODEXCoding.REFERENCE_NUMBERS[reference]
|
|
54
|
+
return code + checkchar
|
|
55
|
+
|
|
56
|
+
@classmethod
|
|
57
|
+
def _calculate_checksum(cls, barcode: str) -> int:
|
|
58
|
+
code = barcode.upper()
|
|
59
|
+
for char in code:
|
|
60
|
+
if char not in CODEXCoding.REFERENCE_DIGITS:
|
|
61
|
+
raise IncorrectFormat(
|
|
62
|
+
f"Character {char} is not supported by {cls.__name__}"
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
if len(code) == 1:
|
|
66
|
+
return CODEXCoding.REFERENCE_DIGITS[code]
|
|
67
|
+
|
|
68
|
+
numbers = [CODEXCoding.REFERENCE_DIGITS[char] for char in list(code)]
|
|
69
|
+
return sum(numbers) % 43
|
|
70
|
+
|
|
39
71
|
@property
|
|
40
72
|
def get_binary_string(self) -> str:
|
|
41
73
|
"""Converts the code to the binary string that it produces.
|
|
@@ -85,25 +117,21 @@ class Code(Barcode):
|
|
|
85
117
|
barcode = barcode.code
|
|
86
118
|
elif isinstance(barcode, str):
|
|
87
119
|
pass
|
|
88
|
-
elif barcode is None
|
|
120
|
+
elif barcode is None:
|
|
89
121
|
return CODEXCoding.REFERENCE_DIGITS[self.checksum]
|
|
90
122
|
else:
|
|
91
123
|
raise TypeError(f"Can't accept type {type(barcode)}")
|
|
92
124
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
# If the barcode is only 1 character long
|
|
96
|
-
# Then the check sum will be that same character
|
|
97
|
-
if len(barcode) == 1:
|
|
98
|
-
return CODEXCoding.REFERENCE_DIGITS[barcode]
|
|
99
|
-
|
|
100
|
-
# Find the number value of each digit
|
|
101
|
-
numbers = [CODEXCoding.REFERENCE_DIGITS[char] for char in list(barcode)]
|
|
102
|
-
|
|
103
|
-
# Calculate the modulo 43 of the sum
|
|
104
|
-
return sum(numbers) % 43
|
|
125
|
+
return self._calculate_checksum(barcode)
|
|
105
126
|
|
|
106
|
-
def _get_barcode_image(
|
|
127
|
+
def _get_barcode_image(
|
|
128
|
+
self,
|
|
129
|
+
module_width: int = None,
|
|
130
|
+
bar_height: int = None,
|
|
131
|
+
quiet_zone: int = None,
|
|
132
|
+
font_size: int = None,
|
|
133
|
+
draw_text: bool = True,
|
|
134
|
+
) -> Image.Image:
|
|
107
135
|
"""Creates a PIL Image from the binary string of the barcode.
|
|
108
136
|
|
|
109
137
|
Returns
|
|
@@ -111,33 +139,25 @@ class Code(Barcode):
|
|
|
111
139
|
A PIL Image with the barcode is returned to the caller.
|
|
112
140
|
"""
|
|
113
141
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
selected_size[0] + padding.width,
|
|
123
|
-
selected_size[1] + padding.height,
|
|
142
|
+
module_width, bar_height, quiet_zone, font_size, text_padding = (
|
|
143
|
+
self._get_render_options(
|
|
144
|
+
module_width=module_width,
|
|
145
|
+
bar_height=bar_height,
|
|
146
|
+
quiet_zone=quiet_zone,
|
|
147
|
+
font_size=font_size,
|
|
148
|
+
draw_text=draw_text,
|
|
149
|
+
)
|
|
124
150
|
)
|
|
125
151
|
|
|
126
|
-
# Get each column's width and height
|
|
127
|
-
column_size = self._get_column_size()
|
|
128
|
-
|
|
129
|
-
# Create a white base image to paste the barcode on
|
|
130
|
-
base = Image.new("RGB", padded_size, (255, 255, 255))
|
|
131
|
-
|
|
132
152
|
# Create the image to write the columns
|
|
133
153
|
img = Image.new(
|
|
134
154
|
"RGB",
|
|
135
|
-
(
|
|
155
|
+
(module_width * self.BARCODE_COLUMN_NUMBER, bar_height),
|
|
136
156
|
(255, 255, 255),
|
|
137
157
|
)
|
|
138
158
|
|
|
139
159
|
# This is the spacing we are going to add after each digit
|
|
140
|
-
space = Image.new("RGB", (
|
|
160
|
+
space = Image.new("RGB", (module_width, img.height), (255, 255, 255))
|
|
141
161
|
|
|
142
162
|
# Create a binary string representation of the barcode digits
|
|
143
163
|
binary_string = self.get_binary_string
|
|
@@ -151,12 +171,12 @@ class Code(Barcode):
|
|
|
151
171
|
# If the character is a ` ` (space) then we write 3 times the size on the spacing
|
|
152
172
|
# We also need to add a single width column of spacing after each digit
|
|
153
173
|
if digit == "1":
|
|
154
|
-
column_width =
|
|
174
|
+
column_width = module_width * 3
|
|
155
175
|
elif digit == " ":
|
|
156
|
-
column_width =
|
|
176
|
+
column_width = module_width * 3
|
|
157
177
|
color = (255, 255, 255)
|
|
158
178
|
else:
|
|
159
|
-
column_width =
|
|
179
|
+
column_width = module_width
|
|
160
180
|
|
|
161
181
|
# First paste the column
|
|
162
182
|
column = Image.new("RGB", (column_width, img.height), color)
|
|
@@ -171,31 +191,30 @@ class Code(Barcode):
|
|
|
171
191
|
# Crop redundant whitespace after barcode
|
|
172
192
|
img = img.crop((0, 0, index, img.height))
|
|
173
193
|
|
|
194
|
+
base = Image.new(
|
|
195
|
+
"RGB",
|
|
196
|
+
(img.width + quiet_zone * 2, bar_height + text_padding),
|
|
197
|
+
(255, 255, 255),
|
|
198
|
+
)
|
|
199
|
+
|
|
174
200
|
# Paste the barcode on the center of the padded base
|
|
175
201
|
Point = namedtuple("Point", "x y")
|
|
176
202
|
base_center = Point(base.width // 2, base.height // 2)
|
|
177
|
-
img_center = Point(img.width // 2, img.height // 2)
|
|
178
203
|
|
|
179
|
-
base.paste(img, (
|
|
204
|
+
base.paste(img, (quiet_zone, text_padding // 2))
|
|
180
205
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
font_path = str(cwd.joinpath(cwd, "fonts", "arial.ttf"))
|
|
206
|
+
if not draw_text:
|
|
207
|
+
return base
|
|
184
208
|
|
|
185
209
|
draw = ImageDraw.Draw(base)
|
|
186
|
-
font =
|
|
210
|
+
font = self._get_default_font(font_size)
|
|
187
211
|
|
|
188
212
|
text_width = draw.textlength(self.code, font)
|
|
189
213
|
x = base_center.x - text_width // 2
|
|
190
|
-
y =
|
|
214
|
+
y = text_padding // 2 + img.height
|
|
191
215
|
|
|
192
216
|
draw.text((x, y), self.code, (0, 0, 0), font=font)
|
|
193
217
|
|
|
194
|
-
# And now we crop spare white space around base image
|
|
195
|
-
start_index = (base_center.x - img_center.x) - padding.width // 2
|
|
196
|
-
end_index = (base_center.x - img_center.x) + padding.width // 2
|
|
197
|
-
|
|
198
|
-
base.crop((start_index, 0, end_index, base.height))
|
|
199
218
|
return base
|
|
200
219
|
|
|
201
220
|
def _convert_to_binary(self, string: str) -> str:
|
|
@@ -225,17 +244,7 @@ class Code(Barcode):
|
|
|
225
244
|
and the check digit is calculated if not given
|
|
226
245
|
"""
|
|
227
246
|
|
|
228
|
-
|
|
229
|
-
if char not in CODEXCoding.CODES or char == "_":
|
|
230
|
-
raise IncorrectFormat(
|
|
231
|
-
f"Character {char} is not supported by {self.__class__.__name__}"
|
|
232
|
-
)
|
|
233
|
-
|
|
234
|
-
reference = self.calculate_checksum(self.code)
|
|
235
|
-
checkchar = CODEXCoding.REFERENCE_NUMBERS[reference]
|
|
236
|
-
|
|
237
|
-
self.checksum = checkchar
|
|
238
|
-
return self.code + str(checkchar)
|
|
247
|
+
return self.normalize(self.code)
|
|
239
248
|
|
|
240
249
|
def _trim(self, code: str) -> str:
|
|
241
250
|
"""Removes the start and stop characters from the barcode
|