From e8d91a6735143f6dd57068a7dad70aeeed3d5750 Mon Sep 17 00:00:00 2001 From: Patrick Kanzler Date: Mon, 15 Aug 2016 22:33:23 +0200 Subject: [PATCH 1/9] test add type-check for the qr-printing --- src/escpos/escpos.py | 5 ++--- test/test_function_qr_non-native.py | 32 +++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 3 deletions(-) create mode 100644 test/test_function_qr_non-native.py diff --git a/src/escpos/escpos.py b/src/escpos/escpos.py index c0df537..67a9053 100644 --- a/src/escpos/escpos.py +++ b/src/escpos/escpos.py @@ -157,7 +157,7 @@ class Escpos(object): if not native: # Map ESC/POS error correction levels to python 'qrcode' library constant and render to an image if model != QR_MODEL_2: - raise ValueError("Invalid QR model for qrlib rendering (must be QR_MODEL_2)") + raise ValueError("Invalid QR model for python-qrcode rendering (must be QR_MODEL_2)") python_qr_ec = { QR_ECLEVEL_H: qrcode.constants.ERROR_CORRECT_H, QR_ECLEVEL_L: qrcode.constants.ERROR_CORRECT_L, @@ -168,8 +168,7 @@ class Escpos(object): qr_code.add_data(content) qr_code.make(fit=True) qr_img = qr_code.make_image() - im = qr_img._img.convert("RGB") - # Convert the RGB image in printable image + im = qr_img.convert("RGB") # Convert the RGB image in printable image self.image(im) return # Native 2D code printing diff --git a/test/test_function_qr_non-native.py b/test/test_function_qr_non-native.py new file mode 100644 index 0000000..5c0566a --- /dev/null +++ b/test/test_function_qr_non-native.py @@ -0,0 +1,32 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +"""tests for the non-native part of qr() + +:author: `Patrick Kanzler `_ +:organization: `python-escpos `_ +:copyright: Copyright (c) 2016 `python-escpos `_ +:license: GNU GPL v3 +""" + +from __future__ import absolute_import +from __future__ import division +from __future__ import print_function +from __future__ import unicode_literals + +import mock + +from escpos.printer import Dummy +from PIL import Image + + +@mock.patch('escpos.printer.Dummy.image', spec=Dummy) +def test_type_of_object_passed_to_image_function(img_function): + """ + Test the type of object that is passed to the image function during non-native qr-printing. + + The type should be PIL.Image + """ + d = Dummy() + d.qr("LoremIpsum") + args, kwargs = img_function.call_args + assert isinstance(args[0], Image.Image) From 798893caeea7ebd439dd8217e6549f9cd696cfb7 Mon Sep 17 00:00:00 2001 From: Patrick Kanzler Date: Mon, 15 Aug 2016 23:24:06 +0200 Subject: [PATCH 2/9] refactor access of private member _img of qrcode Since version 2.5 python-qrcode allows the direct access of the PIL-functions. (We require version 4 and above). Thus, we can simply call qr_img.convert() without accessing the private member. This refactoring is identical in functionality. --- src/escpos/escpos.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/escpos/escpos.py b/src/escpos/escpos.py index 67a9053..c0df537 100644 --- a/src/escpos/escpos.py +++ b/src/escpos/escpos.py @@ -157,7 +157,7 @@ class Escpos(object): if not native: # Map ESC/POS error correction levels to python 'qrcode' library constant and render to an image if model != QR_MODEL_2: - raise ValueError("Invalid QR model for python-qrcode rendering (must be QR_MODEL_2)") + raise ValueError("Invalid QR model for qrlib rendering (must be QR_MODEL_2)") python_qr_ec = { QR_ECLEVEL_H: qrcode.constants.ERROR_CORRECT_H, QR_ECLEVEL_L: qrcode.constants.ERROR_CORRECT_L, @@ -168,7 +168,8 @@ class Escpos(object): qr_code.add_data(content) qr_code.make(fit=True) qr_img = qr_code.make_image() - im = qr_img.convert("RGB") # Convert the RGB image in printable image + im = qr_img._img.convert("RGB") + # Convert the RGB image in printable image self.image(im) return # Native 2D code printing From 5c3d7dab722f09e1d98eab9f8bd002acf6029325 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Elsd=C3=B6rfer?= Date: Thu, 25 Aug 2016 15:55:14 +0200 Subject: [PATCH 3/9] Change setup.py shebang. This supports using the current virtualenv. --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 0e3eea5..02d479a 100755 --- a/setup.py +++ b/setup.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python import os import sys From df0c874f6e57453e8ec09a7867da3aff2a5f0d3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Elsd=C3=B6rfer?= Date: Thu, 25 Aug 2016 16:17:58 +0200 Subject: [PATCH 4/9] Add constants for sheet mode, colors. --- src/escpos/constants.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/escpos/constants.py b/src/escpos/constants.py index 93721cb..9ec5eb7 100644 --- a/src/escpos/constants.py +++ b/src/escpos/constants.py @@ -55,11 +55,18 @@ _CUT_PAPER = lambda m: GS + b'V' + m PAPER_FULL_CUT = _CUT_PAPER(b'\x00') # Full cut paper PAPER_PART_CUT = _CUT_PAPER(b'\x01') # Partial cut paper +# Beep +BEEP = b'\x07' + # Panel buttons (e.g. the FEED button) _PANEL_BUTTON = lambda n: ESC + b'c5' + six.int2byte(n) PANEL_BUTTON_ON = _PANEL_BUTTON(0) # enable all panel buttons PANEL_BUTTON_OFF = _PANEL_BUTTON(1) # disable all panel buttons +# Sheet modes +SHEET_SLIP_MODE = ESC + b'\x63\x30\x04' # slip paper +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. @@ -101,6 +108,11 @@ 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 +# Text colors +TXT_COLOR_BLACK = ESC + b'\x72\x00' # Default Color +TXT_COLOR_RED = ESC + b'\x72\x01' # Alternative Color (Usually Red) + + # Char code table CHARCODE_PC437 = ESC + b'\x74\x00' # USA: Standard Europe CHARCODE_JIS = ESC + b'\x74\x01' # Japanese Katakana From 854b75be30c8161f41b41dcae747d86d47d93e9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Elsd=C3=B6rfer?= Date: Thu, 25 Aug 2016 15:56:32 +0200 Subject: [PATCH 5/9] Support changing the line spacing. --- src/escpos/constants.py | 7 +++++++ src/escpos/escpos.py | 23 +++++++++++++++++++++++ test/test_functions.py | 20 ++++++++++++++++++++ 3 files changed, 50 insertions(+) create mode 100644 test/test_functions.py diff --git a/src/escpos/constants.py b/src/escpos/constants.py index 93721cb..703e48b 100644 --- a/src/escpos/constants.py +++ b/src/escpos/constants.py @@ -101,6 +101,13 @@ 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 +# Spacing +LINESPACING_FUNCS = { + 60: ESC + b'A', # line_spacing/60 of an inch, 0 <= line_spacing <= 85 + 360: ESC + b'+', # line_spacing/360 of an inch, 0 <= line_spacing <= 255 + 180: ESC + b'3', # line_spacing/180 of an inch, 0 <= line_spacing <= 255 +} + # Char code table CHARCODE_PC437 = ESC + b'\x74\x00' # USA: Standard Europe CHARCODE_JIS = ESC + b'\x74\x01' # Japanese Katakana diff --git a/src/escpos/escpos.py b/src/escpos/escpos.py index c0df537..99c9308 100644 --- a/src/escpos/escpos.py +++ b/src/escpos/escpos.py @@ -565,6 +565,29 @@ class Escpos(object): else: self._raw(TXT_INVERT_OFF) + def line_spacing(self, spacing=30, divisor=180): + """ Set line character spacing. + + There are different commands for setting the line spacing, using + a different denominator: + + + line_spacing/360 of an inch, 0 <= line_spacing <= 255 + 3 line_spacing/180 of an inch, 0 <= line_spacing <= 255 + A line_spacing/60 of an inch, 0 <= line_spacing <= 85 + + Some printers may not support all of them. The most commonly + available command (using a divisor of 180) is chosen. + """ + if divisor not in LINESPACING_FUNCS: + raise ValueError("divisor must be either 360, 180 or 60") + if (divisor in [360, 180] \ + and (not(0 <= spacing <= 255))): + raise ValueError("spacing must be a int between 0 and 255 when divisor is 360 or 180") + if divisor == 60 and (not(0 <= spacing <= 85)): + raise ValueError("spacing must be a int between 0 and 85 when divisor is 60") + + self._raw(LINESPACING_FUNCS[divisor] + six.int2byte(spacing)) + def cut(self, mode=''): """ Cut paper. diff --git a/test/test_functions.py b/test/test_functions.py new file mode 100644 index 0000000..a78cc14 --- /dev/null +++ b/test/test_functions.py @@ -0,0 +1,20 @@ +from nose.tools import assert_raises +from escpos.printer import Dummy + + +def test_line_spacing_code_gen(): + printer = Dummy() + printer.line_spacing(10) + assert printer.output == '\x1b3\n' + + +def test_line_spacing_error_handling(): + printer = Dummy() + with assert_raises(ValueError): + printer.line_spacing(divisor=44) + with assert_raises(ValueError): + printer.line_spacing(divisor=80, spacing=86) + with assert_raises(ValueError): + printer.line_spacing(divisor=360, spacing=256) + with assert_raises(ValueError): + printer.line_spacing(divisor=180, spacing=256) \ No newline at end of file From 07d47765aad69c6ee5512e3b0580b9ce1f7e95e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Elsd=C3=B6rfer?= Date: Fri, 26 Aug 2016 10:38:36 +0200 Subject: [PATCH 6/9] Allow linespacing reset. Make this the default. --- src/escpos/constants.py | 1 + src/escpos/escpos.py | 8 +++++++- test/test_functions.py | 8 +++++++- 3 files changed, 15 insertions(+), 2 deletions(-) diff --git a/src/escpos/constants.py b/src/escpos/constants.py index 703e48b..999dba1 100644 --- a/src/escpos/constants.py +++ b/src/escpos/constants.py @@ -102,6 +102,7 @@ TXT_INVERT_ON = GS + b'\x42\x01' # Inverse Printing ON TXT_INVERT_OFF = GS + b'\x42\x00' # Inverse Printing OFF # Spacing +LINESPACING_RESET = ESC + b'2' LINESPACING_FUNCS = { 60: ESC + b'A', # line_spacing/60 of an inch, 0 <= line_spacing <= 85 360: ESC + b'+', # line_spacing/360 of an inch, 0 <= line_spacing <= 255 diff --git a/src/escpos/escpos.py b/src/escpos/escpos.py index 99c9308..797b5ed 100644 --- a/src/escpos/escpos.py +++ b/src/escpos/escpos.py @@ -565,9 +565,11 @@ class Escpos(object): else: self._raw(TXT_INVERT_OFF) - def line_spacing(self, spacing=30, divisor=180): + def line_spacing(self, spacing=None, divisor=180): """ Set line character spacing. + If no spacing is given, we reset it to the default. + There are different commands for setting the line spacing, using a different denominator: @@ -578,6 +580,10 @@ class Escpos(object): Some printers may not support all of them. The most commonly available command (using a divisor of 180) is chosen. """ + if spacing is None: + self._raw(LINESPACING_RESET) + return + if divisor not in LINESPACING_FUNCS: raise ValueError("divisor must be either 360, 180 or 60") if (divisor in [360, 180] \ diff --git a/test/test_functions.py b/test/test_functions.py index a78cc14..f35de54 100644 --- a/test/test_functions.py +++ b/test/test_functions.py @@ -8,10 +8,16 @@ def test_line_spacing_code_gen(): assert printer.output == '\x1b3\n' +def test_line_spacing_rest(): + printer = Dummy() + printer.line_spacing() + assert printer.output == '\x1b2' + + def test_line_spacing_error_handling(): printer = Dummy() with assert_raises(ValueError): - printer.line_spacing(divisor=44) + printer.line_spacing(99, divisor=44) with assert_raises(ValueError): printer.line_spacing(divisor=80, spacing=86) with assert_raises(ValueError): From ae9b3785c2d859aecab7d005ca757aab74c471fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Elsd=C3=B6rfer?= Date: Fri, 26 Aug 2016 11:48:58 +0200 Subject: [PATCH 7/9] Fix broken tests. --- test/test_functions.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/test_functions.py b/test/test_functions.py index f35de54..22ee737 100644 --- a/test/test_functions.py +++ b/test/test_functions.py @@ -5,13 +5,13 @@ from escpos.printer import Dummy def test_line_spacing_code_gen(): printer = Dummy() printer.line_spacing(10) - assert printer.output == '\x1b3\n' + assert printer.output == b'\x1b3\n' def test_line_spacing_rest(): printer = Dummy() printer.line_spacing() - assert printer.output == '\x1b2' + assert printer.output == b'\x1b2' def test_line_spacing_error_handling(): From 632a10421960e14645a08e686f0ef0a877c2c728 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michael=20Elsd=C3=B6rfer?= Date: Fri, 26 Aug 2016 11:59:40 +0200 Subject: [PATCH 8/9] Fix docstring warning. --- src/escpos/escpos.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/escpos/escpos.py b/src/escpos/escpos.py index 797b5ed..c102e2c 100644 --- a/src/escpos/escpos.py +++ b/src/escpos/escpos.py @@ -573,9 +573,9 @@ class Escpos(object): There are different commands for setting the line spacing, using a different denominator: - + line_spacing/360 of an inch, 0 <= line_spacing <= 255 - 3 line_spacing/180 of an inch, 0 <= line_spacing <= 255 - A line_spacing/60 of an inch, 0 <= line_spacing <= 85 + '+'' line_spacing/360 of an inch, 0 <= line_spacing <= 255 + '3' line_spacing/180 of an inch, 0 <= line_spacing <= 255 + 'A' line_spacing/60 of an inch, 0 <= line_spacing <= 85 Some printers may not support all of them. The most commonly available command (using a divisor of 180) is chosen. From 6b069a45296d445243da8bb8806e59a060ab9fff Mon Sep 17 00:00:00 2001 From: Patrick Kanzler Date: Fri, 26 Aug 2016 14:27:17 +0200 Subject: [PATCH 9/9] update CHANGELOG --- CHANGELOG.rst | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index c005071..0ff3ed2 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,6 +1,21 @@ ********* Changelog ********* +2016-08-26 - Version 2.2.0 - "Fate Amenable To Change" +------------------------------------------------------ + +changes +^^^^^^^ +- fix improper API-use in qrcode() +- change setup.py shebang to make it compatible with virtualenvs. +- add constants for sheet mode and colors +- support changing the linespacing + +contributors +^^^^^^^^^^^^ +- Michael Elsdörfer +- Patrick Kanzler + 2016-08-10 - Version 2.1.3 - "Ethics Gradient" ----------------------------------------------