add implementation of GS v 0, GS ( L and GS *.
- ported test cases for EscposImage class, copied over 1px and 2px test images from escpos-php - added test cases over image print function - updated QR tests to also include image output check - updated CLI to match new image function options
|
@ -37,8 +37,8 @@ DEMO_FUNCTIONS = {
|
||||||
{'txt': 'Hello, World!\n',}
|
{'txt': 'Hello, World!\n',}
|
||||||
],
|
],
|
||||||
'qr': [
|
'qr': [
|
||||||
{'text': 'This tests a QR code'},
|
{'content': 'This tests a QR code'},
|
||||||
{'text': 'https://en.wikipedia.org/'}
|
{'content': 'https://en.wikipedia.org/'}
|
||||||
],
|
],
|
||||||
'barcodes_a': [
|
'barcodes_a': [
|
||||||
{'bc': 'UPC-A', 'code': '13243546576'},
|
{'bc': 'UPC-A', 'code': '13243546576'},
|
||||||
|
@ -87,7 +87,7 @@ ESCPOS_COMMANDS = [
|
||||||
},
|
},
|
||||||
'arguments': [
|
'arguments': [
|
||||||
{
|
{
|
||||||
'option_strings': ('--text',),
|
'option_strings': ('--content',),
|
||||||
'help': 'Text to print as a qr code',
|
'help': 'Text to print as a qr code',
|
||||||
'required': True,
|
'required': True,
|
||||||
}
|
}
|
||||||
|
@ -223,10 +223,26 @@ ESCPOS_COMMANDS = [
|
||||||
},
|
},
|
||||||
'arguments': [
|
'arguments': [
|
||||||
{
|
{
|
||||||
'option_strings': ('--path_img',),
|
'option_strings': ('--img_source',),
|
||||||
'help': 'Path to image',
|
'help': 'Path to image',
|
||||||
'required': True,
|
'required': True,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
'option_strings': ('--impl',),
|
||||||
|
'help': 'Implementation to use',
|
||||||
|
'choices': ['bitImageRaster', 'bitImageColumn', 'graphics'],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'option_strings': ('--high_density_horizontal',),
|
||||||
|
'help': 'Image density (horizontal)',
|
||||||
|
'type': str_to_bool,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
'option_strings': ('--high_density_vertical',),
|
||||||
|
'help': 'Image density (vertical)',
|
||||||
|
'type': str_to_bool,
|
||||||
|
},
|
||||||
|
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
@ -21,7 +21,7 @@ from .constants import *
|
||||||
from .exceptions import *
|
from .exceptions import *
|
||||||
|
|
||||||
from abc import ABCMeta, abstractmethod # abstract base class support
|
from abc import ABCMeta, abstractmethod # abstract base class support
|
||||||
|
from escpos.image import EscposImage
|
||||||
|
|
||||||
class Escpos(object):
|
class Escpos(object):
|
||||||
""" ESC/POS Printer object
|
""" ESC/POS Printer object
|
||||||
|
@ -49,17 +49,53 @@ class Escpos(object):
|
||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def image(self, path_img):
|
def image(self, img_source, high_density_vertical = True, high_density_horizontal = True, impl = "graphics"):
|
||||||
""" Open and print an image file
|
""" Print an image
|
||||||
|
|
||||||
Prints an image. The image is automatically adjusted in size in order to print it.
|
:param img_source: PIL image or filename to load: `jpg`, `gif`, `png` or `bmp`
|
||||||
|
|
||||||
|
"""
|
||||||
|
im = EscposImage(img_source)
|
||||||
|
|
||||||
|
if impl == "bitImageRaster":
|
||||||
|
# GS v 0, raster format bit image
|
||||||
|
density_byte = (0 if high_density_vertical else 1) + (0 if high_density_horizontal else 2)
|
||||||
|
header = GS + b"v0" + six.int2byte(density_byte) + self._int_low_high(im.width_bytes, 2) + self._int_low_high(im.height, 2);
|
||||||
|
self._raw(header + im.to_raster_format())
|
||||||
|
|
||||||
|
if impl == "graphics":
|
||||||
|
# GS ( L raster format graphics
|
||||||
|
img_header = self._int_low_high(im.width, 2) + self._int_low_high(im.height, 2);
|
||||||
|
tone = b'0';
|
||||||
|
colors = b'1';
|
||||||
|
ym = six.int2byte(1 if high_density_vertical else 2)
|
||||||
|
xm = six.int2byte(1 if high_density_horizontal else 2)
|
||||||
|
header = tone + xm + ym + colors + img_header
|
||||||
|
raster_data = im.to_raster_format()
|
||||||
|
self._image_send_graphics_data(b'0', b'p', header + raster_data);
|
||||||
|
self._image_send_graphics_data(b'0', b'2', b'');
|
||||||
|
|
||||||
|
if impl == "bitImageColumn":
|
||||||
|
# ESC *, column format bit image
|
||||||
|
density_byte = (1 if high_density_horizontal else 0) + (32 if high_density_vertical else 0);
|
||||||
|
header = ESC + b"*" + six.int2byte(density_byte) + self._int_low_high( im.width, 2 );
|
||||||
|
outp = []
|
||||||
|
outp.append(ESC + b"3" + six.int2byte(16)) # Adjust line-feed size
|
||||||
|
for blob in im.to_column_format(high_density_vertical):
|
||||||
|
outp.append(header + blob + b"\n")
|
||||||
|
outp.append(ESC + b"2"); # Reset line-feed size
|
||||||
|
self._raw(b''.join(outp))
|
||||||
|
|
||||||
.. todo:: Seems to be broken. Write test that simply executes function with a dummy printer in order to
|
def _image_send_graphics_data(self, m, fn, data):
|
||||||
check for bugs like these in the future.
|
|
||||||
|
|
||||||
:param path_img: complete filename and path to image of type `jpg`, `gif`, `png` or `bmp`
|
|
||||||
"""
|
"""
|
||||||
pass
|
Wrapper for GS ( L, to calculate and send correct data length.
|
||||||
|
|
||||||
|
:param m: Modifier//variant for function. Usually '0'
|
||||||
|
:param fn: Function number to use, as byte
|
||||||
|
:param data: Data to send
|
||||||
|
"""
|
||||||
|
header = self._int_low_high(len(data) + 2, 2);
|
||||||
|
self._raw(GS + b'(L' + header + m + fn + data)
|
||||||
|
|
||||||
def qr(self, content, ec=QR_ECLEVEL_L, size=3, model=QR_MODEL_2, native=False):
|
def qr(self, content, ec=QR_ECLEVEL_L, size=3, model=QR_MODEL_2, native=False):
|
||||||
""" Print QR Code for the provided string
|
""" Print QR Code for the provided string
|
||||||
|
@ -84,7 +120,7 @@ class Escpos(object):
|
||||||
if not native:
|
if not native:
|
||||||
# Map ESC/POS error correction levels to python 'qrcode' library constant and render to an image
|
# Map ESC/POS error correction levels to python 'qrcode' library constant and render to an image
|
||||||
if model != QR_MODEL_2:
|
if model != QR_MODEL_2:
|
||||||
raise ValueError("Invalid QR mocel for qrlib rendering (must be QR_MODEL_2)")
|
raise ValueError("Invalid QR model for qrlib rendering (must be QR_MODEL_2)")
|
||||||
python_qr_ec = {
|
python_qr_ec = {
|
||||||
QR_ECLEVEL_H: qrcode.constants.ERROR_CORRECT_H,
|
QR_ECLEVEL_H: qrcode.constants.ERROR_CORRECT_H,
|
||||||
QR_ECLEVEL_L: qrcode.constants.ERROR_CORRECT_L,
|
QR_ECLEVEL_L: qrcode.constants.ERROR_CORRECT_L,
|
||||||
|
@ -97,7 +133,7 @@ class Escpos(object):
|
||||||
qr_img = qr_code.make_image()
|
qr_img = qr_code.make_image()
|
||||||
im = qr_img._img.convert("RGB")
|
im = qr_img._img.convert("RGB")
|
||||||
# Convert the RGB image in printable image
|
# Convert the RGB image in printable image
|
||||||
self._convert_image(im)
|
self.image(im)
|
||||||
return
|
return
|
||||||
# Native 2D code printing
|
# Native 2D code printing
|
||||||
cn = b'1' # Code type for QR code
|
cn = b'1' # Code type for QR code
|
||||||
|
|
|
@ -0,0 +1,85 @@
|
||||||
|
""" Image format handling class
|
||||||
|
|
||||||
|
This module contains the image format handler :py:class:`EscposImage`.
|
||||||
|
|
||||||
|
The class is designed to efficiently delegate image processing to
|
||||||
|
PIL, rather than spend CPU cycles looping over pixels.
|
||||||
|
|
||||||
|
:author: `Michael Billington <michael.billington@gmail.com>`_
|
||||||
|
:organization: `python-escpos <https://github.com/python-escpos>`_
|
||||||
|
:copyright: Copyright (c) 2016 Michael Billington <michael.billington@gmail.com>
|
||||||
|
:license: GNU GPL v3
|
||||||
|
"""
|
||||||
|
|
||||||
|
from PIL import Image, ImageOps
|
||||||
|
|
||||||
|
class EscposImage(object):
|
||||||
|
def __init__(self, img_source):
|
||||||
|
"""
|
||||||
|
Load in an image
|
||||||
|
|
||||||
|
:param img_source: PIL.Image, or filename to load one from.
|
||||||
|
"""
|
||||||
|
if isinstance(img_source, Image.Image):
|
||||||
|
img_original = img_source
|
||||||
|
else:
|
||||||
|
img_original = Image.open(img_source)
|
||||||
|
|
||||||
|
# Convert to white RGB background, paste over white background
|
||||||
|
# to strip alpha.
|
||||||
|
img_original = img_original.convert('RGBA')
|
||||||
|
im = Image.new("RGB", img_original.size, (255, 255, 255))
|
||||||
|
im.paste(img_original, mask=img_original.split()[3])
|
||||||
|
# Convert down to greyscale
|
||||||
|
im = im.convert("L")
|
||||||
|
# Invert: Only works on 'L' images
|
||||||
|
im = ImageOps.invert(im)
|
||||||
|
# Pure black and white
|
||||||
|
self._im = im.convert("1")
|
||||||
|
|
||||||
|
@property
|
||||||
|
def width(self):
|
||||||
|
"""
|
||||||
|
Width of image in pixels
|
||||||
|
"""
|
||||||
|
width_pixels, _ = self._im.size
|
||||||
|
return width_pixels
|
||||||
|
|
||||||
|
@property
|
||||||
|
def width_bytes(self):
|
||||||
|
"""
|
||||||
|
Width of image if you use 8 pixels per byte and 0-pad at the end.
|
||||||
|
"""
|
||||||
|
return (self.width + 7) >> 3
|
||||||
|
|
||||||
|
@property
|
||||||
|
def height(self):
|
||||||
|
"""
|
||||||
|
Height of image in pixels
|
||||||
|
"""
|
||||||
|
_, height_pixels = self._im.size
|
||||||
|
return height_pixels
|
||||||
|
|
||||||
|
def to_column_format(self, high_density_vertical = True):
|
||||||
|
"""
|
||||||
|
Extract slices of an image as equal-sized blobs of column-format data.
|
||||||
|
|
||||||
|
:param high_density_vertical: Printed line height in dots
|
||||||
|
"""
|
||||||
|
im = self._im.transpose(Image.ROTATE_270).transpose(Image.FLIP_LEFT_RIGHT)
|
||||||
|
line_height = 24 if high_density_vertical else 8
|
||||||
|
width_pixels, height_pixels = im.size
|
||||||
|
top = 0
|
||||||
|
left = 0
|
||||||
|
while left < width_pixels:
|
||||||
|
box = (left, top, left + line_height, top + height_pixels)
|
||||||
|
im_slice = im.transform((line_height, height_pixels), Image.EXTENT, box)
|
||||||
|
im_bytes = im_slice.tobytes()
|
||||||
|
yield(im_bytes)
|
||||||
|
left += line_height
|
||||||
|
|
||||||
|
def to_raster_format(self):
|
||||||
|
"""
|
||||||
|
Convert image to raster-format binary
|
||||||
|
"""
|
||||||
|
return self._im.tobytes()
|
|
@ -20,7 +20,6 @@ import socket
|
||||||
from .escpos import Escpos
|
from .escpos import Escpos
|
||||||
from .exceptions import *
|
from .exceptions import *
|
||||||
|
|
||||||
|
|
||||||
class Usb(Escpos):
|
class Usb(Escpos):
|
||||||
""" USB printer
|
""" USB printer
|
||||||
|
|
||||||
|
@ -260,3 +259,37 @@ class File(Escpos):
|
||||||
""" Close system file """
|
""" Close system file """
|
||||||
self.device.flush()
|
self.device.flush()
|
||||||
self.device.close()
|
self.device.close()
|
||||||
|
|
||||||
|
class Dummy(Escpos):
|
||||||
|
""" Dummy printer
|
||||||
|
|
||||||
|
This class is used for saving commands to a variable, for use in situations where
|
||||||
|
there is no need to send commands to an actual printer. This includes
|
||||||
|
generating print jobs for later use, or testing output.
|
||||||
|
|
||||||
|
inheritance:
|
||||||
|
|
||||||
|
.. inheritance-diagram:: escpos.printer.Dummy
|
||||||
|
:parts: 1
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
"""
|
||||||
|
|
||||||
|
:param devfile : Device file under dev filesystem
|
||||||
|
"""
|
||||||
|
Escpos.__init__(self, *args, **kwargs)
|
||||||
|
self._output_list = []
|
||||||
|
|
||||||
|
def _raw(self, msg):
|
||||||
|
""" Print any command sent in raw format
|
||||||
|
|
||||||
|
:param msg: arbitrary code to be printed
|
||||||
|
:type msg: bytes
|
||||||
|
"""
|
||||||
|
self._output_list.append(msg)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def output(self):
|
||||||
|
return b''.join(self._output_list)
|
||||||
|
|
After Width: | Height: | Size: 65 B |
After Width: | Height: | Size: 167 B |
After Width: | Height: | Size: 65 B |
After Width: | Height: | Size: 175 B |
After Width: | Height: | Size: 156 B |
After Width: | Height: | Size: 72 B |
After Width: | Height: | Size: 160 B |
After Width: | Height: | Size: 239 B |
After Width: | Height: | Size: 72 B |
After Width: | Height: | Size: 160 B |
After Width: | Height: | Size: 239 B |
|
@ -0,0 +1,115 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
""" Image function tests- Check that image print commands are sent correctly.
|
||||||
|
|
||||||
|
:author: `Michael Billington <michael.billington@gmail.com>`_
|
||||||
|
:organization: `python-escpos <https://github.com/python-escpos>`_
|
||||||
|
:copyright: Copyright (c) 2016 `Michael Billington <michael.billington@gmail.com>`_
|
||||||
|
:license: GNU GPL v3
|
||||||
|
"""
|
||||||
|
|
||||||
|
import escpos.printer as printer
|
||||||
|
from PIL import Image
|
||||||
|
|
||||||
|
# Raster format print
|
||||||
|
def test_bit_image_black():
|
||||||
|
"""
|
||||||
|
Test printing solid black bit image (raster)
|
||||||
|
"""
|
||||||
|
instance = printer.Dummy()
|
||||||
|
instance.image('test/resources/canvas_black.png', impl="bitImageRaster")
|
||||||
|
assert(instance.output == b'\x1dv0\x00\x01\x00\x01\x00\x80')
|
||||||
|
# Same thing w/ object created on the fly, rather than a filename
|
||||||
|
instance = printer.Dummy()
|
||||||
|
im = Image.new("RGB", (1, 1), (0, 0, 0))
|
||||||
|
instance.image(im, impl="bitImageRaster")
|
||||||
|
assert(instance.output == b'\x1dv0\x00\x01\x00\x01\x00\x80')
|
||||||
|
|
||||||
|
def test_bit_image_white():
|
||||||
|
"""
|
||||||
|
Test printing solid white bit image (raster)
|
||||||
|
"""
|
||||||
|
instance = printer.Dummy()
|
||||||
|
instance.image('test/resources/canvas_white.png', impl="bitImageRaster")
|
||||||
|
assert(instance.output == b'\x1dv0\x00\x01\x00\x01\x00\x00')
|
||||||
|
|
||||||
|
def test_bit_image_both():
|
||||||
|
"""
|
||||||
|
Test printing black/white bit image (raster)
|
||||||
|
"""
|
||||||
|
instance = printer.Dummy()
|
||||||
|
instance.image('test/resources/black_white.png', impl="bitImageRaster")
|
||||||
|
assert(instance.output == b'\x1dv0\x00\x01\x00\x02\x00\xc0\x00')
|
||||||
|
|
||||||
|
def test_bit_image_transparent():
|
||||||
|
"""
|
||||||
|
Test printing black/transparent bit image (raster)
|
||||||
|
"""
|
||||||
|
instance = printer.Dummy()
|
||||||
|
instance.image('test/resources/black_transparent.png', impl="bitImageRaster")
|
||||||
|
assert(instance.output == b'\x1dv0\x00\x01\x00\x02\x00\xc0\x00')
|
||||||
|
|
||||||
|
# Column format print
|
||||||
|
def test_bit_image_colfmt_black():
|
||||||
|
"""
|
||||||
|
Test printing solid black bit image (column format)
|
||||||
|
"""
|
||||||
|
instance = printer.Dummy()
|
||||||
|
instance.image('test/resources/canvas_black.png', impl="bitImageColumn")
|
||||||
|
assert(instance.output == b'\x1b3\x10\x1b*!\x01\x00\x80\x00\x00\x0a\x1b2')
|
||||||
|
|
||||||
|
def test_bit_image_colfmt_white():
|
||||||
|
"""
|
||||||
|
Test printing solid white bit image (column format)
|
||||||
|
"""
|
||||||
|
instance = printer.Dummy()
|
||||||
|
instance.image('test/resources/canvas_white.png', impl="bitImageColumn")
|
||||||
|
assert(instance.output == b'\x1b3\x10\x1b*!\x01\x00\x00\x00\x00\x0a\x1b2')
|
||||||
|
|
||||||
|
def test_bit_image_colfmt_both():
|
||||||
|
"""
|
||||||
|
Test printing black/white bit image (column format)
|
||||||
|
"""
|
||||||
|
instance = printer.Dummy()
|
||||||
|
instance.image('test/resources/black_white.png', impl="bitImageColumn")
|
||||||
|
assert(instance.output == b'\x1b3\x10\x1b*!\x02\x00\x80\x00\x00\x80\x00\x00\x0a\x1b2')
|
||||||
|
|
||||||
|
def test_bit_image_colfmt_transparent():
|
||||||
|
"""
|
||||||
|
Test printing black/transparent bit image (column format)
|
||||||
|
"""
|
||||||
|
instance = printer.Dummy()
|
||||||
|
instance.image('test/resources/black_transparent.png', impl="bitImageColumn")
|
||||||
|
assert(instance.output == b'\x1b3\x10\x1b*!\x02\x00\x80\x00\x00\x80\x00\x00\x0a\x1b2')
|
||||||
|
|
||||||
|
# Graphics print
|
||||||
|
def test_graphics_black():
|
||||||
|
"""
|
||||||
|
Test printing solid black graphics
|
||||||
|
"""
|
||||||
|
instance = printer.Dummy()
|
||||||
|
instance.image('test/resources/canvas_black.png', impl="graphics")
|
||||||
|
assert(instance.output == b'\x1d(L\x0b\x000p0\x01\x011\x01\x00\x01\x00\x80\x1d(L\x02\x0002')
|
||||||
|
|
||||||
|
def test_graphics_white():
|
||||||
|
"""
|
||||||
|
Test printing solid white graphics
|
||||||
|
"""
|
||||||
|
instance = printer.Dummy()
|
||||||
|
instance.image('test/resources/canvas_white.png', impl="graphics")
|
||||||
|
assert(instance.output == b'\x1d(L\x0b\x000p0\x01\x011\x01\x00\x01\x00\x00\x1d(L\x02\x0002')
|
||||||
|
|
||||||
|
def test_graphics_both():
|
||||||
|
"""
|
||||||
|
Test printing black/white graphics
|
||||||
|
"""
|
||||||
|
instance = printer.Dummy()
|
||||||
|
instance.image('test/resources/black_white.png', impl="graphics")
|
||||||
|
assert(instance.output == b'\x1d(L\x0c\x000p0\x01\x011\x02\x00\x02\x00\xc0\x00\x1d(L\x02\x0002')
|
||||||
|
|
||||||
|
def test_graphics_transparent():
|
||||||
|
"""
|
||||||
|
Test printing black/transparent graphics
|
||||||
|
"""
|
||||||
|
instance = printer.Dummy()
|
||||||
|
instance.image('test/resources/black_transparent.png', impl="graphics")
|
||||||
|
assert(instance.output == b'\x1d(L\x0c\x000p0\x01\x011\x02\x00\x02\x00\xc0\x00\x1d(L\x02\x0002')
|
|
@ -12,70 +12,78 @@ from __future__ import division
|
||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from nose.tools import with_setup
|
from nose.tools import raises
|
||||||
|
|
||||||
import escpos.printer as printer
|
import escpos.printer as printer
|
||||||
import os
|
|
||||||
from escpos.constants import QR_ECLEVEL_H, QR_MODEL_1
|
from escpos.constants import QR_ECLEVEL_H, QR_MODEL_1
|
||||||
|
|
||||||
devfile = 'testfile'
|
def test_defaults():
|
||||||
|
"""Test QR code with defaults"""
|
||||||
|
instance = printer.Dummy()
|
||||||
def setup_testfile():
|
|
||||||
"""create a testfile as devfile"""
|
|
||||||
fhandle = open(devfile, 'a')
|
|
||||||
try:
|
|
||||||
os.utime(devfile, None)
|
|
||||||
finally:
|
|
||||||
fhandle.close()
|
|
||||||
|
|
||||||
|
|
||||||
def teardown_testfile():
|
|
||||||
"""destroy testfile again"""
|
|
||||||
os.remove(devfile)
|
|
||||||
|
|
||||||
|
|
||||||
@with_setup(setup_testfile, teardown_testfile)
|
|
||||||
def test_function_qr_defaults():
|
|
||||||
"""test QR code with defaults"""
|
|
||||||
instance = printer.File(devfile=devfile)
|
|
||||||
instance.qr("1234", native=True)
|
instance.qr("1234", native=True)
|
||||||
instance.flush()
|
expected = b'\x1d(k\x04\x001A2\x00\x1d(k\x03\x001C\x03\x1d(k\x03\x001E0\x1d' \
|
||||||
with open(devfile, "rb") as f:
|
b'(k\x07\x001P01234\x1d(k\x03\x001Q0'
|
||||||
assert(f.read() == b'\x1d(k\x04\x001A2\x00\x1d(k\x03\x001C\x03\x1d(k\x03\x001E0\x1d(k\x07\x001P01234\x1d(k\x03\x001Q0')
|
assert(instance.output == expected)
|
||||||
|
|
||||||
@with_setup(setup_testfile, teardown_testfile)
|
def test_empty():
|
||||||
def test_function_qr_empty():
|
"""Test QR printing blank code"""
|
||||||
"""test QR printing blank code"""
|
instance = printer.Dummy()
|
||||||
instance = printer.File(devfile=devfile)
|
|
||||||
instance.qr("", native=True)
|
instance.qr("", native=True)
|
||||||
instance.flush()
|
assert(instance.output == b'')
|
||||||
with open(devfile, "rb") as f:
|
|
||||||
assert(f.read() == b'')
|
|
||||||
|
|
||||||
@with_setup(setup_testfile, teardown_testfile)
|
def test_ec():
|
||||||
def test_function_qr_ec():
|
"""Test QR error correction setting"""
|
||||||
"""test QR error correction setting"""
|
instance = printer.Dummy()
|
||||||
instance = printer.File(devfile=devfile)
|
|
||||||
instance.qr("1234", native=True, ec=QR_ECLEVEL_H)
|
instance.qr("1234", native=True, ec=QR_ECLEVEL_H)
|
||||||
instance.flush()
|
expected = b'\x1d(k\x04\x001A2\x00\x1d(k\x03\x001C\x03\x1d(k\x03\x001E3\x1d' \
|
||||||
with open(devfile, "rb") as f:
|
b'(k\x07\x001P01234\x1d(k\x03\x001Q0'
|
||||||
assert(f.read() == b'\x1d(k\x04\x001A2\x00\x1d(k\x03\x001C\x03\x1d(k\x03\x001E3\x1d(k\x07\x001P01234\x1d(k\x03\x001Q0')
|
assert(instance.output == expected)
|
||||||
|
|
||||||
@with_setup(setup_testfile, teardown_testfile)
|
def test_size():
|
||||||
def test_function_qr_size():
|
"""Test QR box size"""
|
||||||
"""test QR box size"""
|
instance = printer.Dummy()
|
||||||
instance = printer.File(devfile=devfile)
|
|
||||||
instance.qr("1234", native=True, size=7)
|
instance.qr("1234", native=True, size=7)
|
||||||
instance.flush()
|
expected = b'\x1d(k\x04\x001A2\x00\x1d(k\x03\x001C\x07\x1d(k\x03\x001E0\x1d' \
|
||||||
with open(devfile, "rb") as f:
|
b'(k\x07\x001P01234\x1d(k\x03\x001Q0'
|
||||||
assert(f.read() == b'\x1d(k\x04\x001A2\x00\x1d(k\x03\x001C\x07\x1d(k\x03\x001E0\x1d(k\x07\x001P01234\x1d(k\x03\x001Q0')
|
assert(instance.output == expected)
|
||||||
|
|
||||||
@with_setup(setup_testfile, teardown_testfile)
|
def test_model():
|
||||||
def test_function_qr_model():
|
"""Test QR model"""
|
||||||
"""test QR model"""
|
instance = printer.Dummy()
|
||||||
instance = printer.File(devfile=devfile)
|
|
||||||
instance.qr("1234", native=True, model=QR_MODEL_1)
|
instance.qr("1234", native=True, model=QR_MODEL_1)
|
||||||
instance.flush()
|
expected = b'\x1d(k\x04\x001A1\x00\x1d(k\x03\x001C\x03\x1d(k\x03\x001E0\x1d' \
|
||||||
with open(devfile, "rb") as f:
|
b'(k\x07\x001P01234\x1d(k\x03\x001Q0'
|
||||||
assert(f.read() == b'\x1d(k\x04\x001A1\x00\x1d(k\x03\x001C\x03\x1d(k\x03\x001E0\x1d(k\x07\x001P01234\x1d(k\x03\x001Q0')
|
assert(instance.output == expected)
|
||||||
|
|
||||||
|
@raises(ValueError)
|
||||||
|
def test_invalid_ec():
|
||||||
|
"""Test invalid QR error correction"""
|
||||||
|
instance = printer.Dummy()
|
||||||
|
instance.qr("1234", native=True, ec=-1)
|
||||||
|
|
||||||
|
@raises(ValueError)
|
||||||
|
def test_invalid_size():
|
||||||
|
"""Test invalid QR size"""
|
||||||
|
instance = printer.Dummy()
|
||||||
|
instance.qr("1234", native=True, size=0)
|
||||||
|
|
||||||
|
@raises(ValueError)
|
||||||
|
def test_invalid_model():
|
||||||
|
"""Test invalid QR model"""
|
||||||
|
instance = printer.Dummy()
|
||||||
|
instance.qr("1234", native=True, model="Hello")
|
||||||
|
|
||||||
|
def test_image():
|
||||||
|
"""Test QR as image"""
|
||||||
|
instance = printer.Dummy()
|
||||||
|
instance.qr("1", native=False, size=1)
|
||||||
|
expected = b'\x1d(LO\x000p0\x01\x011\x17\x00\x17\x00\x00\x00\x00\x7f]\xfcA' \
|
||||||
|
b'\x19\x04]it]et]ItA=\x04\x7fU\xfc\x00\x0c\x00y~t4\x7f =\xa84j\xd9\xf0' \
|
||||||
|
b'\x05\xd4\x90\x00i(\x7f<\xa8A \xd8]\'\xc4]y\xf8]E\x80Ar\x94\x7fR@\x00\x00' \
|
||||||
|
b'\x00\x1d(L\x02\x0002'
|
||||||
|
assert(instance.output == expected)
|
||||||
|
|
||||||
|
@raises(ValueError)
|
||||||
|
def test_image_invalid_model():
|
||||||
|
"""Test unsupported QR model as image"""
|
||||||
|
instance = printer.Dummy()
|
||||||
|
instance.qr("1234", native=False, model=QR_MODEL_1)
|
||||||
|
|
|
@ -0,0 +1,52 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
""" Image tests- Check that images from different source formats are correctly
|
||||||
|
converted to ESC/POS column & raster formats.
|
||||||
|
|
||||||
|
:author: `Michael Billington <michael.billington@gmail.com>`_
|
||||||
|
:organization: `python-escpos <https://github.com/python-escpos>`_
|
||||||
|
:copyright: Copyright (c) 2016 `Michael Billington <michael.billington@gmail.com>`_
|
||||||
|
:license: GNU GPL v3
|
||||||
|
"""
|
||||||
|
|
||||||
|
from escpos.image import EscposImage
|
||||||
|
|
||||||
|
def test_image_black():
|
||||||
|
"""
|
||||||
|
Test rendering solid black image
|
||||||
|
"""
|
||||||
|
for img_format in ['png', 'jpg', 'gif']:
|
||||||
|
_load_and_check_img('canvas_black.' + img_format, 1, 1, b'\x80', [b'\x80'])
|
||||||
|
|
||||||
|
def test_image_black_transparent():
|
||||||
|
"""
|
||||||
|
Test rendering black/transparent image
|
||||||
|
"""
|
||||||
|
for img_format in ['png', 'gif']:
|
||||||
|
_load_and_check_img('black_transparent.' + img_format, 2, 2, b'\xc0\x00', [b'\x80\x80'])
|
||||||
|
|
||||||
|
def test_image_black_white():
|
||||||
|
"""
|
||||||
|
Test rendering black/white image
|
||||||
|
"""
|
||||||
|
for img_format in ['png', 'jpg', 'gif']:
|
||||||
|
_load_and_check_img('black_white.' + img_format, 2, 2, b'\xc0\x00', [b'\x80\x80'])
|
||||||
|
|
||||||
|
def test_image_white():
|
||||||
|
"""
|
||||||
|
Test rendering solid white image
|
||||||
|
"""
|
||||||
|
for img_format in ['png', 'jpg', 'gif']:
|
||||||
|
_load_and_check_img('canvas_white.' + img_format, 1, 1, b'\x00', [b'\x00'])
|
||||||
|
|
||||||
|
def _load_and_check_img(filename, width_expected, height_expected, raster_format_expected, column_format_expected):
|
||||||
|
"""
|
||||||
|
Load an image, and test whether raster & column formatted output, sizes, etc match expectations.
|
||||||
|
"""
|
||||||
|
im = EscposImage('test/resources/' + filename)
|
||||||
|
assert(im.width == width_expected)
|
||||||
|
assert(im.height == height_expected)
|
||||||
|
assert(im.to_raster_format() == raster_format_expected)
|
||||||
|
i = 0
|
||||||
|
for row in im.to_column_format(False):
|
||||||
|
assert(row == column_format_expected[i])
|
||||||
|
i = i + 1
|