diff --git a/src/escpos/constants.py b/src/escpos/constants.py index e3225f8..821c143 100644 --- a/src/escpos/constants.py +++ b/src/escpos/constants.py @@ -71,51 +71,90 @@ SHEET_ROLL_MODE = ESC + b'\x63\x30\x01' # paper roll # Text format # TODO: Acquire the "ESC/POS Application Programming Guide for Paper Roll # Printers" and tidy up this stuff too. -TXT_FLIP_ON = ESC + b'\x7b\x01' -TXT_FLIP_OFF = ESC + b'\x7b\x00' -TXT_SMOOTH_ON = GS + b'\x62\x01' -TXT_SMOOTH_OFF = GS + b'\x62\x00' TXT_SIZE = GS + b'!' -TXT_WIDTH = {1: 0x00, - 2: 0x10, - 3: 0x20, - 4: 0x30, - 5: 0x40, - 6: 0x50, - 7: 0x60, - 8: 0x70} -TXT_HEIGHT = {1: 0x00, - 2: 0x01, - 3: 0x02, - 4: 0x03, - 5: 0x04, - 6: 0x05, - 7: 0x06, - 8: 0x07} + TXT_NORMAL = ESC + b'!\x00' # Normal text -TXT_2HEIGHT = ESC + b'!\x10' # Double height text -TXT_2WIDTH = ESC + b'!\x20' # Double width text -TXT_4SQUARE = ESC + b'!\x30' # Quad area text -TXT_UNDERL_OFF = ESC + b'\x2d\x00' # Underline font OFF -TXT_UNDERL_ON = ESC + b'\x2d\x01' # Underline font 1-dot ON -TXT_UNDERL2_ON = ESC + b'\x2d\x02' # Underline font 2-dot ON -TXT_BOLD_OFF = ESC + b'\x45\x00' # Bold font OFF -TXT_BOLD_ON = ESC + b'\x45\x01' # Bold font ON -TXT_ALIGN_LT = ESC + b'\x61\x00' # Left justification -TXT_ALIGN_CT = ESC + b'\x61\x01' # Centering -TXT_ALIGN_RT = ESC + b'\x61\x02' # Right justification -TXT_INVERT_ON = GS + b'\x42\x01' # Inverse Printing ON -TXT_INVERT_OFF = GS + b'\x42\x00' # Inverse Printing OFF + + +TXT_STYLE = { + 'bold': { + False: ESC + b'\x45\x00', # Bold font OFF + True: ESC + b'\x45\x01' # Bold font ON + }, + 'underline': { + 0: ESC + b'\x2d\x00', # Underline font OFF + 1: ESC + b'\x2d\x01', # Underline font 1-dot ON + 2: ESC + b'\x2d\x02' # Underline font 2-dot ON + }, + 'size': { + 'normal': TXT_NORMAL + ESC + b'!\x00', # Normal text + '2h': TXT_NORMAL + ESC + b'!\x10', # Double height text + '2w': TXT_NORMAL + ESC + b'!\x20', # Double width text + '2x': TXT_NORMAL + ESC + b'!\x30' # Quad area text + }, + 'font': { + 'a': ESC + b'\x4d\x00', # Font type A + 'b': ESC + b'\x4d\x00' # Font type B + }, + 'align': { + 'left': ESC + b'\x61\x00', # Left justification + 'center': ESC + b'\x61\x01', # Centering + 'right': ESC + b'\x61\x02' # Right justification + }, + 'invert': { + True: GS + b'\x42\x01', # Inverse Printing ON + False: GS + b'\x42\x00' # Inverse Printing OFF + }, + 'color': { + 'black': ESC + b'\x72\x00', # Default Color + 'red': ESC + b'\x72\x01' # Alternative Color, Usually Red + }, + 'flip': { + True: ESC + b'\x7b\x01', # Flip ON + False: ESC + b'\x7b\x00' # Flip OFF + }, + 'density': { + 0: GS + b'\x7c\x00', # Printing Density -50% + 1: GS + b'\x7c\x01', # Printing Density -37.5% + 2: GS + b'\x7c\x02', # Printing Density -25% + 3: GS + b'\x7c\x03', # Printing Density -12.5% + 4: GS + b'\x7c\x04', # Printing Density 0% + 5: GS + b'\x7c\x08', # Printing Density +50% + 6: GS + b'\x7c\x07', # Printing Density +37.5% + 7: GS + b'\x7c\x06', # Printing Density +25% + 8: GS + b'\x7c\x05' # Printing Density +12.5% + }, + 'smooth': { + True: GS + b'\x62\x01', # Smooth ON + False: GS + b'\x62\x00' # Smooth OFF + }, + 'height': { # Custom text height + 1: 0x00, + 2: 0x01, + 3: 0x02, + 4: 0x03, + 5: 0x04, + 6: 0x05, + 7: 0x06, + 8: 0x07 + }, + 'width': { # Custom text width + 1: 0x00, + 2: 0x10, + 3: 0x20, + 4: 0x30, + 5: 0x40, + 6: 0x50, + 7: 0x60, + 8: 0x70 + } +} # Fonts SET_FONT = lambda n: ESC + b'\x4d' + n TXT_FONT_A = SET_FONT(b'\x00') # Font type A TXT_FONT_B = SET_FONT(b'\x01') # Font type B -# Text colors -TXT_COLOR_BLACK = ESC + b'\x72\x00' # Default Color -TXT_COLOR_RED = ESC + b'\x72\x01' # Alternative Color (Usually Red) - # Spacing LINESPACING_RESET = ESC + b'2' LINESPACING_FUNCS = { @@ -205,14 +244,3 @@ S_RASTER_N = _PRINT_RASTER_IMG(b'\x00') # Set raster image normal size S_RASTER_2W = _PRINT_RASTER_IMG(b'\x01') # Set raster image double width S_RASTER_2H = _PRINT_RASTER_IMG(b'\x02') # Set raster image double height S_RASTER_Q = _PRINT_RASTER_IMG(b'\x03') # Set raster image quadruple - -# Printing Density -PD_N50 = GS + b'\x7c\x00' # Printing Density -50% -PD_N37 = GS + b'\x7c\x01' # Printing Density -37.5% -PD_N25 = GS + b'\x7c\x02' # Printing Density -25% -PD_N12 = GS + b'\x7c\x03' # Printing Density -12.5% -PD_0 = GS + b'\x7c\x04' # Printing Density 0% -PD_P50 = GS + b'\x7c\x08' # Printing Density +50% -PD_P37 = GS + b'\x7c\x07' # Printing Density +37.5% -PD_P25 = GS + b'\x7c\x06' # Printing Density +25% -PD_P12 = GS + b'\x7c\x05' # Printing Density +12.5% diff --git a/src/escpos/escpos.py b/src/escpos/escpos.py index 3faba40..b7040cd 100644 --- a/src/escpos/escpos.py +++ b/src/escpos/escpos.py @@ -21,16 +21,15 @@ import six from .constants import ESC, GS, NUL, QR_ECLEVEL_L, QR_ECLEVEL_M, QR_ECLEVEL_H, QR_ECLEVEL_Q from .constants import QR_MODEL_1, QR_MODEL_2, QR_MICRO, BARCODE_TYPES, BARCODE_HEIGHT, BARCODE_WIDTH -from .constants import TXT_ALIGN_CT, TXT_ALIGN_LT, TXT_ALIGN_RT, BARCODE_FONT_A, BARCODE_FONT_B +from .constants import BARCODE_FONT_A, BARCODE_FONT_B from .constants import BARCODE_TXT_OFF, BARCODE_TXT_BTH, BARCODE_TXT_ABV, BARCODE_TXT_BLW -from .constants import TXT_HEIGHT, TXT_WIDTH, TXT_SIZE, TXT_NORMAL, TXT_SMOOTH_OFF, TXT_SMOOTH_ON -from .constants import TXT_FLIP_OFF, TXT_FLIP_ON, TXT_2WIDTH, TXT_2HEIGHT, TXT_4SQUARE -from .constants import TXT_UNDERL_OFF, TXT_UNDERL_ON, TXT_BOLD_OFF, TXT_BOLD_ON, SET_FONT, TXT_UNDERL2_ON -from .constants import TXT_INVERT_OFF, TXT_INVERT_ON, LINESPACING_FUNCS, LINESPACING_RESET -from .constants import PD_0, PD_N12, PD_N25, PD_N37, PD_N50, PD_P50, PD_P37, PD_P25, PD_P12 +from .constants import TXT_SIZE, TXT_NORMAL +from .constants import SET_FONT +from .constants import LINESPACING_FUNCS, LINESPACING_RESET from .constants import CD_KICK_DEC_SEQUENCE, CD_KICK_5, CD_KICK_2, PAPER_FULL_CUT, PAPER_PART_CUT from .constants import HW_RESET, HW_SELECT, HW_INIT from .constants import CTL_VT, CTL_HT, CTL_CR, CTL_FF, CTL_LF, CTL_SET_HT, PANEL_BUTTON_OFF, PANEL_BUTTON_ON +from .constants import TXT_STYLE from .exceptions import BarcodeTypeError, BarcodeSizeError, TabPosError from .exceptions import CashDrawerError, SetVariableError, BarcodeCodeError @@ -356,7 +355,7 @@ class Escpos(object): # Align Bar Code() if align_ct: - self._raw(TXT_ALIGN_CT) + self._raw(TXT_STYLE['align']['center']) # Height if 1 <= height <= 255: self._raw(BARCODE_HEIGHT + six.int2byte(height)) @@ -421,8 +420,9 @@ class Escpos(object): col_count = self.profile.get_columns(font) if columns is None else columns self.text(textwrap.fill(txt, col_count)) - def set(self, align='left', font='a', text_type='normal', width=1, - height=1, density=9, invert=False, smooth=False, flip=False): + def set(self, align='left', font='a', bold=False, underline=0, width=1, + height=1, density=9, invert=False, smooth=False, flip=False, + size='normal'): """ Set text properties by sending them to the printer :param align: horizontal position for text, possible values are: @@ -453,87 +453,29 @@ class Escpos(object): :param flip: True enables upside-down printing, *default*: False :type invert: bool """ - # Width - if height == 2 and width == 2: - self._raw(TXT_NORMAL) - self._raw(TXT_4SQUARE) - elif height == 2 and width == 1: - self._raw(TXT_NORMAL) - self._raw(TXT_2HEIGHT) - elif width == 2 and height == 1: - self._raw(TXT_NORMAL) - self._raw(TXT_2WIDTH) - elif width == 1 and height == 1: - self._raw(TXT_NORMAL) - elif 1 <= width <= 8 and 1 <= height <= 8 and isinstance(width, int) and isinstance(height, int): - self._raw(TXT_SIZE + six.int2byte(TXT_WIDTH[width] + TXT_HEIGHT[height])) - else: - raise SetVariableError() - # Upside down - if flip: - self._raw(TXT_FLIP_ON) - else: - self._raw(TXT_FLIP_OFF) - # Smoothing - if smooth: - self._raw(TXT_SMOOTH_ON) - else: - self._raw(TXT_SMOOTH_OFF) - # Type - if text_type.upper() == "B": - self._raw(TXT_BOLD_ON) - self._raw(TXT_UNDERL_OFF) - elif text_type.upper() == "U": - self._raw(TXT_BOLD_OFF) - self._raw(TXT_UNDERL_ON) - elif text_type.upper() == "U2": - self._raw(TXT_BOLD_OFF) - self._raw(TXT_UNDERL2_ON) - elif text_type.upper() == "BU": - self._raw(TXT_BOLD_ON) - self._raw(TXT_UNDERL_ON) - elif text_type.upper() == "BU2": - self._raw(TXT_BOLD_ON) - self._raw(TXT_UNDERL2_ON) - elif text_type.upper() == "NORMAL": - self._raw(TXT_BOLD_OFF) - self._raw(TXT_UNDERL_OFF) - # Font - self._raw(SET_FONT(six.int2byte(self.profile.get_font(font)))) - # Align - if align.upper() == "CENTER": - self._raw(TXT_ALIGN_CT) - elif align.upper() == "RIGHT": - self._raw(TXT_ALIGN_RT) - elif align.upper() == "LEFT": - self._raw(TXT_ALIGN_LT) - # Density - if density == 0: - self._raw(PD_N50) - elif density == 1: - self._raw(PD_N37) - elif density == 2: - self._raw(PD_N25) - elif density == 3: - self._raw(PD_N12) - elif density == 4: - self._raw(PD_0) - elif density == 5: - self._raw(PD_P12) - elif density == 6: - self._raw(PD_P25) - elif density == 7: - self._raw(PD_P37) - elif density == 8: - self._raw(PD_P50) - else: # DEFAULT: DOES NOTHING - pass - # Invert Printing - if invert: - self._raw(TXT_INVERT_ON) - else: - self._raw(TXT_INVERT_OFF) + if size in TXT_STYLE['size']: + self._raw(TXT_NORMAL) + self._raw(TXT_STYLE['size'][size]) + elif size == 'custom': + if 1 <= width <= 8 and 1 <= height <= 8 and isinstance(width, int) and\ + isinstance(height, int): + size_byte = TXT_STYLE['width'][width] + TXT_STYLE['height'][height] + self._raw(TXT_SIZE + six.int2byte(size_byte)) + else: + raise SetVariableError() + + self._raw(TXT_STYLE['flip'][flip]) + self._raw(TXT_STYLE['smooth'][smooth]) + self._raw(TXT_STYLE['bold'][bold]) + self._raw(TXT_STYLE['underline'][underline]) + self._raw(SET_FONT(six.int2byte(self.profile.get_font(font)))) + self._raw(TXT_STYLE['align'][align]) + + if density != 9: + self._raw(TXT_STYLE['density'][density]) + + self._raw(TXT_STYLE['invert'][invert]) def line_spacing(self, spacing=None, divisor=180): """ Set line character spacing. diff --git a/test/test_function_set.py b/test/test_function_set.py new file mode 100644 index 0000000..274011e --- /dev/null +++ b/test/test_function_set.py @@ -0,0 +1,280 @@ +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function +from __future__ import unicode_literals + +import six + +import escpos.printer as printer +from escpos.constants import TXT_NORMAL, TXT_STYLE, SET_FONT +from escpos.constants import TXT_SIZE + + +# Default test, please copy and paste this block to test set method calls + +def test_default_values(): + instance = printer.Dummy() + instance.set() + + expected_sequence = ( + TXT_NORMAL, TXT_STYLE['size']['normal'], # Normal text size + TXT_STYLE['flip'][False], # Flip OFF + TXT_STYLE['smooth'][False], # Smooth OFF + TXT_STYLE['bold'][False], # Bold OFF + TXT_STYLE['underline'][0], # Underline OFF + SET_FONT(b'\x00'), # Default font + TXT_STYLE['align']['left'], # Align left + TXT_STYLE['invert'][False] # Inverted OFF + ) + + assert(instance.output == b''.join(expected_sequence)) + +# Size tests + +def test_set_size_2h(): + instance = printer.Dummy() + instance.set(size='2h') + + expected_sequence = ( + TXT_NORMAL, TXT_STYLE['size']['2h'], # Double height text size + TXT_STYLE['flip'][False], # Flip OFF + TXT_STYLE['smooth'][False], # Smooth OFF + TXT_STYLE['bold'][False], # Bold OFF + TXT_STYLE['underline'][0], # Underline OFF + SET_FONT(b'\x00'), # Default font + TXT_STYLE['align']['left'], # Align left + TXT_STYLE['invert'][False] # Inverted OFF + ) + + assert (instance.output == b''.join(expected_sequence)) + + +def test_set_size_2w(): + instance = printer.Dummy() + instance.set(size='2w') + + expected_sequence = ( + TXT_NORMAL, TXT_STYLE['size']['2w'], # Double width text size + TXT_STYLE['flip'][False], # Flip OFF + TXT_STYLE['smooth'][False], # Smooth OFF + TXT_STYLE['bold'][False], # Bold OFF + TXT_STYLE['underline'][0], # Underline OFF + SET_FONT(b'\x00'), # Default font + TXT_STYLE['align']['left'], # Align left + TXT_STYLE['invert'][False] # Inverted OFF + ) + + assert (instance.output == b''.join(expected_sequence)) + + +def test_set_size_2x(): + instance = printer.Dummy() + instance.set(size='2x') + + expected_sequence = ( + TXT_NORMAL, TXT_STYLE['size']['2x'], # Double text size + TXT_STYLE['flip'][False], # Flip OFF + TXT_STYLE['smooth'][False], # Smooth OFF + TXT_STYLE['bold'][False], # Bold OFF + TXT_STYLE['underline'][0], # Underline OFF + SET_FONT(b'\x00'), # Default font + TXT_STYLE['align']['left'], # Align left + TXT_STYLE['invert'][False] # Inverted OFF + ) + + assert (instance.output == b''.join(expected_sequence)) + + +def test_set_size_custom(): + instance = printer.Dummy() + instance.set(size='custom', width=8, height=7) + + expected_sequence = ( + TXT_SIZE, # Custom text size, no normal reset + six.int2byte(TXT_STYLE['width'][8] + TXT_STYLE['height'][7]), + TXT_STYLE['flip'][False], # Flip OFF + TXT_STYLE['smooth'][False], # Smooth OFF + TXT_STYLE['bold'][False], # Bold OFF + TXT_STYLE['underline'][0], # Underline OFF + SET_FONT(b'\x00'), # Default font + TXT_STYLE['align']['left'], # Align left + TXT_STYLE['invert'][False] # Inverted OFF + ) + + assert (instance.output == b''.join(expected_sequence)) + +# Flip + +def test_set_flip(): + instance = printer.Dummy() + instance.set(flip=True) + + expected_sequence = ( + TXT_NORMAL, TXT_STYLE['size']['normal'], # Normal text size + TXT_STYLE['flip'][True], # Flip ON + TXT_STYLE['smooth'][False], # Smooth OFF + TXT_STYLE['bold'][False], # Bold OFF + TXT_STYLE['underline'][0], # Underline OFF + SET_FONT(b'\x00'), # Default font + TXT_STYLE['align']['left'], # Align left + TXT_STYLE['invert'][False] # Inverted OFF + ) + + assert (instance.output == b''.join(expected_sequence)) + +# Smooth + +def test_smooth(): + instance = printer.Dummy() + instance.set(smooth=True) + + expected_sequence = ( + TXT_NORMAL, TXT_STYLE['size']['normal'], # Normal text size + TXT_STYLE['flip'][False], # Flip OFF + TXT_STYLE['smooth'][True], # Smooth ON + TXT_STYLE['bold'][False], # Bold OFF + TXT_STYLE['underline'][0], # Underline OFF + SET_FONT(b'\x00'), # Default font + TXT_STYLE['align']['left'], # Align left + TXT_STYLE['invert'][False] # Inverted OFF + ) + + assert(instance.output == b''.join(expected_sequence)) + + +# Type + + +def test_set_bold(): + instance = printer.Dummy() + instance.set(bold=True) + + expected_sequence = ( + TXT_NORMAL, TXT_STYLE['size']['normal'], # Normal text size + TXT_STYLE['flip'][False], # Flip OFF + TXT_STYLE['smooth'][False], # Smooth OFF + TXT_STYLE['bold'][True], # Bold ON + TXT_STYLE['underline'][0], # Underline OFF + SET_FONT(b'\x00'), # Default font + TXT_STYLE['align']['left'], # Align left + TXT_STYLE['invert'][False] # Inverted OFF + ) + + assert (instance.output == b''.join(expected_sequence)) + + +def test_set_underline(): + instance = printer.Dummy() + instance.set(underline=1) + + expected_sequence = ( + TXT_NORMAL, TXT_STYLE['size']['normal'], # Normal text size + TXT_STYLE['flip'][False], # Flip OFF + TXT_STYLE['smooth'][False], # Smooth OFF + TXT_STYLE['bold'][False], # Bold OFF + TXT_STYLE['underline'][1], # Underline ON, type 1 + SET_FONT(b'\x00'), # Default font + TXT_STYLE['align']['left'], # Align left + TXT_STYLE['invert'][False] # Inverted OFF + ) + + assert (instance.output == b''.join(expected_sequence)) + + +def test_set_underline2(): + instance = printer.Dummy() + instance.set(underline=2) + + expected_sequence = ( + TXT_NORMAL, TXT_STYLE['size']['normal'], # Normal text size + TXT_STYLE['flip'][False], # Flip OFF + TXT_STYLE['smooth'][False], # Smooth OFF + TXT_STYLE['bold'][False], # Bold OFF + TXT_STYLE['underline'][2], # Underline ON, type 2 + SET_FONT(b'\x00'), # Default font + TXT_STYLE['align']['left'], # Align left + TXT_STYLE['invert'][False] # Inverted OFF + ) + + assert (instance.output == b''.join(expected_sequence)) + + +# Align + +def test_align_center(): + instance = printer.Dummy() + instance.set(align='center') + + expected_sequence = ( + TXT_NORMAL, TXT_STYLE['size']['normal'], # Normal text size + TXT_STYLE['flip'][False], # Flip OFF + TXT_STYLE['smooth'][False], # Smooth OFF + TXT_STYLE['bold'][False], # Bold OFF + TXT_STYLE['underline'][0], # Underline OFF + SET_FONT(b'\x00'), # Default font + TXT_STYLE['align']['center'], # Align center + TXT_STYLE['invert'][False] # Inverted OFF + ) + + assert(instance.output == b''.join(expected_sequence)) + + +def test_align_right(): + instance = printer.Dummy() + instance.set(align='right') + + expected_sequence = ( + TXT_NORMAL, TXT_STYLE['size']['normal'], # Normal text size + TXT_STYLE['flip'][False], # Flip OFF + TXT_STYLE['smooth'][False], # Smooth OFF + TXT_STYLE['bold'][False], # Bold OFF + TXT_STYLE['underline'][0], # Underline OFF + SET_FONT(b'\x00'), # Default font + TXT_STYLE['align']['right'], # Align right + TXT_STYLE['invert'][False] # Inverted OFF + ) + + assert(instance.output == b''.join(expected_sequence)) + + +# Densities + +def test_densities(): + + for density in range(8): + instance = printer.Dummy() + instance.set(density=density) + + expected_sequence = ( + TXT_NORMAL, TXT_STYLE['size']['normal'], # Normal text size + TXT_STYLE['flip'][False], # Flip OFF + TXT_STYLE['smooth'][False], # Smooth OFF + TXT_STYLE['bold'][False], # Bold OFF + TXT_STYLE['underline'][0], # Underline OFF + SET_FONT(b'\x00'), # Default font + TXT_STYLE['align']['left'], # Align left + TXT_STYLE['density'][density], # Custom density from 0 to 8 + TXT_STYLE['invert'][False] # Inverted OFF + ) + + assert(instance.output == b''.join(expected_sequence)) + + +# Invert + +def test_invert(): + instance = printer.Dummy() + instance.set(invert=True) + + expected_sequence = ( + TXT_NORMAL, TXT_STYLE['size']['normal'], # Normal text size + TXT_STYLE['flip'][False], # Flip OFF + TXT_STYLE['smooth'][False], # Smooth OFF + TXT_STYLE['bold'][False], # Bold OFF + TXT_STYLE['underline'][0], # Underline OFF + SET_FONT(b'\x00'), # Default font + TXT_STYLE['align']['left'], # Align left + TXT_STYLE['invert'][True] # Inverted ON + ) + + assert(instance.output == b''.join(expected_sequence)) \ No newline at end of file