Skip to content

Commit 54f4568

Browse files
committed
implement missing tables, add logging
1 parent 28cb3d7 commit 54f4568

File tree

3 files changed

+88
-26
lines changed

3 files changed

+88
-26
lines changed

dls_barcode/datamatrix/read/interpret.py

Lines changed: 70 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,15 @@ def interpret_bytes(data_bytes):
3737
i += num_bytes
3838

3939
elif byte == 231:
40+
log.error(NotImplementedError("Datamatrix Base 256 decoding not implemented"))
4041
raise NotImplementedError("Datamatrix Base 256 decoding not implemented")
4142

4243
elif 232 <= byte <= 237: # Other parts of the Data Matrix spec., not supported.
44+
log.error(NotImplementedError("Datamatrix Base 256 decoding not implemented"))
4345
raise NotImplementedError("Datamatrix encoded symbol {} not implemented".format(byte))
4446

4547
elif byte == 238:
48+
log.error(NotImplementedError("Datamatrix ANSI X12 decoding not implemented"))
4649
raise NotImplementedError("Datamatrix ANSI X12 decoding not implemented")
4750

4851
elif byte == 239:
@@ -51,23 +54,19 @@ def interpret_bytes(data_bytes):
5154
i += num_bytes
5255

5356
elif byte == 240:
54-
#log = log = logging.getLogger(".".join([__name__]))
55-
#log.error(NotImplementedError("Datamatrix EDIFACT decoding not implemented"))
57+
log.error(NotImplementedError("Datamatrix EDIFACT decoding not implemented"))
5658
raise NotImplementedError("Datamatrix EDIFACT decoding not implemented")
5759

5860
elif byte == 241:
59-
#log = log = logging.getLogger(".".join([__name__]))
60-
#log.error(NotImplementedError("Datamatrix Extended Channel Interpretation code not implemented"))
61+
log.error(NotImplementedError("Datamatrix Extended Channel Interpretation code not implemented"))
6162
raise NotImplementedError("Datamatrix Extended Channel Interpretation code not implemented")
6263

6364
elif 242 <= byte < 256: # Unused parts of message space.
64-
#log = log = logging.getLogger(".".join([__name__]))
6565
error = ValueError("Code {} is not used in Datamatrix specification".format(byte))
66-
#.error(error)
66+
log.error(error)
6767
raise error
6868
elif byte == 0:
6969
error = ValueError("Code {} is not used in Datamatrix specification".format(byte))
70-
7170
log.error(error)
7271

7372
return ''.join(m for m in message)
@@ -78,6 +77,7 @@ def _interpret_text_mode_bytes(data_bytes):
7877
which can encode 3 characters in 2 bytes, as long as the characters are digits or capital
7978
letters. This function decodes those bytes.
8079
"""
80+
log = logging.getLogger(".".join([__name__]))
8181
encoded_bytes = []
8282
mode = None
8383
for b in data_bytes:
@@ -98,8 +98,10 @@ def _interpret_text_mode_bytes(data_bytes):
9898
num_encoded_bytes = len(encoded_bytes)
9999

100100
if num_encoded_bytes == 0:
101+
log.error(ValueError("No data bytes encoded in Datamatrix Text Mode encoding"))
101102
return ValueError("No data bytes encoded in Datamatrix Text Mode encoding")
102103
elif num_encoded_bytes % 2 != 0:
104+
log.error(ValueError("Odd number of Text mode encoded bytes"))
103105
raise ValueError("Odd number of Text mode encoded bytes")
104106

105107
byte_pairs = [encoded_bytes[i:i + 2] for i in range(0, len(encoded_bytes), 2)]
@@ -110,7 +112,10 @@ def _interpret_text_mode_bytes(data_bytes):
110112
decoded = DBI._decode_txt_mode_byte_pair(pair)
111113
decoded_bytes.extend(decoded)
112114

113-
ascii_chars = [DBI._interpret_decoded_text_byte(byte, mode) for byte in decoded_bytes]
115+
ascii_chars = []
116+
it = iter(decoded_bytes)
117+
for byte in it:
118+
ascii_chars.extend(DBI._interpret_decoded_text_byte(byte, next(byte),mode))
114119

115120
num_bytes = num_encoded_bytes + 2
116121
return ascii_chars, num_bytes
@@ -127,9 +132,10 @@ def _decode_txt_mode_byte_pair(byte_pair):
127132
c3 = val16 - (c1 * 1600) - (c2 * 40) - 1
128133

129134
return [c1, c2, c3]
130-
135+
136+
131137
@staticmethod
132-
def _interpret_decoded_text_byte(byte, mode):
138+
def _interpret_decoded_text_byte(byte, next_byte, mode):
133139
""" Interpret the byte by lookup in the C40 or Text tables.
134140
135141
C40 includes 4 encoding sets which each map the values 0-39 to a table of symbols. The first
@@ -140,24 +146,63 @@ def _interpret_decoded_text_byte(byte, mode):
140146
141147
Text mode is exactly the same as C40 except that the upper and lower case characters are swapped
142148
"""
149+
log = logging.getLogger(".".join([__name__]))
143150
if mode not in ["C40", "Text"]:
151+
log.error(ValueError("Unrecognised Text encoding mode"))
144152
raise ValueError("Unrecognised Text encoding mode")
145153

146154
if 0 <= byte <= 2: # Used to switch to other encoding tables - not implemented here
147155
# Todo: implement the other tables
148-
raise NotImplementedError("{} Set 1, 2, and 3 encoding not implemented".format(mode))
149-
150-
elif byte == 3: # C40 3 is space
151-
return " "
152-
153-
elif 4 <= byte <= 13: # C40 number range, add 40 to get ascii value
154-
return chr(byte + 44)
156+
# raise NotImplementedError("{} Set 1, 2, and 3 encoding not implemented".format(mode))
157+
DatamatrixByteInterpreter._interpret_decoded_text_byte_other_table(byte, next_byte, mode)
158+
else :
159+
decoded_chars = []
160+
for b in [byte, next_byte]:
161+
if b == 3: # C40 3 is space
162+
decoded_chars.append(" ")
163+
164+
elif 4 <= b <= 13: # C40 number range, add 40 to get ascii value
165+
decoded_chars.append(chr(b + 44))
166+
167+
elif b <= 39: # C40 range A-Z, add 51 to get ascii value
168+
if mode == "C40":
169+
decoded_chars.append(chr(b + 51))
170+
elif mode == "Text":
171+
decoded_chars.append(chr(b + 83))
172+
173+
else:
174+
log.error(ValueError("Value {} is not a valid C40 or Text symbol".format(b)))
175+
raise ValueError("Value {} is not a valid C40 or Text symbol".format(b))
176+
return decoded_chars
155177

156-
elif byte <= 39: # C40 range A-Z, add 51 to get ascii value
157-
if mode == "C40":
158-
return chr(byte + 51)
159-
elif mode == "Text":
160-
return chr(byte + 83)
161-
162-
else:
163-
raise ValueError("Value {} is not a valid C40 or Text symbol".format(byte))
178+
@staticmethod
179+
def _interpret_decoded_text_byte_other_table(byte, next_byte, mode):
180+
log = logging.getLogger(".".join([__name__]))
181+
if byte == 1:
182+
if 0 <= next_byte <= 31:
183+
return chr(next_byte)
184+
else:
185+
log.error(ValueError("Value {} is not a valid C40 or Text symbol".format(next_byte)))
186+
raise ValueError("Value {} is not a valid C40 or Text symbol".format(next_byte))
187+
elif byte == 2:
188+
if 0 <= next_byte <= 14:
189+
return chr(next_byte + 33)
190+
if 15 <= next_byte <= 21:
191+
return chr(next_byte + 43)
192+
if 22 <= next_byte <= 26:
193+
return chr(next_byte + 69)
194+
else:
195+
log.error(ValueError("Value {} is not a valid C40 or Text symbol".format(next_byte)))
196+
raise ValueError("Value {} is not a valid C40 or Text symbol".format(next_byte))
197+
elif byte == 3:
198+
if next_byte == 0:
199+
return chr(next_byte + 96)
200+
elif 1 <= next_byte <= 31 :
201+
if mode == "C40":
202+
return chr(next_byte + 40)
203+
elif mode == "Text":
204+
return chr(next_byte + 96)
205+
206+
else:
207+
log.error(ValueError("Value {} is not a valid C40 or Text symbol".format(next_byte)))
208+
raise ValueError("Value {} is not a valid C40 or Text symbol".format(next_byte))

dls_barcode/datamatrix/read/reedsolo.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,14 @@
3030
| it shouldn't make a difference from an API perspective.
3131
--------------------------------------------------------------------------------------------------------
3232
"""
33-
33+
import logging
3434

3535
class ReedSolomonError(Exception):
3636
pass
3737

3838

3939
class ReedSolomonDecoder:
40+
4041
def __init__(self):
4142
self.gf = GaloisField(GaloisField.DATAMATRIX)
4243

@@ -46,12 +47,16 @@ def decode(self, encoded_msg, num_data_bytes):
4647
try:
4748
decoded = self._correct_msg(encoded_msg, num_error_bytes)
4849
except ReedSolomonError as ex:
50+
log = logging.getLogger(".".join([__name__]))
51+
log.error(ReedSolomonError("Unable to correct encoding errors: {}".format(str(ex))))
4952
raise ReedSolomonError("Unable to correct encoding errors: {}".format(str(ex)))
5053

5154
return decoded
5255

5356
def _correct_msg(self, msg_in, num_symbols):
57+
log = logging.getLogger(".".join([__name__]))
5458
if len(msg_in) > 255:
59+
log.error(ReedSolomonError("Message too long"))
5560
raise ReedSolomonError("Message too long")
5661

5762
msg_out = list(msg_in) # copy of message
@@ -64,6 +69,7 @@ def _correct_msg(self, msg_in, num_symbols):
6469
erase_pos.append(i)
6570

6671
if len(erase_pos) > num_symbols:
72+
log.error(ReedSolomonError("Too many erasures to correct"))
6773
raise ReedSolomonError("Too many erasures to correct")
6874

6975
syndromes = self._calculate_syndromes(msg_out, num_symbols)
@@ -73,12 +79,14 @@ def _correct_msg(self, msg_in, num_symbols):
7379
forney_syndromes = self._forney_syndromes(syndromes, erase_pos, len(msg_out))
7480
err_pos = self._find_errors(forney_syndromes, len(msg_out))
7581
if err_pos is None:
82+
log.error(ReedSolomonError("Could not locate error"))
7683
raise ReedSolomonError("Could not locate error")
7784

7885
self._correct_errata(msg_out, syndromes, erase_pos + err_pos)
7986
syndromes = self._calculate_syndromes(msg_out, num_symbols)
8087

8188
if max(syndromes) > 0:
89+
log.error(ReedSolomonError("Could not correct message"))
8290
raise ReedSolomonError("Could not correct message")
8391

8492
return msg_out[:-num_symbols]
@@ -113,6 +121,8 @@ def _find_errors(self, syndromes, nmess):
113121

114122
errs = len(err_poly) - 1
115123
if errs * 2 > len(syndromes):
124+
log = logging.getLogger(".".join([__name__]))
125+
log.error(ReedSolomonError("Too many errors to correct"))
116126
raise ReedSolomonError("Too many errors to correct")
117127

118128
# find zeros of error polynomial
@@ -150,6 +160,8 @@ def _correct_errata(self, msg, syndromes, pos):
150160

151161
def encode(self, msg_in, num_ecc_symbols):
152162
if len(msg_in) + num_ecc_symbols > 255:
163+
log = logging.getLogger(".".join([__name__]))
164+
log.error(ReedSolomonError("Message too long"))
153165
raise ReedSolomonError("Message too long")
154166

155167
gen = self._generator_poly(num_ecc_symbols)
@@ -188,6 +200,8 @@ def __init__(self, field_type):
188200
self._primitive = self.QR_CODE_PRIMITIVE
189201
self._generator_base = self.QR_CODE_GEN_BASE
190202
else:
203+
log = logging.getLogger(".".join([__name__]))
204+
log.error(ReedSolomonError("Unknown Galois Field type"))
191205
raise ReedSolomonError("Unknown Galois Field type")
192206

193207
# Generate the exponential and logarithm tables
@@ -221,6 +235,8 @@ def mul(self, x, y):
221235

222236
def div(self, x, y):
223237
if y == 0:
238+
log = logging.getLogger(".".join([__name__]))
239+
log.error( ZeroDivisionError())
224240
raise ZeroDivisionError()
225241
if x == 0:
226242
return 0

tests/unit_tests/test_dls_barcode/test_datamatrix/test_decode.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
([85, 102, 116, 117, 129], "Test"),
77
([85, 102, 116, 117, 129, 101, 102, 103], "Test"),
88
([69, 71, 145, 49, 70, 134, 173, 129], "DF150E0443"),
9+
([230, 14, 32,14,29,1,23,2,14], "ASAP\n"),
910
([x+1 for x in range(32, 127)], bytearray([x for x in range(32, 127)]).decode("utf-8")) #, 'utf-8'
1011
]
1112

0 commit comments

Comments
 (0)