Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cleanup of barcode.codex._convert #234

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 45 additions & 20 deletions barcode/codex.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,12 +64,14 @@ def get_fullcode(self) -> str:
""":returns: The full code as it will be encoded."""
return self.code

def calculate_checksum(self):
def calculate_checksum(self) -> str:
check = sum(code39.MAP[x][0] for x in self.code) % 43
for k, v in code39.MAP.items():
if check == v[0]:
return k
return None
raise RuntimeError(
"All possible values for the checksum should have been included in the map."
)

def build(self) -> list[str]:
chars = [code39.EDGE]
Expand Down Expand Up @@ -150,7 +152,7 @@ def __init__(self, code: str, writer=None) -> None:
self.code = code
self.writer = writer or self.default_writer()
self._charset = "B"
self._buffer = ""
self._digit_buffer = "" # Accumulate pairs of digits for charset C
check_code(self.code, self.name, code128.ALL)

def __str__(self) -> str:
Expand Down Expand Up @@ -194,9 +196,11 @@ def look_next() -> bool:
codes = self._new_charset("B")
elif char in code128.A:
codes = self._new_charset("A")
if len(self._buffer) == 1:
codes.append(self._convert(self._buffer[0]))
self._buffer = ""
assert self._charset != "C"
if len(self._digit_buffer) == 1:
# Flush the remaining single digit from the buffer
codes.append(self._convert(self._digit_buffer[0]))
self._digit_buffer = ""
elif self._charset == "B":
if look_next():
codes = self._new_charset("C")
Expand All @@ -209,25 +213,45 @@ def look_next() -> bool:
codes = self._new_charset("B")
return codes

def _convert(self, char: str):
def _convert(self, char: str) -> int:
"""Convert a character to a code number for the current charset.

NOTE: encoding digits with charset C requires buffering and is not supported
here. Use _convert_or_buffer instead.
"""
if self._charset == "A":
return code128.A[char]
if self._charset == "B":
return code128.B[char]
if self._charset == "C":
if char in code128.C:
if char in ["TO_A", "TO_B"]:
return code128.C[char]
if char.isdigit():
self._buffer += char
if len(self._buffer) == 2:
value = int(self._buffer)
self._buffer = ""
return value
return None
raise RuntimeError("Use _convert_or_buffer for charset C.")
raise RuntimeError(
f"Character {char} could not be converted in charset {self._charset}."
)

def _convert_or_buffer(self, char: str) -> int | None:
"""Convert a character to a code number for the current charset.

If charset C is active then digits are encoded in pairs. When the first digit
is encountered, it is buffered and None is returned.
"""
if self._charset != "C":
return self._convert(char)
if char in code128.C:
return code128.C[char]
if char.isdigit():
self._digit_buffer += char
if len(self._digit_buffer) == 1:
# Wait for the second digit to group in pairs
return None
assert len(self._digit_buffer) == 2
value = int(self._digit_buffer)
self._digit_buffer = ""
return value
raise RuntimeError(f"Character {char} could not be converted in charset C.")

def _try_to_optimize(self, encoded: list[int]) -> list[int]:
if encoded[1] in code128.TO:
encoded[:2] = [code128.TO[encoded[1]]]
Expand All @@ -243,14 +267,15 @@ def _build(self) -> list[int]:
encoded: list[int] = [code128.START_CODES[self._charset]]
for i, char in enumerate(self.code):
encoded.extend(self._maybe_switch_charset(i))
code_num = self._convert(char)
code_num = self._convert_or_buffer(char)
if code_num is not None:
encoded.append(code_num)
# Finally look in the buffer
if len(self._buffer) == 1:
# If we finish in charset C with a single digit remaining in the buffer,
# switch to charset B and flush out the buffer.
if len(self._digit_buffer) == 1:
encoded.extend(self._new_charset("B"))
encoded.append(self._convert(self._buffer[0]))
self._buffer = ""
encoded.append(self._convert(self._digit_buffer[0]))
self._digit_buffer = ""
return self._try_to_optimize(encoded)

def build(self) -> list[str]:
Expand Down
Loading