Make barcode() smarter, improvements and clean up

This commit is contained in:
belono 2023-05-10 20:40:58 +02:00
parent 6b7653fbbf
commit 8f225fe53a

View File

@ -82,6 +82,19 @@ from escpos.image import EscposImage
from escpos.capabilities import get_profile, BARCODE_B from escpos.capabilities import get_profile, BARCODE_B
# Remove special characters and whitespaces of the supported barcode names,
# convert to uppercase and map them to their original names.
HW_BARCODE_NAMES = {
"".join([char for char in name.upper() if char.isalnum()]): name
for bc_type in BARCODE_TYPES.values()
for name in bc_type
}
SW_BARCODE_NAMES = {
"".join([char for char in name.upper() if char.isalnum()]): name
for name in barcode.PROVIDED_BARCODES
}
@six.add_metaclass(ABCMeta) @six.add_metaclass(ABCMeta)
class Escpos(object): class Escpos(object):
"""ESC/POS Printer object """ESC/POS Printer object
@ -427,7 +440,7 @@ class Escpos(object):
Set force_software=True to force the software renderer. Set force_software=True to force the software renderer.
""" """
hw_modes = ["barcodeA", "barcodeB"] hw_modes = ["barcodeA", "barcodeB"]
sw_modes = ["bitImageRaster", "graphics", "bitImageColumn"] sw_modes = ["graphics", "bitImageColumn", "bitImageRaster"]
capable = { capable = {
"hw": [mode for mode in hw_modes if self.profile.supports(mode)] or None, "hw": [mode for mode in hw_modes if self.profile.supports(mode)] or None,
"sw": [mode for mode in sw_modes if self.profile.supports(mode)] or None, "sw": [mode for mode in sw_modes if self.profile.supports(mode)] or None,
@ -435,47 +448,43 @@ class Escpos(object):
if (not capable["hw"] and not capable["sw"]) or ( if (not capable["hw"] and not capable["sw"]) or (
not capable["sw"] and force_software not capable["sw"] and force_software
): ):
print( raise BarcodeCodeError(
f"""Profile { f"""Profile {
self.profile['name'] self.profile['name']
} - hw barcode: {capable['hw']}, sw barcode: {capable['sw']}""" } - hw barcode: {capable['hw']}, sw barcode: {capable['sw']}"""
) )
return
if force_software or not capable["hw"]: bc_alnum = "".join([char for char in bc.upper() if char.isalnum()])
# Select the best possible render mode capable_bc = {
impl = capable["sw"][0] "hw": HW_BARCODE_NAMES.get(bc_alnum),
print(f"Using {impl} software barcode renderer") "sw": SW_BARCODE_NAMES.get(bc_alnum),
# Translate hw to sw barcode type name if supported
sw_bc_type_names = {
"UPC-A": "upca",
"UPC-E": "", # not implemented type
"EAN13": "ean13",
"EAN8": "ean8",
"CODE39": "code39",
"ITF": "itf",
"NW7": "nw-7",
"CODE93": "", # not implemented type
"CODE128": "code128",
"GS1-128": "gs1_128",
"GS1 DataBar Omnidirectional": "", # not implemented type
"GS1 DataBar Truncated": "", # not implemented type
"GS1 DataBar Limited": "", # not implemented type
"GS1 DataBar Expanded": "", # not implemented type
} }
bc = sw_bc_type_names.get(bc, bc) if not any([*capable_bc.values()]):
raise BarcodeTypeError(f"Not supported or wrong barcode name {bc}.")
if force_software or not capable["hw"] or not capable_bc["hw"]:
# Select the best possible capable render mode
impl = capable["sw"][0]
if force_software in capable["sw"]:
# Force to a specific mode
impl = force_software
print(f"Using {impl} software barcode renderer")
# Set barcode type
bc = capable_bc["sw"] or bc
self._sw_barcode( self._sw_barcode(
bc, bc,
code, code,
impl=impl, impl=impl,
module_height=5, # TODO: _hw_barcode() size equivalence module_height=5, # TODO: _hw_barcode() size equivalence
module_width=0.2, # TODO: _hw_barcode() size equivalence module_width=0.2, # TODO: _hw_barcode() size equivalence
text_distance=1, # TODO: _hw_barcode() size equivalence text_distance=2, # TODO: _hw_barcode() size equivalence
font_size=6,
center=align_ct, center=align_ct,
) )
return return
print("Using hardware barcode renderer") print("Using hardware barcode renderer")
bc = capable_bc["hw"] or bc
self._hw_barcode( self._hw_barcode(
code, bc, height, width, pos, font, align_ct, function_type, check code, bc, height, width, pos, font, align_ct, function_type, check
) )
@ -575,27 +584,12 @@ class Escpos(object):
:py:exc:`~escpos.exceptions.BarcodeTypeError`, :py:exc:`~escpos.exceptions.BarcodeTypeError`,
:py:exc:`~escpos.exceptions.BarcodeCodeError` :py:exc:`~escpos.exceptions.BarcodeCodeError`
""" """
if function_type is None: # If function_type is specified, otherwise use guessing.
# Choose the function type automatically. ft_guess = [ft for ft in ["A", "B"] if bc in BARCODE_TYPES.get(ft)]
if bc in BARCODE_TYPES["A"]: ft_guess = ft_guess or [None]
function_type = "A" function_type = function_type or ft_guess[0]
else:
if bc in BARCODE_TYPES["B"]:
if not self.profile.supports(BARCODE_B):
raise BarcodeTypeError(
(
"Barcode type '{bc} not supported for "
"the current printer profile"
).format(bc=bc)
)
function_type = "B"
else:
raise BarcodeTypeError(
("Barcode type '{bc} is not valid").format(bc=bc)
)
bc_types = BARCODE_TYPES[function_type.upper()] if not function_type or not BARCODE_TYPES.get(function_type.upper()):
if bc.upper() not in bc_types.keys():
raise BarcodeTypeError( raise BarcodeTypeError(
( (
"Barcode '{bc}' not valid for barcode function type " "Barcode '{bc}' not valid for barcode function type "
@ -605,6 +599,7 @@ class Escpos(object):
function_type=function_type, function_type=function_type,
) )
) )
bc_types = BARCODE_TYPES[function_type.upper()]
if check and not self.check_barcode(bc, code): if check and not self.check_barcode(bc, code):
raise BarcodeCodeError( raise BarcodeCodeError(
@ -663,7 +658,8 @@ class Escpos(object):
impl="bitImageColumn", impl="bitImageColumn",
module_height=5, module_height=5,
module_width=0.2, module_width=0.2,
text_distance=1, text_distance=5,
font_size=10,
center=True, center=True,
): ):
image_writer = ImageWriter() image_writer = ImageWriter()