mirror of
https://github.com/python-escpos/python-escpos
synced 2025-09-13 09:09:58 +00:00
Compare commits
49 Commits
update-fla
...
update-rea
Author | SHA1 | Date | |
---|---|---|---|
![]() |
ea9a7b3fbb | ||
![]() |
02a47d413c | ||
![]() |
1f9e7bd45a | ||
![]() |
062660e00f | ||
![]() |
6a8cc54b97 | ||
![]() |
6c6fe9bccf | ||
![]() |
c5e46a888d | ||
![]() |
46942820a5 | ||
![]() |
e50e295acc | ||
![]() |
2d7458fa49 | ||
![]() |
a6f635c0d5 | ||
![]() |
2d0f045457 | ||
![]() |
293b8632ff | ||
![]() |
5ff73595b6 | ||
![]() |
4ecab402b8 | ||
![]() |
c56e43da84 | ||
![]() |
88af26f46e | ||
![]() |
9dd966c2a3 | ||
![]() |
a7d959428f | ||
![]() |
8bf0e08659 | ||
![]() |
5ac5a24b50 | ||
![]() |
63252515b5 | ||
![]() |
29a546821b | ||
![]() |
4ddd18279f | ||
![]() |
de761e96e3 | ||
![]() |
ed7bce6932 | ||
![]() |
edd567785c | ||
![]() |
f1054876da | ||
![]() |
490e0657dd | ||
![]() |
b4c32b5a4a | ||
![]() |
40b30225d3 | ||
![]() |
19e3ec6895 | ||
![]() |
df539da854 | ||
![]() |
4534038b39 | ||
![]() |
adf85f7784 | ||
![]() |
aaa8162967 | ||
![]() |
0461adc212 | ||
![]() |
91ff83e506 | ||
![]() |
29ef88f591 | ||
![]() |
7c01a30d6c | ||
![]() |
035c425581 | ||
![]() |
d20646b2a9 | ||
![]() |
206822ac69 | ||
![]() |
dc08792e72 | ||
![]() |
2886075ce9 | ||
![]() |
73fff6291d | ||
![]() |
d5b9d99093 | ||
![]() |
18c51358aa | ||
![]() |
52719c0b7d |
1
.mailmap
1
.mailmap
@@ -12,3 +12,4 @@ Juanmi Taboada <juanmi@juanmitaboada.com> Juanmi Taboada <juanmi@juan
|
|||||||
csoft2k <csoft2k@hotmail.com>
|
csoft2k <csoft2k@hotmail.com>
|
||||||
Sergio Pulgarin <sergio.pulgarin@gmail.com>
|
Sergio Pulgarin <sergio.pulgarin@gmail.com>
|
||||||
reck31 <rakesh.gunduka@gmail.com>
|
reck31 <rakesh.gunduka@gmail.com>
|
||||||
|
Alex Debiasio <alex.debiasio@thinkin.io> <alex.debiasio@studenti.unitn.it>
|
||||||
|
10
.readthedocs.yml
Normal file
10
.readthedocs.yml
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
version: 2
|
||||||
|
formats:
|
||||||
|
- pdf
|
||||||
|
- epub
|
||||||
|
python:
|
||||||
|
version: 3.7
|
||||||
|
install:
|
||||||
|
- requirements: doc/requirements.txt
|
||||||
|
- method: setuptools
|
||||||
|
path: .
|
35
.travis.yml
35
.travis.yml
@@ -1,6 +1,7 @@
|
|||||||
language: python
|
language: python
|
||||||
sudo: false
|
sudo: false
|
||||||
cache: pip
|
cache: pip
|
||||||
|
dist: xenial
|
||||||
git:
|
git:
|
||||||
depth: 100000
|
depth: 100000
|
||||||
addons:
|
addons:
|
||||||
@@ -11,7 +12,23 @@ env:
|
|||||||
global:
|
global:
|
||||||
- ESCPOS_CAPABILITIES_FILE=/home/travis/build/python-escpos/python-escpos/capabilities-data/dist/capabilities.json
|
- ESCPOS_CAPABILITIES_FILE=/home/travis/build/python-escpos/python-escpos/capabilities-data/dist/capabilities.json
|
||||||
matrix:
|
matrix:
|
||||||
|
fast_finish: true
|
||||||
include:
|
include:
|
||||||
|
- name: "Python 3.7 on Windows"
|
||||||
|
os: windows
|
||||||
|
language: shell
|
||||||
|
before_install:
|
||||||
|
- choco install python
|
||||||
|
- pip install tox codecov 'sphinx>=1.5.1'
|
||||||
|
env:
|
||||||
|
- TOXENV=py37
|
||||||
|
- PATH=/c/Python37:/c/Python37/Scripts:$PATH
|
||||||
|
- ESCPOS_CAPABILITIES_FILE=C:/Users/travis/build/python-escpos/python-escpos/capabilities-data/dist/capabilities.json
|
||||||
|
- name: "Python 3.7 on macOS"
|
||||||
|
os: osx
|
||||||
|
osx_image: xcode10.2
|
||||||
|
language: shell
|
||||||
|
env: TOXENV=py37 ESCPOS_CAPABILITIES_FILE=/Users/travis/build/python-escpos/python-escpos/capabilities-data/dist/capabilities.json
|
||||||
- python: 2.7
|
- python: 2.7
|
||||||
env: TOXENV=py27
|
env: TOXENV=py27
|
||||||
- python: 3.4
|
- python: 3.4
|
||||||
@@ -22,25 +39,31 @@ matrix:
|
|||||||
env: TOXENV=py36
|
env: TOXENV=py36
|
||||||
- python: 3.6-dev
|
- python: 3.6-dev
|
||||||
env: TOXENV=py36
|
env: TOXENV=py36
|
||||||
|
- python: 3.7
|
||||||
|
env: TOXENV=py37
|
||||||
- python: 3.7-dev
|
- python: 3.7-dev
|
||||||
env: TOXENV=py37
|
env: TOXENV=py37
|
||||||
|
- python: 3.8-dev
|
||||||
|
env: TOXENV=py38
|
||||||
- python: nightly
|
- python: nightly
|
||||||
env: TOXENV=py37
|
env: TOXENV=py38
|
||||||
- python: pypy
|
- python: pypy
|
||||||
env: TOXENV=pypy
|
env: TOXENV=pypy
|
||||||
- python: pypy3
|
- python: pypy3
|
||||||
env: TOXENV=pypy3
|
env: TOXENV=pypy3
|
||||||
- python: 2.7
|
- python: 3.7
|
||||||
env: TOXENV=docs
|
env: TOXENV=docs
|
||||||
- python: 2.7
|
- python: 3.7
|
||||||
env: TOXENV=flake8
|
|
||||||
- python: 3.6
|
|
||||||
env: TOXENV=flake8
|
env: TOXENV=flake8
|
||||||
allow_failures:
|
allow_failures:
|
||||||
|
- python: 2.7
|
||||||
- python: 3.6-dev
|
- python: 3.6-dev
|
||||||
- python: 3.7-dev
|
- python: 3.7-dev
|
||||||
|
- python: 3.8-dev
|
||||||
- python: nightly
|
- python: nightly
|
||||||
- python: pypy3
|
- python: pypy3
|
||||||
|
- os: windows
|
||||||
|
- os: osx
|
||||||
before_install:
|
before_install:
|
||||||
- pip install tox codecov 'sphinx>=1.5.1'
|
- pip install tox codecov 'sphinx>=1.5.1'
|
||||||
- ./doc/generate_authors.sh --check
|
- ./doc/generate_authors.sh --check
|
||||||
@@ -63,4 +86,4 @@ deploy:
|
|||||||
tags: true
|
tags: true
|
||||||
repo: python-escpos/python-escpos
|
repo: python-escpos/python-escpos
|
||||||
branch: master
|
branch: master
|
||||||
condition: $TRAVIS_PYTHON_VERSION = "3.6"
|
condition: $TRAVIS_PYTHON_VERSION = "3.7"
|
||||||
|
6
AUTHORS
6
AUTHORS
@@ -1,4 +1,6 @@
|
|||||||
Ahmed Tahri
|
Ahmed Tahri
|
||||||
|
akeonly
|
||||||
|
Alex Debiasio
|
||||||
Asuki Kono
|
Asuki Kono
|
||||||
belono
|
belono
|
||||||
Christoph Heuel
|
Christoph Heuel
|
||||||
@@ -8,8 +10,10 @@ Curtis // mashedkeyboard
|
|||||||
Davis Goglin
|
Davis Goglin
|
||||||
Dean Rispin
|
Dean Rispin
|
||||||
Dmytro Katyukha
|
Dmytro Katyukha
|
||||||
|
Gerard Marull-Paretas
|
||||||
Hark
|
Hark
|
||||||
Joel Lehtonen
|
Joel Lehtonen
|
||||||
|
Justin Vieira
|
||||||
kennedy
|
kennedy
|
||||||
Kristi
|
Kristi
|
||||||
ldos
|
ldos
|
||||||
@@ -19,9 +23,11 @@ Michael Billington
|
|||||||
Michael Elsdörfer
|
Michael Elsdörfer
|
||||||
mrwunderbar666
|
mrwunderbar666
|
||||||
Nathan Bookham
|
Nathan Bookham
|
||||||
|
Omer Akram
|
||||||
Patrick Kanzler
|
Patrick Kanzler
|
||||||
primax79
|
primax79
|
||||||
Qian Linfeng
|
Qian Linfeng
|
||||||
|
Ramon Poca
|
||||||
reck31
|
reck31
|
||||||
Renato Lorenzi
|
Renato Lorenzi
|
||||||
Romain Porte
|
Romain Porte
|
||||||
|
@@ -1,6 +1,29 @@
|
|||||||
*********
|
*********
|
||||||
Changelog
|
Changelog
|
||||||
*********
|
*********
|
||||||
|
2019-06-16 - Version 3.0a5 - "Lightly Seared On The Reality Grill"
|
||||||
|
------------------------------------------------------------------
|
||||||
|
This release is the sixth alpha release of the new version 3.0. Please
|
||||||
|
be aware that the API is subject to change until v3.0 is released.
|
||||||
|
|
||||||
|
changes
|
||||||
|
^^^^^^^
|
||||||
|
- allow arbitrary USB arguments in USB-class
|
||||||
|
- add Win32Raw-Printer on Windows-platforms
|
||||||
|
- add and improve Windows support of USB-class
|
||||||
|
- use pyyaml safe_load()
|
||||||
|
- improve doc
|
||||||
|
- implement _read method of Network printer class
|
||||||
|
|
||||||
|
contributors
|
||||||
|
^^^^^^^^^^^^
|
||||||
|
- Patrick Kanzler
|
||||||
|
- Gerard Marull-Paretas
|
||||||
|
- Ramon Poca
|
||||||
|
- akeonly
|
||||||
|
- Omer Akram
|
||||||
|
- Justin Vieira
|
||||||
|
|
||||||
2018-05-15 - Version 3.0a4 - "Kakistocrat"
|
2018-05-15 - Version 3.0a4 - "Kakistocrat"
|
||||||
------------------------------------------
|
------------------------------------------
|
||||||
This release is the fifth alpha release of the new version 3.0. Please
|
This release is the fifth alpha release of the new version 3.0. Please
|
||||||
|
19
README.rst
19
README.rst
@@ -59,12 +59,25 @@ The basic usage is:
|
|||||||
from escpos.printer import Usb
|
from escpos.printer import Usb
|
||||||
|
|
||||||
""" Seiko Epson Corp. Receipt Printer (EPSON TM-T88III) """
|
""" Seiko Epson Corp. Receipt Printer (EPSON TM-T88III) """
|
||||||
p = Usb(0x04b8, 0x0202, 0, profile='TM-T88III')
|
p = Usb(0x04b8, 0x0202, 0, profile="TM-T88III")
|
||||||
p.text('Hello World\n')
|
p.text("Hello World\n")
|
||||||
p.image('logo.gif')
|
p.image("logo.gif")
|
||||||
p.barcode('1324354657687', 'EAN13', 64, 2, '', '')
|
p.barcode('1324354657687', 'EAN13', 64, 2, '', '')
|
||||||
p.cut()
|
p.cut()
|
||||||
|
|
||||||
|
|
||||||
|
Another example based on the Network printer class:
|
||||||
|
|
||||||
|
.. code:: python
|
||||||
|
|
||||||
|
from escpos.printer import Network
|
||||||
|
|
||||||
|
kitchen = Network("192.168.1.100") #Printer IP Address
|
||||||
|
kitchen.text("Hello World\n")
|
||||||
|
kitchen.barcode('1324354657687', 'EAN13', 64, 2, '', '')
|
||||||
|
kitchen.cut()
|
||||||
|
|
||||||
|
|
||||||
The full project-documentation is available on `Read the Docs <https://python-escpos.readthedocs.io>`_.
|
The full project-documentation is available on `Read the Docs <https://python-escpos.readthedocs.io>`_.
|
||||||
|
|
||||||
Contributing
|
Contributing
|
||||||
|
@@ -44,7 +44,7 @@ to have and the second yields the "Output Endpoint" address.
|
|||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
Epson = printer.Usb(0x04b8,0x0202)
|
p = printer.Usb(0x04b8,0x0202)
|
||||||
|
|
||||||
By default the "Interface" number is "0" and the "Output Endpoint"
|
By default the "Interface" number is "0" and the "Output Endpoint"
|
||||||
address is "0x01". If you have other values then you can define them on
|
address is "0x01". If you have other values then you can define them on
|
||||||
@@ -55,7 +55,7 @@ on 0x81 and out\_ep=0x02, then the printer definition should look like:
|
|||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
Generic = printer.Usb(0x1a2b,0x1a2b,0,0x81,0x02)
|
p = printer.Usb(0x1a2b,0x1a2b,0,0x81,0x02)
|
||||||
|
|
||||||
Network printer
|
Network printer
|
||||||
^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^
|
||||||
@@ -67,7 +67,7 @@ IP by DHCP or you set it manually.
|
|||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
Epson = printer.Network('192.168.1.99')
|
p = printer.Network("192.168.1.99")
|
||||||
|
|
||||||
Serial printer
|
Serial printer
|
||||||
^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^
|
||||||
@@ -81,7 +81,10 @@ to.
|
|||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
Epson = printer.Serial('/dev/tty0')
|
p = printer.Serial("/dev/tty0")
|
||||||
|
|
||||||
|
# on a Windows OS serial devices are typically accessible as COM
|
||||||
|
p = printer.Serial("COM1")
|
||||||
|
|
||||||
Other printers
|
Other printers
|
||||||
^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^
|
||||||
@@ -93,7 +96,7 @@ passing the device node name.
|
|||||||
|
|
||||||
::
|
::
|
||||||
|
|
||||||
Epson = printer.File('/dev/usb/lp1')
|
p = printer.File("/dev/usb/lp1")
|
||||||
|
|
||||||
The default is "/dev/usb/lp0", so if the printer is located on that
|
The default is "/dev/usb/lp0", so if the printer is located on that
|
||||||
node, then you don't necessary need to pass the node name.
|
node, then you don't necessary need to pass the node name.
|
||||||
@@ -108,17 +111,17 @@ on a USB interface.
|
|||||||
|
|
||||||
from escpos import *
|
from escpos import *
|
||||||
""" Seiko Epson Corp. Receipt Printer M129 Definitions (EPSON TM-T88IV) """
|
""" Seiko Epson Corp. Receipt Printer M129 Definitions (EPSON TM-T88IV) """
|
||||||
Epson = printer.Usb(0x04b8,0x0202)
|
p = printer.Usb(0x04b8,0x0202)
|
||||||
# Print text
|
# Print text
|
||||||
Epson.text('Hello World\n')
|
p.text("Hello World\n")
|
||||||
# Print image
|
# Print image
|
||||||
Epson.image('logo.gif')
|
p.image("logo.gif")
|
||||||
# Print QR Code
|
# Print QR Code
|
||||||
Epson.qr('You can readme from your smartphone')
|
p.qr("You can readme from your smartphone")
|
||||||
# Print barcode
|
# Print barcode
|
||||||
Epson.barcode('1324354657687','EAN13',64,2,'','')
|
p.barcode('1324354657687','EAN13',64,2,'','')
|
||||||
# Cut paper
|
# Cut paper
|
||||||
Epson.cut()
|
p.cut()
|
||||||
|
|
||||||
Configuration File
|
Configuration File
|
||||||
------------------
|
------------------
|
||||||
@@ -214,7 +217,7 @@ advantage of the fact that `_raw()` accepts binary strings.)
|
|||||||
from escpos import printer
|
from escpos import printer
|
||||||
p = printer.Serial() # adapt this to your printer model
|
p = printer.Serial() # adapt this to your printer model
|
||||||
|
|
||||||
file = open('binary-blob.bin', 'rb') # read in the file containing your commands in binary-mode
|
file = open("binary-blob.bin", "rb") # read in the file containing your commands in binary-mode
|
||||||
data = file.read()
|
data = file.read()
|
||||||
file.close()
|
file.close()
|
||||||
|
|
||||||
@@ -273,8 +276,8 @@ This is probably best explained by an example:
|
|||||||
d = Dummy()
|
d = Dummy()
|
||||||
|
|
||||||
# create ESC/POS for the print job, this should go really fast
|
# create ESC/POS for the print job, this should go really fast
|
||||||
d.text('This is my image:\n')
|
d.text("This is my image:\n")
|
||||||
d.image('funny_cat.png')
|
d.image("funny_cat.png")
|
||||||
d.cut()
|
d.cut()
|
||||||
|
|
||||||
# send code to printer
|
# send code to printer
|
||||||
|
@@ -1,14 +1,8 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
from __future__ import absolute_import
|
|
||||||
from __future__ import division
|
|
||||||
from __future__ import print_function
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
|
|
||||||
from escpos.printer import Usb
|
from escpos.printer import Usb
|
||||||
|
|
||||||
|
|
||||||
# Adapt to your needs
|
# Adapt to your needs
|
||||||
p = Usb(0x0416, 0x5011, profile='POS-5890')
|
p = Usb(0x0416, 0x5011, profile="POS-5890")
|
||||||
|
|
||||||
# Print software and then hardware barcode with the same content
|
# Print software and then hardware barcode with the same content
|
||||||
p.soft_barcode('code39', '123456')
|
p.soft_barcode('code39', '123456')
|
||||||
|
@@ -1,17 +1,13 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
"""Prints code page tables.
|
"""Prints code page tables.
|
||||||
"""
|
"""
|
||||||
from __future__ import absolute_import
|
|
||||||
from __future__ import division
|
|
||||||
from __future__ import print_function
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
|
|
||||||
|
from __future__ import print_function
|
||||||
|
|
||||||
|
import six
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from escpos import printer
|
from escpos import printer
|
||||||
from escpos.constants import CODEPAGE_CHANGE, CTL_CR, CTL_FF, CTL_HT, CTL_LF, CTL_VT, ESC
|
from escpos.constants import CODEPAGE_CHANGE, ESC, CTL_LF, CTL_FF, CTL_CR, CTL_HT, CTL_VT
|
||||||
|
|
||||||
import six
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
@@ -21,9 +17,9 @@ def main():
|
|||||||
|
|
||||||
for codepage in sys.argv[1:] or ['USA']:
|
for codepage in sys.argv[1:] or ['USA']:
|
||||||
dummy.set(height=2, width=2)
|
dummy.set(height=2, width=2)
|
||||||
dummy._raw(codepage + '\n\n\n')
|
dummy._raw(codepage + "\n\n\n")
|
||||||
print_codepage(dummy, codepage)
|
print_codepage(dummy, codepage)
|
||||||
dummy._raw('\n\n')
|
dummy._raw("\n\n")
|
||||||
|
|
||||||
dummy.cut()
|
dummy.cut()
|
||||||
|
|
||||||
@@ -34,22 +30,22 @@ def print_codepage(printer, codepage):
|
|||||||
if codepage.isdigit():
|
if codepage.isdigit():
|
||||||
codepage = int(codepage)
|
codepage = int(codepage)
|
||||||
printer._raw(CODEPAGE_CHANGE + six.int2byte(codepage))
|
printer._raw(CODEPAGE_CHANGE + six.int2byte(codepage))
|
||||||
printer._raw('after')
|
printer._raw("after")
|
||||||
else:
|
else:
|
||||||
printer.charcode(codepage)
|
printer.charcode(codepage)
|
||||||
|
|
||||||
sep = ''
|
sep = ""
|
||||||
|
|
||||||
# Table header
|
# Table header
|
||||||
printer.set(font='b')
|
printer.set(font='b')
|
||||||
printer._raw(' {}\n'.format(sep.join(map(lambda s: hex(s)[2:], range(0, 16)))))
|
printer._raw(" {}\n".format(sep.join(map(lambda s: hex(s)[2:], range(0, 16)))))
|
||||||
printer.set()
|
printer.set()
|
||||||
|
|
||||||
# The table
|
# The table
|
||||||
for x in range(0, 16):
|
for x in range(0, 16):
|
||||||
# First column
|
# First column
|
||||||
printer.set(font='b')
|
printer.set(font='b')
|
||||||
printer._raw('{} '.format(hex(x)[2:]))
|
printer._raw("{} ".format(hex(x)[2:]))
|
||||||
printer.set()
|
printer.set()
|
||||||
|
|
||||||
for y in range(0, 16):
|
for y in range(0, 16):
|
||||||
|
@@ -1,16 +1,10 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
from __future__ import absolute_import
|
|
||||||
from __future__ import division
|
|
||||||
from __future__ import print_function
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from escpos.printer import Usb
|
from escpos.printer import Usb
|
||||||
|
|
||||||
|
|
||||||
def usage():
|
def usage():
|
||||||
print('usage: qr_code.py <content>')
|
print("usage: qr_code.py <content>")
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
@@ -21,5 +15,5 @@ if __name__ == '__main__':
|
|||||||
content = sys.argv[1]
|
content = sys.argv[1]
|
||||||
|
|
||||||
# Adapt to your needs
|
# Adapt to your needs
|
||||||
p = Usb(0x0416, 0x5011, profile='POS-5890')
|
p = Usb(0x0416, 0x5011, profile="POS-5890")
|
||||||
p.qr(content, center=True)
|
p.qr(content, center=True)
|
||||||
|
@@ -1,14 +1,8 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
from __future__ import absolute_import
|
|
||||||
from __future__ import division
|
|
||||||
from __future__ import print_function
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
|
|
||||||
from escpos.printer import Usb
|
from escpos.printer import Usb
|
||||||
|
|
||||||
|
|
||||||
# Adapt to your needs
|
# Adapt to your needs
|
||||||
p = Usb(0x0416, 0x5011, profile='POS-5890')
|
p = Usb(0x0416, 0x5011, profile="POS-5890")
|
||||||
|
|
||||||
# Some software barcodes
|
# Some software barcodes
|
||||||
p.soft_barcode('code128', 'Hello')
|
p.soft_barcode('code128', 'Hello')
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/python
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
# Adapted script from Adafruit
|
# Adapted script from Adafruit
|
||||||
# Weather forecast for Raspberry Pi w/Adafruit Mini Thermal Printer.
|
# Weather forecast for Raspberry Pi w/Adafruit Mini Thermal Printer.
|
||||||
@@ -12,38 +12,35 @@
|
|||||||
# Icons taken from http://adamwhitcroft.com/climacons/
|
# Icons taken from http://adamwhitcroft.com/climacons/
|
||||||
# Check out his github: https://github.com/AdamWhitcroft/climacons
|
# Check out his github: https://github.com/AdamWhitcroft/climacons
|
||||||
|
|
||||||
from __future__ import absolute_import
|
|
||||||
from __future__ import division
|
|
||||||
from __future__ import print_function
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
|
|
||||||
import calendar
|
from __future__ import print_function
|
||||||
import json
|
|
||||||
import os
|
|
||||||
import time
|
|
||||||
import urllib
|
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
import calendar
|
||||||
|
import urllib
|
||||||
|
import json
|
||||||
|
import time
|
||||||
|
import os
|
||||||
|
|
||||||
from escpos.printer import Usb
|
from escpos.printer import Usb
|
||||||
|
|
||||||
""" Setting up the main pathing """
|
""" Setting up the main pathing """
|
||||||
this_dir, this_filename = os.path.split(__file__)
|
this_dir, this_filename = os.path.split(__file__)
|
||||||
GRAPHICS_PATH = os.path.join(this_dir, 'graphics/climacons/')
|
GRAPHICS_PATH = os.path.join(this_dir, "graphics/climacons/")
|
||||||
|
|
||||||
# Adapt to your needs
|
# Adapt to your needs
|
||||||
printer = Usb(0x0416, 0x5011, profile='POS-5890')
|
printer = Usb(0x0416, 0x5011, profile="POS-5890")
|
||||||
|
|
||||||
# You can get your API Key on www.darksky.net and register a dev account.
|
# You can get your API Key on www.darksky.net and register a dev account.
|
||||||
# Technically you can use any other weather service, of course :)
|
# Technically you can use any other weather service, of course :)
|
||||||
API_KEY = 'YOUR API KEY'
|
API_KEY = "YOUR API KEY"
|
||||||
|
|
||||||
LAT = '22.345490' # Your Location
|
LAT = "22.345490" # Your Location
|
||||||
LONG = '114.189945' # Your Location
|
LONG = "114.189945" # Your Location
|
||||||
|
|
||||||
|
|
||||||
def forecast_icon(idx):
|
def forecast_icon(idx):
|
||||||
icon = data['daily']['data'][idx]['icon']
|
icon = data['daily']['data'][idx]['icon']
|
||||||
image = GRAPHICS_PATH + icon + '.png'
|
image = GRAPHICS_PATH + icon + ".png"
|
||||||
return image
|
return image
|
||||||
|
|
||||||
|
|
||||||
@@ -83,23 +80,23 @@ def forecast(idx):
|
|||||||
|
|
||||||
def icon():
|
def icon():
|
||||||
icon = data['currently']['icon']
|
icon = data['currently']['icon']
|
||||||
image = GRAPHICS_PATH + icon + '.png'
|
image = GRAPHICS_PATH + icon + ".png"
|
||||||
return image
|
return image
|
||||||
|
|
||||||
|
|
||||||
deg = ' C' # Degree symbol on thermal printer, need to find a better way to use a proper degree symbol
|
deg = ' C' # Degree symbol on thermal printer, need to find a better way to use a proper degree symbol
|
||||||
|
|
||||||
# if you want Fahrenheit change units= to 'us'
|
# if you want Fahrenheit change units= to 'us'
|
||||||
url = 'https://api.darksky.net/forecast/' + API_KEY + '/' + LAT + ',' + LONG + \
|
url = "https://api.darksky.net/forecast/" + API_KEY + "/" + LAT + "," + LONG + \
|
||||||
'?exclude=[alerts,minutely,hourly,flags]&units=si' # change last bit to 'us' for Fahrenheit
|
"?exclude=[alerts,minutely,hourly,flags]&units=si" # change last bit to 'us' for Fahrenheit
|
||||||
response = urllib.urlopen(url)
|
response = urllib.urlopen(url)
|
||||||
data = json.loads(response.read())
|
data = json.loads(response.read())
|
||||||
|
|
||||||
printer.print_and_feed(n=1)
|
printer.print_and_feed(n=1)
|
||||||
printer.control('LF')
|
printer.control("LF")
|
||||||
printer.set(font='a', height=2, align='center', bold=True, double_height=True)
|
printer.set(font='a', height=2, align='center', bold=True, double_height=True)
|
||||||
printer.text('Weather Forecast')
|
printer.text("Weather Forecast")
|
||||||
printer.text('\n')
|
printer.text("\n")
|
||||||
printer.set(align='center')
|
printer.set(align='center')
|
||||||
|
|
||||||
|
|
||||||
@@ -107,7 +104,7 @@ printer.set(align='center')
|
|||||||
printer.set(font='a', height=2, align='center', bold=True, double_height=False)
|
printer.set(font='a', height=2, align='center', bold=True, double_height=False)
|
||||||
printer.text('Current conditions: \n')
|
printer.text('Current conditions: \n')
|
||||||
printer.image(icon())
|
printer.image(icon())
|
||||||
printer.text('\n')
|
printer.text("\n")
|
||||||
|
|
||||||
printer.set(font='a', height=2, align='left', bold=False, double_height=False)
|
printer.set(font='a', height=2, align='left', bold=False, double_height=False)
|
||||||
temp = data['currently']['temperature']
|
temp = data['currently']['temperature']
|
||||||
@@ -127,4 +124,4 @@ printer.text('Forecast: \n')
|
|||||||
forecast(0)
|
forecast(0)
|
||||||
forecast(1)
|
forecast(1)
|
||||||
printer.cut()
|
printer.cut()
|
||||||
printer.control('LF')
|
printer.control("LF")
|
||||||
|
@@ -1,7 +0,0 @@
|
|||||||
formats:
|
|
||||||
- pdf
|
|
||||||
- epub
|
|
||||||
requirements_file: doc/requirements.txt
|
|
||||||
python:
|
|
||||||
version: 2
|
|
||||||
setup_py_install: true
|
|
11
setup.cfg
11
setup.cfg
@@ -9,13 +9,4 @@ universal=1
|
|||||||
[flake8]
|
[flake8]
|
||||||
exclude = .git,.tox,.github,.eggs,__pycache__,doc/conf.py,build,dist,capabilities-data,test,src/escpos/constants.py
|
exclude = .git,.tox,.github,.eggs,__pycache__,doc/conf.py,build,dist,capabilities-data,test,src/escpos/constants.py
|
||||||
max-line-length = 120
|
max-line-length = 120
|
||||||
accept-encoding = utf-8, utf-16
|
# future-imports = absolute_import, division, print_function, unicode_literals # we are not there yet
|
||||||
require-code = True
|
|
||||||
# FI12 __future__ import "with_statement" missing
|
|
||||||
# FI15 __future__ import "generator_stop" missing
|
|
||||||
# FI16 __future__ import "nested_scopes" missing
|
|
||||||
# FI17 __future__ import "generators" missing
|
|
||||||
# FI5x __future__ import "xxx" present
|
|
||||||
# I101 Imported names are in the wrong order.
|
|
||||||
ignore = FI12,FI15,FI16,FI17,FI5, I101
|
|
||||||
copyright-check = True
|
|
||||||
|
17
setup.py
17
setup.py
@@ -1,19 +1,12 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
from __future__ import absolute_import
|
|
||||||
from __future__ import division
|
|
||||||
from __future__ import print_function
|
|
||||||
# from __future__ import unicode_literals
|
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
from setuptools import find_packages, setup
|
from setuptools import find_packages, setup
|
||||||
|
|
||||||
|
|
||||||
base_dir = os.path.dirname(__file__)
|
base_dir = os.path.dirname(__file__)
|
||||||
src_dir = os.path.join(base_dir, 'src')
|
src_dir = os.path.join(base_dir, "src")
|
||||||
|
|
||||||
# When executing the setup.py, we need to be able to import ourselves, this
|
# When executing the setup.py, we need to be able to import ourselves, this
|
||||||
# means that we need to add the src/ directory to the sys.path.
|
# means that we need to add the src/ directory to the sys.path.
|
||||||
@@ -61,8 +54,8 @@ setup(
|
|||||||
'receipt,',
|
'receipt,',
|
||||||
],
|
],
|
||||||
platforms='any',
|
platforms='any',
|
||||||
package_dir={'': 'src'},
|
package_dir={"": "src"},
|
||||||
packages=find_packages(where='src', exclude=['tests', 'tests.*']),
|
packages=find_packages(where="src", exclude=["tests", "tests.*"]),
|
||||||
package_data={'': ['COPYING', 'src/escpos/capabilities.json']},
|
package_data={'': ['COPYING', 'src/escpos/capabilities.json']},
|
||||||
include_package_data=True,
|
include_package_data=True,
|
||||||
classifiers=[
|
classifiers=[
|
||||||
@@ -72,8 +65,6 @@ setup(
|
|||||||
'License :: OSI Approved :: MIT License',
|
'License :: OSI Approved :: MIT License',
|
||||||
'Operating System :: OS Independent',
|
'Operating System :: OS Independent',
|
||||||
'Programming Language :: Python',
|
'Programming Language :: Python',
|
||||||
'Programming Language :: Python :: 2',
|
|
||||||
'Programming Language :: Python :: 2.7',
|
|
||||||
'Programming Language :: Python :: 3',
|
'Programming Language :: Python :: 3',
|
||||||
'Programming Language :: Python :: 3.4',
|
'Programming Language :: Python :: 3.4',
|
||||||
'Programming Language :: Python :: 3.5',
|
'Programming Language :: Python :: 3.5',
|
||||||
@@ -109,7 +100,7 @@ setup(
|
|||||||
'nose',
|
'nose',
|
||||||
'scripttest',
|
'scripttest',
|
||||||
'mock',
|
'mock',
|
||||||
'hypothesis!=3.56.9',
|
'hypothesis!=3.56.9,<4',
|
||||||
'flake8'
|
'flake8'
|
||||||
],
|
],
|
||||||
entry_points={
|
entry_points={
|
||||||
|
@@ -7,7 +7,7 @@ from __future__ import division
|
|||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
__all__ = ['constants', 'escpos', 'exceptions', 'printer']
|
__all__ = ["constants", "escpos", "exceptions", "printer"]
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from .version import version as __version__ # noqa
|
from .version import version as __version__ # noqa
|
||||||
|
@@ -1,23 +1,15 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
from __future__ import absolute_import
|
|
||||||
from __future__ import division
|
|
||||||
from __future__ import print_function
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
|
|
||||||
import logging
|
|
||||||
import pickle
|
|
||||||
import platform
|
|
||||||
import re
|
import re
|
||||||
import time
|
|
||||||
from os import environ, path
|
from os import environ, path
|
||||||
from tempfile import gettempdir
|
import pickle
|
||||||
|
import logging
|
||||||
|
import time
|
||||||
|
|
||||||
import six
|
import six
|
||||||
|
|
||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
|
from tempfile import gettempdir
|
||||||
|
import platform
|
||||||
|
|
||||||
logging.basicConfig()
|
logging.basicConfig()
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@@ -46,7 +38,7 @@ else:
|
|||||||
if full_load:
|
if full_load:
|
||||||
logger.debug('Loading and pickling capabilities')
|
logger.debug('Loading and pickling capabilities')
|
||||||
with open(capabilities_path) as cp, open(pickle_path, 'wb') as pp:
|
with open(capabilities_path) as cp, open(pickle_path, 'wb') as pp:
|
||||||
CAPABILITIES = yaml.load(cp)
|
CAPABILITIES = yaml.safe_load(cp)
|
||||||
pickle.dump(CAPABILITIES, pp, protocol=2)
|
pickle.dump(CAPABILITIES, pp, protocol=2)
|
||||||
|
|
||||||
logger.debug('Finished loading capabilities took %.2fs', time.time() - t0)
|
logger.debug('Finished loading capabilities took %.2fs', time.time() - t0)
|
||||||
|
@@ -1,5 +1,4 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/env python
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
# PYTHON_ARGCOMPLETE_OK
|
# PYTHON_ARGCOMPLETE_OK
|
||||||
""" CLI
|
""" CLI
|
||||||
|
|
||||||
@@ -16,15 +15,13 @@ from __future__ import print_function
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import sys
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import argcomplete
|
import argcomplete
|
||||||
except ImportError:
|
except ImportError:
|
||||||
# this CLI works nevertheless without argcomplete
|
# this CLI works nevertheless without argcomplete
|
||||||
pass # noqa
|
pass # noqa
|
||||||
|
import sys
|
||||||
import six
|
import six
|
||||||
|
|
||||||
from . import config
|
from . import config
|
||||||
from . import version
|
from . import version
|
||||||
|
|
||||||
@@ -553,7 +550,7 @@ def main():
|
|||||||
# print command with args
|
# print command with args
|
||||||
getattr(printer, target_command)(**command_arguments)
|
getattr(printer, target_command)(**command_arguments)
|
||||||
if target_command in REQUIRES_NEWLINE:
|
if target_command in REQUIRES_NEWLINE:
|
||||||
printer.text('\n')
|
printer.text("\n")
|
||||||
else:
|
else:
|
||||||
command_arguments['printer'] = printer
|
command_arguments['printer'] = printer
|
||||||
globals()[target_command](**command_arguments)
|
globals()[target_command](**command_arguments)
|
||||||
|
@@ -1,11 +1,3 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
# -*- coding: utf-8 -*-
|
|
||||||
|
|
||||||
from __future__ import absolute_import
|
|
||||||
from __future__ import division
|
|
||||||
from __future__ import print_function
|
|
||||||
from __future__ import unicode_literals
|
|
||||||
|
|
||||||
from .capabilities import CAPABILITIES
|
from .capabilities import CAPABILITIES
|
||||||
|
|
||||||
|
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
""" ESC/POS configuration manager.
|
""" ESC/POS configuration manager.
|
||||||
|
|
||||||
This module contains the implentations of abstract base class :py:class:`Config`.
|
This module contains the implentations of abstract base class :py:class:`Config`.
|
||||||
@@ -11,13 +10,11 @@ from __future__ import print_function
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
|
||||||
import appdirs
|
import appdirs
|
||||||
|
|
||||||
import yaml
|
import yaml
|
||||||
|
|
||||||
from . import exceptions
|
|
||||||
from . import printer
|
from . import printer
|
||||||
|
from . import exceptions
|
||||||
|
|
||||||
|
|
||||||
class Config(object):
|
class Config(object):
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/python
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
""" Main class
|
""" Main class
|
||||||
|
|
||||||
@@ -15,41 +15,42 @@ from __future__ import division
|
|||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
import os
|
import qrcode
|
||||||
import textwrap
|
import textwrap
|
||||||
|
import six
|
||||||
import time
|
import time
|
||||||
from abc import ABCMeta, abstractmethod # abstract base class support
|
|
||||||
from re import match as re_match
|
from re import match as re_match
|
||||||
|
|
||||||
import barcode
|
import barcode
|
||||||
from barcode.writer import ImageWriter
|
from barcode.writer import ImageWriter
|
||||||
|
|
||||||
import qrcode
|
import os
|
||||||
|
|
||||||
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 .capabilities import BARCODE_B, get_profile
|
|
||||||
from .constants import BARCODE_FONT_A, BARCODE_FONT_B, BARCODE_FORMATS
|
from .constants import BARCODE_FONT_A, BARCODE_FONT_B, BARCODE_FORMATS
|
||||||
from .constants import BARCODE_TXT_OFF, BARCODE_TXT_BTH, BARCODE_TXT_ABV, BARCODE_TXT_BLW
|
from .constants import BARCODE_TXT_OFF, BARCODE_TXT_BTH, BARCODE_TXT_ABV, BARCODE_TXT_BLW
|
||||||
from .constants import BARCODE_TYPES, BARCODE_HEIGHT, BARCODE_WIDTH
|
from .constants import TXT_SIZE, TXT_NORMAL
|
||||||
from .constants import CD_KICK_DEC_SEQUENCE, CD_KICK_5, CD_KICK_2, PAPER_FULL_CUT, PAPER_PART_CUT
|
from .constants import SET_FONT
|
||||||
from .constants import CTL_VT, CTL_CR, CTL_FF, CTL_LF, CTL_SET_HT, PANEL_BUTTON_OFF, PANEL_BUTTON_ON
|
|
||||||
from .constants import ESC, GS, NUL, QR_ECLEVEL_L, QR_ECLEVEL_M, QR_ECLEVEL_H, QR_ECLEVEL_Q
|
|
||||||
from .constants import HW_INIT, HW_RESET, HW_SELECT
|
|
||||||
from .constants import LINESPACING_FUNCS, LINESPACING_RESET
|
from .constants import LINESPACING_FUNCS, LINESPACING_RESET
|
||||||
from .constants import LINE_DISPLAY_OPEN, LINE_DISPLAY_CLEAR, LINE_DISPLAY_CLOSE
|
from .constants import LINE_DISPLAY_OPEN, LINE_DISPLAY_CLEAR, LINE_DISPLAY_CLOSE
|
||||||
from .constants import QR_MODEL_1, QR_MODEL_2, QR_MICRO
|
from .constants import CD_KICK_DEC_SEQUENCE, CD_KICK_5, CD_KICK_2, PAPER_FULL_CUT, PAPER_PART_CUT
|
||||||
from .constants import RT_MASK_ONLINE, RT_STATUS_ONLINE
|
from .constants import HW_RESET, HW_SELECT, HW_INIT
|
||||||
from .constants import RT_STATUS_PAPER, RT_MASK_PAPER, RT_MASK_LOWPAPER, RT_MASK_NOPAPER
|
from .constants import CTL_VT, CTL_CR, CTL_FF, CTL_LF, CTL_SET_HT, PANEL_BUTTON_OFF, PANEL_BUTTON_ON
|
||||||
from .constants import SET_FONT
|
|
||||||
from .constants import TXT_SIZE, TXT_NORMAL
|
|
||||||
from .constants import TXT_STYLE
|
from .constants import TXT_STYLE
|
||||||
from .exceptions import BarcodeCodeError, BarcodeSizeError, BarcodeTypeError
|
from .constants import RT_STATUS_ONLINE, RT_MASK_ONLINE
|
||||||
from .exceptions import CashDrawerError, ImageWidthError
|
from .constants import RT_STATUS_PAPER, RT_MASK_PAPER, RT_MASK_LOWPAPER, RT_MASK_NOPAPER
|
||||||
from .exceptions import SetVariableError, TabPosError
|
|
||||||
from .image import EscposImage
|
from .exceptions import BarcodeTypeError, BarcodeSizeError, TabPosError
|
||||||
|
from .exceptions import CashDrawerError, SetVariableError, BarcodeCodeError
|
||||||
|
from .exceptions import ImageWidthError
|
||||||
|
|
||||||
from .magicencode import MagicEncode
|
from .magicencode import MagicEncode
|
||||||
|
|
||||||
|
from abc import ABCMeta, abstractmethod # abstract base class support
|
||||||
|
from escpos.image import EscposImage
|
||||||
|
from escpos.capabilities import get_profile, BARCODE_B
|
||||||
|
|
||||||
|
|
||||||
@six.add_metaclass(ABCMeta)
|
@six.add_metaclass(ABCMeta)
|
||||||
class Escpos(object):
|
class Escpos(object):
|
||||||
@@ -88,7 +89,7 @@ class Escpos(object):
|
|||||||
"""
|
"""
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
def image(self, img_source, high_density_vertical=True, high_density_horizontal=True, impl='bitImageRaster',
|
def image(self, img_source, high_density_vertical=True, high_density_horizontal=True, impl="bitImageRaster",
|
||||||
fragment_height=960, center=False):
|
fragment_height=960, center=False):
|
||||||
""" Print an image
|
""" Print an image
|
||||||
|
|
||||||
@@ -140,14 +141,14 @@ class Escpos(object):
|
|||||||
fragment_height=fragment_height)
|
fragment_height=fragment_height)
|
||||||
return
|
return
|
||||||
|
|
||||||
if impl == 'bitImageRaster':
|
if impl == "bitImageRaster":
|
||||||
# GS v 0, raster format bit image
|
# GS v 0, raster format bit image
|
||||||
density_byte = (0 if high_density_horizontal else 1) + (0 if high_density_vertical else 2)
|
density_byte = (0 if high_density_horizontal else 1) + (0 if high_density_vertical else 2)
|
||||||
header = GS + b'v0' + six.int2byte(density_byte) + self._int_low_high(im.width_bytes, 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._int_low_high(im.height, 2)
|
||||||
self._raw(header + im.to_raster_format())
|
self._raw(header + im.to_raster_format())
|
||||||
|
|
||||||
if impl == 'graphics':
|
if impl == "graphics":
|
||||||
# GS ( L raster format graphics
|
# GS ( L raster format graphics
|
||||||
img_header = self._int_low_high(im.width, 2) + self._int_low_high(im.height, 2)
|
img_header = self._int_low_high(im.width, 2) + self._int_low_high(im.height, 2)
|
||||||
tone = b'0'
|
tone = b'0'
|
||||||
@@ -159,14 +160,14 @@ class Escpos(object):
|
|||||||
self._image_send_graphics_data(b'0', b'p', header + raster_data)
|
self._image_send_graphics_data(b'0', b'p', header + raster_data)
|
||||||
self._image_send_graphics_data(b'0', b'2', b'')
|
self._image_send_graphics_data(b'0', b'2', b'')
|
||||||
|
|
||||||
if impl == 'bitImageColumn':
|
if impl == "bitImageColumn":
|
||||||
# ESC *, column format bit image
|
# ESC *, column format bit image
|
||||||
density_byte = (1 if high_density_horizontal else 0) + (32 if high_density_vertical else 0)
|
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)
|
header = ESC + b"*" + six.int2byte(density_byte) + self._int_low_high(im.width, 2)
|
||||||
outp = [ESC + b'3' + six.int2byte(16)] # Adjust line-feed size
|
outp = [ESC + b"3" + six.int2byte(16)] # Adjust line-feed size
|
||||||
for blob in im.to_column_format(high_density_vertical):
|
for blob in im.to_column_format(high_density_vertical):
|
||||||
outp.append(header + blob + b'\n')
|
outp.append(header + blob + b"\n")
|
||||||
outp.append(ESC + b'2') # Reset line-feed size
|
outp.append(ESC + b"2") # Reset line-feed size
|
||||||
self._raw(b''.join(outp))
|
self._raw(b''.join(outp))
|
||||||
|
|
||||||
def _image_send_graphics_data(self, m, fn, data):
|
def _image_send_graphics_data(self, m, fn, data):
|
||||||
@@ -181,7 +182,7 @@ class Escpos(object):
|
|||||||
self._raw(GS + b'(L' + header + m + fn + data)
|
self._raw(GS + b'(L' + header + m + fn + data)
|
||||||
|
|
||||||
def qr(self, content, ec=QR_ECLEVEL_L, size=3, model=QR_MODEL_2,
|
def qr(self, content, ec=QR_ECLEVEL_L, size=3, model=QR_MODEL_2,
|
||||||
native=False, center=False, impl='bitImageRaster'):
|
native=False, center=False, impl="bitImageRaster"):
|
||||||
""" Print QR Code for the provided string
|
""" Print QR Code for the provided string
|
||||||
|
|
||||||
:param content: The content of the code. Numeric data will be more efficiently compacted.
|
:param content: The content of the code. Numeric data will be more efficiently compacted.
|
||||||
@@ -194,21 +195,22 @@ class Escpos(object):
|
|||||||
:param native: True to render the code on the printer, False to render the code as an image and send it to the
|
:param native: True to render the code on the printer, False to render the code as an image and send it to the
|
||||||
printer (Default)
|
printer (Default)
|
||||||
:param center: Centers the code *default:* False
|
:param center: Centers the code *default:* False
|
||||||
|
:param impl: Image-printing-implementation, refer to :meth:`.image()` for details
|
||||||
"""
|
"""
|
||||||
# Basic validation
|
# Basic validation
|
||||||
if ec not in [QR_ECLEVEL_L, QR_ECLEVEL_M, QR_ECLEVEL_H, QR_ECLEVEL_Q]:
|
if ec not in [QR_ECLEVEL_L, QR_ECLEVEL_M, QR_ECLEVEL_H, QR_ECLEVEL_Q]:
|
||||||
raise ValueError('Invalid error correction level')
|
raise ValueError("Invalid error correction level")
|
||||||
if not 1 <= size <= 16:
|
if not 1 <= size <= 16:
|
||||||
raise ValueError('Invalid block size (must be 1-16)')
|
raise ValueError("Invalid block size (must be 1-16)")
|
||||||
if model not in [QR_MODEL_1, QR_MODEL_2, QR_MICRO]:
|
if model not in [QR_MODEL_1, QR_MODEL_2, QR_MICRO]:
|
||||||
raise ValueError('Invalid QR model (must be one of QR_MODEL_1, QR_MODEL_2, QR_MICRO)')
|
raise ValueError("Invalid QR model (must be one of QR_MODEL_1, QR_MODEL_2, QR_MICRO)")
|
||||||
if content == '':
|
if content == "":
|
||||||
# Handle edge case by printing nothing.
|
# Handle edge case by printing nothing.
|
||||||
return
|
return
|
||||||
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 model 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,
|
||||||
@@ -219,7 +221,7 @@ class Escpos(object):
|
|||||||
qr_code.add_data(content)
|
qr_code.add_data(content)
|
||||||
qr_code.make(fit=True)
|
qr_code.make(fit=True)
|
||||||
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.text('\n')
|
self.text('\n')
|
||||||
@@ -229,7 +231,7 @@ class Escpos(object):
|
|||||||
return
|
return
|
||||||
|
|
||||||
if center:
|
if center:
|
||||||
raise NotImplementedError('Centering not implemented for native QR rendering')
|
raise NotImplementedError("Centering not implemented for native QR rendering")
|
||||||
|
|
||||||
# Native 2D code printing
|
# Native 2D code printing
|
||||||
cn = b'1' # Code type for QR code
|
cn = b'1' # Code type for QR code
|
||||||
@@ -252,7 +254,7 @@ class Escpos(object):
|
|||||||
:param m: Modifier/variant for function. Often '0' where used.
|
:param m: Modifier/variant for function. Often '0' where used.
|
||||||
"""
|
"""
|
||||||
if len(m) > 1 or len(cn) != 1 or len(fn) != 1:
|
if len(m) > 1 or len(cn) != 1 or len(fn) != 1:
|
||||||
raise ValueError('cn and fn must be one byte each.')
|
raise ValueError("cn and fn must be one byte each.")
|
||||||
header = self._int_low_high(len(data) + len(m) + 2, 2)
|
header = self._int_low_high(len(data) + len(m) + 2, 2)
|
||||||
self._raw(GS + b'(k' + header + cn + fn + m + data)
|
self._raw(GS + b'(k' + header + cn + fn + m + data)
|
||||||
|
|
||||||
@@ -265,16 +267,16 @@ class Escpos(object):
|
|||||||
"""
|
"""
|
||||||
max_input = (256 << (out_bytes * 8) - 1)
|
max_input = (256 << (out_bytes * 8) - 1)
|
||||||
if not 1 <= out_bytes <= 4:
|
if not 1 <= out_bytes <= 4:
|
||||||
raise ValueError('Can only output 1-4 bytes')
|
raise ValueError("Can only output 1-4 bytes")
|
||||||
if not 0 <= inp_number <= max_input:
|
if not 0 <= inp_number <= max_input:
|
||||||
raise ValueError('Number too large. Can only output up to {0} in {1} bytes'.format(max_input, out_bytes))
|
raise ValueError("Number too large. Can only output up to {0} in {1} bytes".format(max_input, out_bytes))
|
||||||
outp = b''
|
outp = b''
|
||||||
for _ in range(0, out_bytes):
|
for _ in range(0, out_bytes):
|
||||||
outp += six.int2byte(inp_number % 256)
|
outp += six.int2byte(inp_number % 256)
|
||||||
inp_number //= 256
|
inp_number //= 256
|
||||||
return outp
|
return outp
|
||||||
|
|
||||||
def charcode(self, code='AUTO'):
|
def charcode(self, code="AUTO"):
|
||||||
""" Set Character Code Table
|
""" Set Character Code Table
|
||||||
|
|
||||||
Sets the control sequence from ``CHARCODE`` in :py:mod:`escpos.constants` as active. It will be sent with
|
Sets the control sequence from ``CHARCODE`` in :py:mod:`escpos.constants` as active. It will be sent with
|
||||||
@@ -284,7 +286,7 @@ class Escpos(object):
|
|||||||
:param code: Name of CharCode
|
:param code: Name of CharCode
|
||||||
:raises: :py:exc:`~escpos.exceptions.CharCodeError`
|
:raises: :py:exc:`~escpos.exceptions.CharCodeError`
|
||||||
"""
|
"""
|
||||||
if code.upper() == 'AUTO':
|
if code.upper() == "AUTO":
|
||||||
self.magic.force_encoding(False)
|
self.magic.force_encoding(False)
|
||||||
else:
|
else:
|
||||||
self.magic.force_encoding(code)
|
self.magic.force_encoding(code)
|
||||||
@@ -305,8 +307,8 @@ class Escpos(object):
|
|||||||
.. todo:: For fixed-length standards with mandatory checksum (EAN, UPC),
|
.. todo:: For fixed-length standards with mandatory checksum (EAN, UPC),
|
||||||
compute and add the checksum automatically if missing.
|
compute and add the checksum automatically if missing.
|
||||||
|
|
||||||
:param bc: barcode format, see :py:func`~escpos.Escpos.barcode`
|
:param bc: barcode format, see :py:meth:`.barcode()`
|
||||||
:param code: alphanumeric data to be printed as bar code, see :py:func`~escpos.Escpos.barcode`
|
:param code: alphanumeric data to be printed as bar code, see :py:meth:`.barcode()`
|
||||||
:return: bool
|
:return: bool
|
||||||
"""
|
"""
|
||||||
if bc not in BARCODE_FORMATS:
|
if bc not in BARCODE_FORMATS:
|
||||||
@@ -315,7 +317,7 @@ class Escpos(object):
|
|||||||
bounds, regex = BARCODE_FORMATS[bc]
|
bounds, regex = BARCODE_FORMATS[bc]
|
||||||
return any(bound[0] <= len(code) <= bound[1] for bound in bounds) and re_match(regex, code)
|
return any(bound[0] <= len(code) <= bound[1] for bound in bounds) and re_match(regex, code)
|
||||||
|
|
||||||
def barcode(self, code, bc, height=64, width=3, pos='BELOW', font='A',
|
def barcode(self, code, bc, height=64, width=3, pos="BELOW", font="A",
|
||||||
align_ct=True, function_type=None, check=True):
|
align_ct=True, function_type=None, check=True):
|
||||||
""" Print Barcode
|
""" Print Barcode
|
||||||
|
|
||||||
@@ -393,7 +395,7 @@ class Escpos(object):
|
|||||||
*default*: A
|
*default*: A
|
||||||
|
|
||||||
:param check: If this parameter is True, the barcode format will be checked to ensure it meets the bc
|
:param check: If this parameter is True, the barcode format will be checked to ensure it meets the bc
|
||||||
requirements as defigned in the esc/pos documentation. See py:func:`~escpos.Escpos.check_barcode`
|
requirements as defigned in the esc/pos documentation. See :py:meth:`.check_barcode()`
|
||||||
for more information. *default*: True.
|
for more information. *default*: True.
|
||||||
|
|
||||||
:raises: :py:exc:`~escpos.exceptions.BarcodeSizeError`,
|
:raises: :py:exc:`~escpos.exceptions.BarcodeSizeError`,
|
||||||
@@ -408,21 +410,21 @@ class Escpos(object):
|
|||||||
if bc in BARCODE_TYPES['B']:
|
if bc in BARCODE_TYPES['B']:
|
||||||
if not self.profile.supports(BARCODE_B):
|
if not self.profile.supports(BARCODE_B):
|
||||||
raise BarcodeTypeError((
|
raise BarcodeTypeError((
|
||||||
"Barcode type '{bc}' not supported for "
|
"Barcode type '{bc} not supported for "
|
||||||
'the current printer profile').format(bc=bc))
|
"the current printer profile").format(bc=bc))
|
||||||
function_type = 'B'
|
function_type = 'B'
|
||||||
else:
|
else:
|
||||||
raise BarcodeTypeError((
|
raise BarcodeTypeError((
|
||||||
"Barcode type '{bc}' is not valid").format(bc=bc))
|
"Barcode type '{bc} is not valid").format(bc=bc))
|
||||||
|
|
||||||
bc_types = BARCODE_TYPES[function_type.upper()]
|
bc_types = BARCODE_TYPES[function_type.upper()]
|
||||||
if bc.upper() not in bc_types.keys():
|
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 "
|
||||||
'{function_type}').format(
|
"{function_type}").format(
|
||||||
bc=bc,
|
bc=bc,
|
||||||
function_type=function_type,)
|
function_type=function_type,
|
||||||
)
|
))
|
||||||
|
|
||||||
if check and not self.check_barcode(bc, code):
|
if check and not self.check_barcode(bc, code):
|
||||||
raise BarcodeCodeError((
|
raise BarcodeCodeError((
|
||||||
@@ -438,30 +440,30 @@ class Escpos(object):
|
|||||||
if 1 <= height <= 255:
|
if 1 <= height <= 255:
|
||||||
self._raw(BARCODE_HEIGHT + six.int2byte(height))
|
self._raw(BARCODE_HEIGHT + six.int2byte(height))
|
||||||
else:
|
else:
|
||||||
raise BarcodeSizeError('height = {height}'.format(height=height))
|
raise BarcodeSizeError("height = {height}".format(height=height))
|
||||||
# Width
|
# Width
|
||||||
if 2 <= width <= 6:
|
if 2 <= width <= 6:
|
||||||
self._raw(BARCODE_WIDTH + six.int2byte(width))
|
self._raw(BARCODE_WIDTH + six.int2byte(width))
|
||||||
else:
|
else:
|
||||||
raise BarcodeSizeError('width = {width}'.format(width=width))
|
raise BarcodeSizeError("width = {width}".format(width=width))
|
||||||
# Font
|
# Font
|
||||||
if font.upper() == 'B':
|
if font.upper() == "B":
|
||||||
self._raw(BARCODE_FONT_B)
|
self._raw(BARCODE_FONT_B)
|
||||||
else: # DEFAULT FONT: A
|
else: # DEFAULT FONT: A
|
||||||
self._raw(BARCODE_FONT_A)
|
self._raw(BARCODE_FONT_A)
|
||||||
# Position
|
# Position
|
||||||
if pos.upper() == 'OFF':
|
if pos.upper() == "OFF":
|
||||||
self._raw(BARCODE_TXT_OFF)
|
self._raw(BARCODE_TXT_OFF)
|
||||||
elif pos.upper() == 'BOTH':
|
elif pos.upper() == "BOTH":
|
||||||
self._raw(BARCODE_TXT_BTH)
|
self._raw(BARCODE_TXT_BTH)
|
||||||
elif pos.upper() == 'ABOVE':
|
elif pos.upper() == "ABOVE":
|
||||||
self._raw(BARCODE_TXT_ABV)
|
self._raw(BARCODE_TXT_ABV)
|
||||||
else: # DEFAULT POSITION: BELOW
|
else: # DEFAULT POSITION: BELOW
|
||||||
self._raw(BARCODE_TXT_BLW)
|
self._raw(BARCODE_TXT_BLW)
|
||||||
|
|
||||||
self._raw(bc_types[bc.upper()])
|
self._raw(bc_types[bc.upper()])
|
||||||
|
|
||||||
if function_type.upper() == 'B':
|
if function_type.upper() == "B":
|
||||||
self._raw(six.int2byte(len(code)))
|
self._raw(six.int2byte(len(code)))
|
||||||
|
|
||||||
# Print Code
|
# Print Code
|
||||||
@@ -470,7 +472,7 @@ class Escpos(object):
|
|||||||
else:
|
else:
|
||||||
raise BarcodeCodeError()
|
raise BarcodeCodeError()
|
||||||
|
|
||||||
if function_type.upper() == 'A':
|
if function_type.upper() == "A":
|
||||||
self._raw(NUL)
|
self._raw(NUL)
|
||||||
|
|
||||||
def soft_barcode(self, barcode_type, data, impl='bitImageColumn',
|
def soft_barcode(self, barcode_type, data, impl='bitImageColumn',
|
||||||
@@ -488,7 +490,7 @@ class Escpos(object):
|
|||||||
barcode_class = barcode.get_barcode_class(barcode_type)
|
barcode_class = barcode.get_barcode_class(barcode_type)
|
||||||
my_code = barcode_class(data, writer=image_writer)
|
my_code = barcode_class(data, writer=image_writer)
|
||||||
|
|
||||||
with open(os.devnull, 'wb') as nullfile:
|
with open(os.devnull, "wb") as nullfile:
|
||||||
my_code.write(nullfile, {
|
my_code.write(nullfile, {
|
||||||
'module_height': module_height,
|
'module_height': module_height,
|
||||||
'module_width': module_width,
|
'module_width': module_width,
|
||||||
@@ -590,7 +592,8 @@ class Escpos(object):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
if custom_size:
|
if custom_size:
|
||||||
if 1 <= width <= 8 and 1 <= height <= 8 and isinstance(width, int) and isinstance(height, int):
|
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]
|
size_byte = TXT_STYLE['width'][width] + TXT_STYLE['height'][height]
|
||||||
self._raw(TXT_SIZE + six.int2byte(size_byte))
|
self._raw(TXT_SIZE + six.int2byte(size_byte))
|
||||||
else:
|
else:
|
||||||
@@ -638,11 +641,12 @@ class Escpos(object):
|
|||||||
return
|
return
|
||||||
|
|
||||||
if divisor not in LINESPACING_FUNCS:
|
if divisor not in LINESPACING_FUNCS:
|
||||||
raise ValueError('divisor must be either 360, 180 or 60')
|
raise ValueError("divisor must be either 360, 180 or 60")
|
||||||
if (divisor in [360, 180] and (not(0 <= spacing <= 255))):
|
if (divisor in [360, 180]
|
||||||
raise ValueError('spacing must be a int between 0 and 255 when divisor is 360 or 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)):
|
if divisor == 60 and (not(0 <= spacing <= 85)):
|
||||||
raise ValueError('spacing must be a int between 0 and 85 when divisor is 60')
|
raise ValueError("spacing must be a int between 0 and 85 when divisor is 60")
|
||||||
|
|
||||||
self._raw(LINESPACING_FUNCS[divisor] + six.int2byte(spacing))
|
self._raw(LINESPACING_FUNCS[divisor] + six.int2byte(spacing))
|
||||||
|
|
||||||
@@ -670,12 +674,12 @@ class Escpos(object):
|
|||||||
if mode not in ('FULL', 'PART'):
|
if mode not in ('FULL', 'PART'):
|
||||||
raise ValueError("Mode must be one of ('FULL', 'PART')")
|
raise ValueError("Mode must be one of ('FULL', 'PART')")
|
||||||
|
|
||||||
if mode == 'PART':
|
if mode == "PART":
|
||||||
if self.profile.supports('paperPartCut'):
|
if self.profile.supports('paperPartCut'):
|
||||||
self._raw(PAPER_PART_CUT)
|
self._raw(PAPER_PART_CUT)
|
||||||
elif self.profile.supports('paperFullCut'):
|
elif self.profile.supports('paperFullCut'):
|
||||||
self._raw(PAPER_FULL_CUT)
|
self._raw(PAPER_FULL_CUT)
|
||||||
elif mode == 'FULL':
|
elif mode == "FULL":
|
||||||
if self.profile.supports('paperFullCut'):
|
if self.profile.supports('paperFullCut'):
|
||||||
self._raw(PAPER_FULL_CUT)
|
self._raw(PAPER_FULL_CUT)
|
||||||
elif self.profile.supports('paperPartCut'):
|
elif self.profile.supports('paperPartCut'):
|
||||||
@@ -745,11 +749,11 @@ class Escpos(object):
|
|||||||
* SELECT
|
* SELECT
|
||||||
* RESET
|
* RESET
|
||||||
"""
|
"""
|
||||||
if hw.upper() == 'INIT':
|
if hw.upper() == "INIT":
|
||||||
self._raw(HW_INIT)
|
self._raw(HW_INIT)
|
||||||
elif hw.upper() == 'SELECT':
|
elif hw.upper() == "SELECT":
|
||||||
self._raw(HW_SELECT)
|
self._raw(HW_SELECT)
|
||||||
elif hw.upper() == 'RESET':
|
elif hw.upper() == "RESET":
|
||||||
self._raw(HW_RESET)
|
self._raw(HW_RESET)
|
||||||
else: # DEFAULT: DOES NOTHING
|
else: # DEFAULT: DOES NOTHING
|
||||||
pass
|
pass
|
||||||
@@ -764,9 +768,9 @@ class Escpos(object):
|
|||||||
"""
|
"""
|
||||||
if 0 <= n <= 255:
|
if 0 <= n <= 255:
|
||||||
# ESC d n
|
# ESC d n
|
||||||
self._raw(ESC + b'd' + six.int2byte(n))
|
self._raw(ESC + b"d" + six.int2byte(n))
|
||||||
else:
|
else:
|
||||||
raise ValueError('n must be betwen 0 and 255')
|
raise ValueError("n must be betwen 0 and 255")
|
||||||
|
|
||||||
def control(self, ctl, count=5, tab_size=8):
|
def control(self, ctl, count=5, tab_size=8):
|
||||||
""" Feed control sequences
|
""" Feed control sequences
|
||||||
@@ -784,13 +788,13 @@ class Escpos(object):
|
|||||||
:raises: :py:exc:`~escpos.exceptions.TabPosError`
|
:raises: :py:exc:`~escpos.exceptions.TabPosError`
|
||||||
"""
|
"""
|
||||||
# Set position
|
# Set position
|
||||||
if ctl.upper() == 'LF':
|
if ctl.upper() == "LF":
|
||||||
self._raw(CTL_LF)
|
self._raw(CTL_LF)
|
||||||
elif ctl.upper() == 'FF':
|
elif ctl.upper() == "FF":
|
||||||
self._raw(CTL_FF)
|
self._raw(CTL_FF)
|
||||||
elif ctl.upper() == 'CR':
|
elif ctl.upper() == "CR":
|
||||||
self._raw(CTL_CR)
|
self._raw(CTL_CR)
|
||||||
elif ctl.upper() == 'HT':
|
elif ctl.upper() == "HT":
|
||||||
if not (0 <= count <= 32 and
|
if not (0 <= count <= 32 and
|
||||||
1 <= tab_size <= 255 and
|
1 <= tab_size <= 255 and
|
||||||
count * tab_size < 256):
|
count * tab_size < 256):
|
||||||
@@ -801,7 +805,7 @@ class Escpos(object):
|
|||||||
for iterator in range(1, count):
|
for iterator in range(1, count):
|
||||||
self._raw(six.int2byte(iterator * tab_size))
|
self._raw(six.int2byte(iterator * tab_size))
|
||||||
self._raw(NUL)
|
self._raw(NUL)
|
||||||
elif ctl.upper() == 'VT':
|
elif ctl.upper() == "VT":
|
||||||
self._raw(CTL_VT)
|
self._raw(CTL_VT)
|
||||||
|
|
||||||
def panel_buttons(self, enable=True):
|
def panel_buttons(self, enable=True):
|
||||||
@@ -927,16 +931,16 @@ class EscposIO(object):
|
|||||||
elif isinstance(text, list) or isinstance(text, tuple):
|
elif isinstance(text, list) or isinstance(text, tuple):
|
||||||
lines = text
|
lines = text
|
||||||
else:
|
else:
|
||||||
lines = ['{0}'.format(text), ]
|
lines = ["{0}".format(text), ]
|
||||||
|
|
||||||
# TODO check unicode handling
|
# TODO check unicode handling
|
||||||
# TODO flush? or on print? (this should prob rather be handled by the _raw-method)
|
# TODO flush? or on print? (this should prob rather be handled by the _raw-method)
|
||||||
for line in lines:
|
for line in lines:
|
||||||
self.printer.set(**params)
|
self.printer.set(**params)
|
||||||
if isinstance(text, six.text_type):
|
if isinstance(text, six.text_type):
|
||||||
self.printer.text(u'{0}\n'.format(line))
|
self.printer.text(u"{0}\n".format(line))
|
||||||
else:
|
else:
|
||||||
self.printer.text('{0}\n'.format(line))
|
self.printer.text("{0}\n".format(line))
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
""" called upon closing the `with`-statement
|
""" called upon closing the `with`-statement
|
||||||
|
@@ -51,13 +51,13 @@ class BarcodeTypeError(Error):
|
|||||||
one of those specified in :py:meth:`escpos.escpos.Escpos.barcode`.
|
one of those specified in :py:meth:`escpos.escpos.Escpos.barcode`.
|
||||||
The returned error code is `10`.
|
The returned error code is `10`.
|
||||||
"""
|
"""
|
||||||
def __init__(self, msg=''):
|
def __init__(self, msg=""):
|
||||||
Error.__init__(self, msg)
|
Error.__init__(self, msg)
|
||||||
self.msg = msg
|
self.msg = msg
|
||||||
self.resultcode = 10
|
self.resultcode = 10
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return 'No Barcode type is defined ({msg})'.format(msg=self.msg)
|
return "No Barcode type is defined ({msg})".format(msg=self.msg)
|
||||||
|
|
||||||
|
|
||||||
class BarcodeSizeError(Error):
|
class BarcodeSizeError(Error):
|
||||||
@@ -67,13 +67,13 @@ class BarcodeSizeError(Error):
|
|||||||
The size of the barcode has to be in the range that is specified in :py:meth:`escpos.escpos.Escpos.barcode`.
|
The size of the barcode has to be in the range that is specified in :py:meth:`escpos.escpos.Escpos.barcode`.
|
||||||
The resulting returncode is `20`.
|
The resulting returncode is `20`.
|
||||||
"""
|
"""
|
||||||
def __init__(self, msg=''):
|
def __init__(self, msg=""):
|
||||||
Error.__init__(self, msg)
|
Error.__init__(self, msg)
|
||||||
self.msg = msg
|
self.msg = msg
|
||||||
self.resultcode = 20
|
self.resultcode = 20
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return 'Barcode size is out of range ({msg})'.format(msg=self.msg)
|
return "Barcode size is out of range ({msg})".format(msg=self.msg)
|
||||||
|
|
||||||
|
|
||||||
class BarcodeCodeError(Error):
|
class BarcodeCodeError(Error):
|
||||||
@@ -83,13 +83,13 @@ class BarcodeCodeError(Error):
|
|||||||
was True and the check failed.
|
was True and the check failed.
|
||||||
The returncode for this exception is `30`.
|
The returncode for this exception is `30`.
|
||||||
"""
|
"""
|
||||||
def __init__(self, msg=''):
|
def __init__(self, msg=""):
|
||||||
Error.__init__(self, msg)
|
Error.__init__(self, msg)
|
||||||
self.msg = msg
|
self.msg = msg
|
||||||
self.resultcode = 30
|
self.resultcode = 30
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return 'No Barcode code was supplied ({msg})'.format(msg=self.msg)
|
return "No Barcode code was supplied ({msg})".format(msg=self.msg)
|
||||||
|
|
||||||
|
|
||||||
class ImageSizeError(Error):
|
class ImageSizeError(Error):
|
||||||
@@ -97,7 +97,7 @@ class ImageSizeError(Error):
|
|||||||
|
|
||||||
The returncode for this exception is `40`.
|
The returncode for this exception is `40`.
|
||||||
"""
|
"""
|
||||||
def __init__(self, msg=''):
|
def __init__(self, msg=""):
|
||||||
Error.__init__(self, msg)
|
Error.__init__(self, msg)
|
||||||
self.msg = msg
|
self.msg = msg
|
||||||
self.resultcode = 40
|
self.resultcode = 40
|
||||||
@@ -111,13 +111,13 @@ class ImageWidthError(Error):
|
|||||||
|
|
||||||
The return code for this exception is `41`.
|
The return code for this exception is `41`.
|
||||||
"""
|
"""
|
||||||
def __init__(self, msg=''):
|
def __init__(self, msg=""):
|
||||||
Error.__init__(self, msg)
|
Error.__init__(self, msg)
|
||||||
self.msg = msg
|
self.msg = msg
|
||||||
self.resultcode = 41
|
self.resultcode = 41
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return 'Image width is too large ({msg})'.format(msg=self.msg)
|
return "Image width is too large ({msg})".format(msg=self.msg)
|
||||||
|
|
||||||
|
|
||||||
class TextError(Error):
|
class TextError(Error):
|
||||||
@@ -126,13 +126,13 @@ class TextError(Error):
|
|||||||
This exception is raised when an empty string is passed to :py:meth:`escpos.escpos.Escpos.text`.
|
This exception is raised when an empty string is passed to :py:meth:`escpos.escpos.Escpos.text`.
|
||||||
The returncode for this exception is `50`.
|
The returncode for this exception is `50`.
|
||||||
"""
|
"""
|
||||||
def __init__(self, msg=''):
|
def __init__(self, msg=""):
|
||||||
Error.__init__(self, msg)
|
Error.__init__(self, msg)
|
||||||
self.msg = msg
|
self.msg = msg
|
||||||
self.resultcode = 50
|
self.resultcode = 50
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return 'Text string must be supplied to the text() method ({msg})'.format(msg=self.msg)
|
return "Text string must be supplied to the text() method ({msg})".format(msg=self.msg)
|
||||||
|
|
||||||
|
|
||||||
class CashDrawerError(Error):
|
class CashDrawerError(Error):
|
||||||
@@ -141,13 +141,13 @@ class CashDrawerError(Error):
|
|||||||
A valid pin number has to be passed onto the method :py:meth:`escpos.escpos.Escpos.cashdraw`.
|
A valid pin number has to be passed onto the method :py:meth:`escpos.escpos.Escpos.cashdraw`.
|
||||||
The returncode for this exception is `60`.
|
The returncode for this exception is `60`.
|
||||||
"""
|
"""
|
||||||
def __init__(self, msg=''):
|
def __init__(self, msg=""):
|
||||||
Error.__init__(self, msg)
|
Error.__init__(self, msg)
|
||||||
self.msg = msg
|
self.msg = msg
|
||||||
self.resultcode = 60
|
self.resultcode = 60
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return 'Valid pin must be set to send pulse ({msg})'.format(msg=self.msg)
|
return "Valid pin must be set to send pulse ({msg})".format(msg=self.msg)
|
||||||
|
|
||||||
|
|
||||||
class TabPosError(Error):
|
class TabPosError(Error):
|
||||||
@@ -157,13 +157,13 @@ class TabPosError(Error):
|
|||||||
This exception is raised by :py:meth:`escpos.escpos.Escpos.control`.
|
This exception is raised by :py:meth:`escpos.escpos.Escpos.control`.
|
||||||
The returncode for this exception is `70`.
|
The returncode for this exception is `70`.
|
||||||
"""
|
"""
|
||||||
def __init__(self, msg=''):
|
def __init__(self, msg=""):
|
||||||
Error.__init__(self, msg)
|
Error.__init__(self, msg)
|
||||||
self.msg = msg
|
self.msg = msg
|
||||||
self.resultcode = 70
|
self.resultcode = 70
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return 'Valid tab positions must be in the range 0 to 16 ({msg})'.format(msg=self.msg)
|
return "Valid tab positions must be in the range 0 to 16 ({msg})".format(msg=self.msg)
|
||||||
|
|
||||||
|
|
||||||
class CharCodeError(Error):
|
class CharCodeError(Error):
|
||||||
@@ -172,13 +172,13 @@ class CharCodeError(Error):
|
|||||||
The supplied charcode-name in :py:meth:`escpos.escpos.Escpos.charcode` is unknown.
|
The supplied charcode-name in :py:meth:`escpos.escpos.Escpos.charcode` is unknown.
|
||||||
Ths returncode for this exception is `80`.
|
Ths returncode for this exception is `80`.
|
||||||
"""
|
"""
|
||||||
def __init__(self, msg=''):
|
def __init__(self, msg=""):
|
||||||
Error.__init__(self, msg)
|
Error.__init__(self, msg)
|
||||||
self.msg = msg
|
self.msg = msg
|
||||||
self.resultcode = 80
|
self.resultcode = 80
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return 'Valid char code must be set ({msg})'.format(msg=self.msg)
|
return "Valid char code must be set ({msg})".format(msg=self.msg)
|
||||||
|
|
||||||
|
|
||||||
class USBNotFoundError(Error):
|
class USBNotFoundError(Error):
|
||||||
@@ -187,13 +187,13 @@ class USBNotFoundError(Error):
|
|||||||
The USB device seems to be not plugged in.
|
The USB device seems to be not plugged in.
|
||||||
Ths returncode for this exception is `90`.
|
Ths returncode for this exception is `90`.
|
||||||
"""
|
"""
|
||||||
def __init__(self, msg=''):
|
def __init__(self, msg=""):
|
||||||
Error.__init__(self, msg)
|
Error.__init__(self, msg)
|
||||||
self.msg = msg
|
self.msg = msg
|
||||||
self.resultcode = 90
|
self.resultcode = 90
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return 'USB device not found ({msg})'.format(msg=self.msg)
|
return "USB device not found ({msg})".format(msg=self.msg)
|
||||||
|
|
||||||
|
|
||||||
class SetVariableError(Error):
|
class SetVariableError(Error):
|
||||||
@@ -202,13 +202,13 @@ class SetVariableError(Error):
|
|||||||
Check set variables against minimum and maximum values
|
Check set variables against minimum and maximum values
|
||||||
Ths returncode for this exception is `100`.
|
Ths returncode for this exception is `100`.
|
||||||
"""
|
"""
|
||||||
def __init__(self, msg=''):
|
def __init__(self, msg=""):
|
||||||
Error.__init__(self, msg)
|
Error.__init__(self, msg)
|
||||||
self.msg = msg
|
self.msg = msg
|
||||||
self.resultcode = 100
|
self.resultcode = 100
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return 'Set variable out of range ({msg})'.format(msg=self.msg)
|
return "Set variable out of range ({msg})".format(msg=self.msg)
|
||||||
|
|
||||||
|
|
||||||
# Configuration errors
|
# Configuration errors
|
||||||
@@ -219,13 +219,13 @@ class ConfigNotFoundError(Error):
|
|||||||
The default or passed configuration file could not be read
|
The default or passed configuration file could not be read
|
||||||
Ths returncode for this exception is `200`.
|
Ths returncode for this exception is `200`.
|
||||||
"""
|
"""
|
||||||
def __init__(self, msg=''):
|
def __init__(self, msg=""):
|
||||||
Error.__init__(self, msg)
|
Error.__init__(self, msg)
|
||||||
self.msg = msg
|
self.msg = msg
|
||||||
self.resultcode = 200
|
self.resultcode = 200
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return 'Configuration not found ({msg})'.format(msg=self.msg)
|
return "Configuration not found ({msg})".format(msg=self.msg)
|
||||||
|
|
||||||
|
|
||||||
class ConfigSyntaxError(Error):
|
class ConfigSyntaxError(Error):
|
||||||
@@ -234,13 +234,13 @@ class ConfigSyntaxError(Error):
|
|||||||
The syntax is incorrect
|
The syntax is incorrect
|
||||||
Ths returncode for this exception is `210`.
|
Ths returncode for this exception is `210`.
|
||||||
"""
|
"""
|
||||||
def __init__(self, msg=''):
|
def __init__(self, msg=""):
|
||||||
Error.__init__(self, msg)
|
Error.__init__(self, msg)
|
||||||
self.msg = msg
|
self.msg = msg
|
||||||
self.resultcode = 210
|
self.resultcode = 210
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return 'Configuration syntax is invalid ({msg})'.format(msg=self.msg)
|
return "Configuration syntax is invalid ({msg})".format(msg=self.msg)
|
||||||
|
|
||||||
|
|
||||||
class ConfigSectionMissingError(Error):
|
class ConfigSectionMissingError(Error):
|
||||||
@@ -249,10 +249,10 @@ class ConfigSectionMissingError(Error):
|
|||||||
The part of the config asked for doesn't exist in the loaded configuration
|
The part of the config asked for doesn't exist in the loaded configuration
|
||||||
Ths returncode for this exception is `220`.
|
Ths returncode for this exception is `220`.
|
||||||
"""
|
"""
|
||||||
def __init__(self, msg=''):
|
def __init__(self, msg=""):
|
||||||
Error.__init__(self, msg)
|
Error.__init__(self, msg)
|
||||||
self.msg = msg
|
self.msg = msg
|
||||||
self.resultcode = 220
|
self.resultcode = 220
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return 'Configuration section is missing ({msg})'.format(msg=self.msg)
|
return "Configuration section is missing ({msg})".format(msg=self.msg)
|
||||||
|
@@ -1,4 +1,3 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
""" Image format handling class
|
""" Image format handling class
|
||||||
|
|
||||||
This module contains the image format handler :py:class:`EscposImage`.
|
This module contains the image format handler :py:class:`EscposImage`.
|
||||||
@@ -15,7 +14,6 @@ from __future__ import print_function
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
import math
|
import math
|
||||||
|
|
||||||
from PIL import Image, ImageOps
|
from PIL import Image, ImageOps
|
||||||
|
|
||||||
|
|
||||||
@@ -44,14 +42,14 @@ class EscposImage(object):
|
|||||||
# Convert to white RGB background, paste over white background
|
# Convert to white RGB background, paste over white background
|
||||||
# to strip alpha.
|
# to strip alpha.
|
||||||
img_original = img_original.convert('RGBA')
|
img_original = img_original.convert('RGBA')
|
||||||
im = Image.new('RGB', img_original.size, (255, 255, 255))
|
im = Image.new("RGB", img_original.size, (255, 255, 255))
|
||||||
im.paste(img_original, mask=img_original.split()[3])
|
im.paste(img_original, mask=img_original.split()[3])
|
||||||
# Convert down to greyscale
|
# Convert down to greyscale
|
||||||
im = im.convert('L')
|
im = im.convert("L")
|
||||||
# Invert: Only works on 'L' images
|
# Invert: Only works on 'L' images
|
||||||
im = ImageOps.invert(im)
|
im = ImageOps.invert(im)
|
||||||
# Pure black and white
|
# Pure black and white
|
||||||
self._im = im.convert('1')
|
self._im = im.convert("1")
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def width(self):
|
def width(self):
|
||||||
@@ -107,7 +105,7 @@ class EscposImage(object):
|
|||||||
:param fragment_height: height of fragment
|
:param fragment_height: height of fragment
|
||||||
:return: list of PIL objects
|
:return: list of PIL objects
|
||||||
"""
|
"""
|
||||||
passes = int(math.ceil(self.height // fragment_height))
|
passes = int(math.ceil(self.height/fragment_height))
|
||||||
fragments = []
|
fragments = []
|
||||||
for n in range(0, passes):
|
for n in range(0, passes):
|
||||||
left = 0
|
left = 0
|
||||||
@@ -127,7 +125,7 @@ class EscposImage(object):
|
|||||||
old_width, height = self._im.size
|
old_width, height = self._im.size
|
||||||
new_size = (max_width, height)
|
new_size = (max_width, height)
|
||||||
|
|
||||||
new_im = Image.new('1', new_size)
|
new_im = Image.new("1", new_size)
|
||||||
paste_x = int((max_width - old_width) / 2)
|
paste_x = int((max_width - old_width) / 2)
|
||||||
|
|
||||||
new_im.paste(self._im, (paste_x, 0))
|
new_im.paste(self._im, (paste_x, 0))
|
||||||
|
@@ -33,7 +33,7 @@ def encode_katakana(text):
|
|||||||
# TODO doesn't this discard all that is not in the map? Can we be sure that the input does contain only
|
# TODO doesn't this discard all that is not in the map? Can we be sure that the input does contain only
|
||||||
# encodable characters? We could at least throw an exception if encoding is not possible.
|
# encodable characters? We could at least throw an exception if encoding is not possible.
|
||||||
pass
|
pass
|
||||||
return b''.join(encoded)
|
return b"".join(encoded)
|
||||||
|
|
||||||
|
|
||||||
TXT_ENC_KATAKANA_MAP = {
|
TXT_ENC_KATAKANA_MAP = {
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env python
|
#!/usr/bin/python
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
""" Magic Encode
|
""" Magic Encode
|
||||||
|
|
||||||
@@ -18,12 +18,10 @@ from __future__ import print_function
|
|||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from builtins import bytes
|
from builtins import bytes
|
||||||
|
|
||||||
import six
|
|
||||||
|
|
||||||
from .codepages import CodePages
|
|
||||||
from .constants import CODEPAGE_CHANGE
|
from .constants import CODEPAGE_CHANGE
|
||||||
from .exceptions import Error
|
from .exceptions import Error
|
||||||
|
from .codepages import CodePages
|
||||||
|
import six
|
||||||
|
|
||||||
|
|
||||||
class Encoder(object):
|
class Encoder(object):
|
||||||
@@ -64,7 +62,7 @@ class Encoder(object):
|
|||||||
raise ValueError((
|
raise ValueError((
|
||||||
'Encoding "{}" cannot be used for the current profile. '
|
'Encoding "{}" cannot be used for the current profile. '
|
||||||
'Valid encodings are: {}'
|
'Valid encodings are: {}'
|
||||||
).format(encoding, ','.join(self.codepages.keys())))
|
).format(encoding, ','.join(self.codepages.keys())))
|
||||||
return encoding
|
return encoding
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@@ -77,11 +75,11 @@ class Encoder(object):
|
|||||||
"""
|
"""
|
||||||
codepage = CodePages.get_encoding(encoding)
|
codepage = CodePages.get_encoding(encoding)
|
||||||
if 'data' in codepage:
|
if 'data' in codepage:
|
||||||
encodable_chars = list(''.join(codepage['data']))
|
encodable_chars = list("".join(codepage['data']))
|
||||||
assert(len(encodable_chars) == 128)
|
assert(len(encodable_chars) == 128)
|
||||||
return encodable_chars
|
return encodable_chars
|
||||||
elif 'python_encode' in codepage:
|
elif 'python_encode' in codepage:
|
||||||
encodable_chars = [u' '] * 128
|
encodable_chars = [u" "] * 128
|
||||||
for i in range(0, 128):
|
for i in range(0, 128):
|
||||||
codepoint = i + 128
|
codepoint = i + 128
|
||||||
try:
|
try:
|
||||||
@@ -282,7 +280,7 @@ class MagicEncode(object):
|
|||||||
|
|
||||||
def write_with_encoding(self, encoding, text):
|
def write_with_encoding(self, encoding, text):
|
||||||
if text is not None and type(text) is not six.text_type:
|
if text is not None and type(text) is not six.text_type:
|
||||||
raise Error('The supplied text has to be unicode, but is of type {type}.'.format(
|
raise Error("The supplied text has to be unicode, but is of type {type}.".format(
|
||||||
type=type(text)
|
type=type(text)
|
||||||
))
|
))
|
||||||
|
|
||||||
|
@@ -13,12 +13,10 @@ from __future__ import division
|
|||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
import socket
|
|
||||||
|
|
||||||
import serial
|
|
||||||
|
|
||||||
import usb.core
|
import usb.core
|
||||||
import usb.util
|
import usb.util
|
||||||
|
import serial
|
||||||
|
import socket
|
||||||
|
|
||||||
from .escpos import Escpos
|
from .escpos import Escpos
|
||||||
from .exceptions import USBNotFoundError
|
from .exceptions import USBNotFoundError
|
||||||
@@ -36,47 +34,64 @@ class Usb(Escpos):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, idVendor, idProduct, timeout=0, in_ep=0x82, out_ep=0x01, *args, **kwargs): # noqa: N803
|
def __init__(self, idVendor, idProduct, usb_args=None, timeout=0, in_ep=0x82, out_ep=0x01,
|
||||||
|
*args, **kwargs): # noqa: N803
|
||||||
"""
|
"""
|
||||||
:param idVendor: Vendor ID
|
:param idVendor: Vendor ID
|
||||||
:param idProduct: Product ID
|
:param idProduct: Product ID
|
||||||
|
:param usb_args: Optional USB arguments (e.g. custom_match)
|
||||||
:param timeout: Is the time limit of the USB operation. Default without timeout.
|
:param timeout: Is the time limit of the USB operation. Default without timeout.
|
||||||
:param in_ep: Input end point
|
:param in_ep: Input end point
|
||||||
:param out_ep: Output end point
|
:param out_ep: Output end point
|
||||||
"""
|
"""
|
||||||
Escpos.__init__(self, *args, **kwargs)
|
Escpos.__init__(self, *args, **kwargs)
|
||||||
self.idVendor = idVendor
|
|
||||||
self.idProduct = idProduct
|
|
||||||
self.timeout = timeout
|
self.timeout = timeout
|
||||||
self.in_ep = in_ep
|
self.in_ep = in_ep
|
||||||
self.out_ep = out_ep
|
self.out_ep = out_ep
|
||||||
self.open()
|
|
||||||
|
|
||||||
def open(self):
|
usb_args = usb_args or {}
|
||||||
""" Search device on USB tree and set it as escpos device """
|
if idVendor:
|
||||||
self.device = usb.core.find(idVendor=self.idVendor, idProduct=self.idProduct)
|
usb_args['idVendor'] = idVendor
|
||||||
|
if idProduct:
|
||||||
|
usb_args['idProduct'] = idProduct
|
||||||
|
self.open(usb_args)
|
||||||
|
|
||||||
|
def open(self, usb_args):
|
||||||
|
""" Search device on USB tree and set it as escpos device.
|
||||||
|
|
||||||
|
:param usb_args: USB arguments
|
||||||
|
"""
|
||||||
|
self.device = usb.core.find(**usb_args)
|
||||||
if self.device is None:
|
if self.device is None:
|
||||||
raise USBNotFoundError('Device not found or cable not plugged in.')
|
raise USBNotFoundError("Device not found or cable not plugged in.")
|
||||||
|
|
||||||
check_driver = None
|
self.idVendor = self.device.idVendor
|
||||||
|
self.idProduct = self.device.idProduct
|
||||||
|
|
||||||
try:
|
# pyusb has three backends: libusb0, libusb1 and openusb but
|
||||||
check_driver = self.device.is_kernel_driver_active(0)
|
# only libusb1 backend implements the methods is_kernel_driver_active()
|
||||||
except NotImplementedError:
|
# and detach_kernel_driver().
|
||||||
pass
|
# This helps enable this library to work on Windows.
|
||||||
|
if self.device.backend.__module__.endswith("libusb1"):
|
||||||
|
check_driver = None
|
||||||
|
|
||||||
if check_driver is None or check_driver:
|
|
||||||
try:
|
try:
|
||||||
self.device.detach_kernel_driver(0)
|
check_driver = self.device.is_kernel_driver_active(0)
|
||||||
except usb.core.USBError as e:
|
except NotImplementedError:
|
||||||
if check_driver is not None:
|
pass
|
||||||
print('Could not detatch kernel driver: {0}'.format(str(e)))
|
|
||||||
|
if check_driver is None or check_driver:
|
||||||
|
try:
|
||||||
|
self.device.detach_kernel_driver(0)
|
||||||
|
except usb.core.USBError as e:
|
||||||
|
if check_driver is not None:
|
||||||
|
print("Could not detatch kernel driver: {0}".format(str(e)))
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.device.set_configuration()
|
self.device.set_configuration()
|
||||||
self.device.reset()
|
self.device.reset()
|
||||||
except usb.core.USBError as e:
|
except usb.core.USBError as e:
|
||||||
print('Could not set configuration: {0}'.format(str(e)))
|
print("Could not set configuration: {0}".format(str(e)))
|
||||||
|
|
||||||
def _raw(self, msg):
|
def _raw(self, msg):
|
||||||
""" Print any command sent in raw format
|
""" Print any command sent in raw format
|
||||||
@@ -109,7 +124,7 @@ class Serial(Escpos):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, devfile='/dev/ttyS0', baudrate=9600, bytesize=8, timeout=1,
|
def __init__(self, devfile="/dev/ttyS0", baudrate=9600, bytesize=8, timeout=1,
|
||||||
parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE,
|
parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE,
|
||||||
xonxoff=False, dsrdtr=True, *args, **kwargs):
|
xonxoff=False, dsrdtr=True, *args, **kwargs):
|
||||||
"""
|
"""
|
||||||
@@ -145,9 +160,9 @@ class Serial(Escpos):
|
|||||||
xonxoff=self.xonxoff, dsrdtr=self.dsrdtr)
|
xonxoff=self.xonxoff, dsrdtr=self.dsrdtr)
|
||||||
|
|
||||||
if self.device is not None:
|
if self.device is not None:
|
||||||
print('Serial printer enabled')
|
print("Serial printer enabled")
|
||||||
else:
|
else:
|
||||||
print('Unable to open serial printer on: {0}'.format(str(self.devfile)))
|
print("Unable to open serial printer on: {0}".format(str(self.devfile)))
|
||||||
|
|
||||||
def _raw(self, msg):
|
def _raw(self, msg):
|
||||||
""" Print any command sent in raw format
|
""" Print any command sent in raw format
|
||||||
@@ -211,7 +226,7 @@ class Network(Escpos):
|
|||||||
self.device.connect((self.host, self.port))
|
self.device.connect((self.host, self.port))
|
||||||
|
|
||||||
if self.device is None:
|
if self.device is None:
|
||||||
print('Could not open socket for {0}'.format(self.host))
|
print("Could not open socket for {0}".format(self.host))
|
||||||
|
|
||||||
def _raw(self, msg):
|
def _raw(self, msg):
|
||||||
""" Print any command sent in raw format
|
""" Print any command sent in raw format
|
||||||
@@ -221,6 +236,11 @@ class Network(Escpos):
|
|||||||
"""
|
"""
|
||||||
self.device.sendall(msg)
|
self.device.sendall(msg)
|
||||||
|
|
||||||
|
def _read(self):
|
||||||
|
""" Read data from the TCP socket """
|
||||||
|
|
||||||
|
return self.device.recv(16)
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
""" Close TCP connection """
|
""" Close TCP connection """
|
||||||
if self.device is not None:
|
if self.device is not None:
|
||||||
@@ -242,7 +262,7 @@ class File(Escpos):
|
|||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, devfile='/dev/usb/lp0', auto_flush=True, *args, **kwargs):
|
def __init__(self, devfile="/dev/usb/lp0", auto_flush=True, *args, **kwargs):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
:param devfile: Device file under dev filesystem
|
:param devfile: Device file under dev filesystem
|
||||||
@@ -255,10 +275,10 @@ class File(Escpos):
|
|||||||
|
|
||||||
def open(self):
|
def open(self):
|
||||||
""" Open system file """
|
""" Open system file """
|
||||||
self.device = open(self.devfile, 'wb')
|
self.device = open(self.devfile, "wb")
|
||||||
|
|
||||||
if self.device is None:
|
if self.device is None:
|
||||||
print('Could not open the specified file {0}'.format(self.devfile))
|
print("Could not open the specified file {0}".format(self.devfile))
|
||||||
|
|
||||||
def flush(self):
|
def flush(self):
|
||||||
""" Flush printing content """
|
""" Flush printing content """
|
||||||
@@ -324,3 +344,48 @@ class Dummy(Escpos):
|
|||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
_WIN32PRINT = False
|
||||||
|
try:
|
||||||
|
import win32print
|
||||||
|
_WIN32PRINT = True
|
||||||
|
except ImportError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
if _WIN32PRINT:
|
||||||
|
class Win32Raw(Escpos):
|
||||||
|
def __init__(self, printer_name=None, *args, **kwargs):
|
||||||
|
Escpos.__init__(self, *args, **kwargs)
|
||||||
|
if printer_name is not None:
|
||||||
|
self.printer_name = printer_name
|
||||||
|
else:
|
||||||
|
self.printer_name = win32print.GetDefaultPrinter()
|
||||||
|
self.hPrinter = None
|
||||||
|
|
||||||
|
def open(self, job_name="python-escpos"):
|
||||||
|
if self.printer_name is None:
|
||||||
|
raise Exception("Printer not found")
|
||||||
|
self.hPrinter = win32print.OpenPrinter(self.printer_name)
|
||||||
|
self.current_job = win32print.StartDocPrinter(self.hPrinter, 1, (job_name, None, "RAW"))
|
||||||
|
win32print.StartPagePrinter(self.hPrinter)
|
||||||
|
|
||||||
|
def close(self):
|
||||||
|
if not self.hPrinter:
|
||||||
|
return
|
||||||
|
win32print.EndPagePrinter(self.hPrinter)
|
||||||
|
win32print.EndDocPrinter(self.hPrinter)
|
||||||
|
win32print.ClosePrinter(self.hPrinter)
|
||||||
|
self.hPrinter = None
|
||||||
|
|
||||||
|
def _raw(self, msg):
|
||||||
|
""" Print any command sent in raw format
|
||||||
|
|
||||||
|
:param msg: arbitrary code to be printed
|
||||||
|
:type msg: bytes
|
||||||
|
"""
|
||||||
|
if self.printer_name is None:
|
||||||
|
raise Exception("Printer not found")
|
||||||
|
if self.hPrinter is None:
|
||||||
|
raise Exception("Printer job not opened")
|
||||||
|
win32print.WritePrinter(self.hPrinter, msg)
|
||||||
|
11
tox.ini
11
tox.ini
@@ -1,5 +1,5 @@
|
|||||||
[tox]
|
[tox]
|
||||||
envlist = py27, py34, py35, docs, flake8
|
envlist = py27, py34, py35, py36, py37, docs, flake8
|
||||||
|
|
||||||
[testenv]
|
[testenv]
|
||||||
deps = nose
|
deps = nose
|
||||||
@@ -10,7 +10,7 @@ deps = nose
|
|||||||
pytest!=3.2.0,!=3.3.0
|
pytest!=3.2.0,!=3.3.0
|
||||||
pytest-cov
|
pytest-cov
|
||||||
pytest-mock
|
pytest-mock
|
||||||
hypothesis!=3.56.9
|
hypothesis!=3.56.9,<4
|
||||||
viivakoodi
|
viivakoodi
|
||||||
commands = py.test --cov escpos
|
commands = py.test --cov escpos
|
||||||
passenv = ESCPOS_CAPABILITIES_PICKLE_DIR ESCPOS_CAPABILITIES_FILE CI TRAVIS TRAVIS_* APPVEYOR APPVEYOR_* CODECOV_*
|
passenv = ESCPOS_CAPABILITIES_PICKLE_DIR ESCPOS_CAPABILITIES_FILE CI TRAVIS TRAVIS_* APPVEYOR APPVEYOR_* CODECOV_*
|
||||||
@@ -25,12 +25,7 @@ commands = sphinx-build -W -b html -d {envtmpdir}/doctrees . {envtmpdir}/html
|
|||||||
|
|
||||||
[testenv:flake8]
|
[testenv:flake8]
|
||||||
basepython = python
|
basepython = python
|
||||||
# TODO add flake8-print after adding logging
|
# TODO add flake8-future
|
||||||
# TODO add flake8-docstrings
|
# TODO add flake8-docstrings
|
||||||
deps = flake8
|
deps = flake8
|
||||||
flake8-coding
|
|
||||||
flake8-copyright
|
|
||||||
flake8-future-import
|
|
||||||
flake8-quotes
|
|
||||||
flake8-import-order
|
|
||||||
commands = flake8
|
commands = flake8
|
||||||
|
Reference in New Issue
Block a user