mirror of
https://github.com/python-escpos/python-escpos
synced 2025-09-13 09:09:58 +00:00
Compare commits
27 Commits
debian/jes
...
appveyor
Author | SHA1 | Date | |
---|---|---|---|
![]() |
7014572ed8 | ||
![]() |
82c67aa646 | ||
![]() |
9e47ff2505 | ||
![]() |
9bc3b30a60 | ||
![]() |
5bd6dcf471 | ||
![]() |
89dfb6cf86 | ||
![]() |
662aa30f4b | ||
![]() |
efec3e508c | ||
![]() |
c3e952befa | ||
![]() |
83b426f5fd | ||
![]() |
b963c5668b | ||
![]() |
4882c31531 | ||
![]() |
7c17141fb2 | ||
![]() |
3f9d44ff15 | ||
![]() |
a069009696 | ||
![]() |
024b0df7d2 | ||
![]() |
74ef9aed7f | ||
![]() |
c4dd4f2960 | ||
![]() |
d348712439 | ||
![]() |
22cf6ad00b | ||
![]() |
5bf2636753 | ||
![]() |
1f427953a8 | ||
![]() |
a6e1d0df00 | ||
![]() |
c0b4d03692 | ||
![]() |
a16d6bde06 | ||
![]() |
737cc3176e | ||
![]() |
4b04a5c425 |
11
.mailmap
Normal file
11
.mailmap
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
<dev@pkanzler.de> <patrick.kanzler@fablab.fau.de>
|
||||||
|
<manpaz@gmail.com> <manpaz@bashlinux.com>
|
||||||
|
Manuel F Martinez <manpaz@gmail.com> manpaz <manpaz@bashlinux.com>
|
||||||
|
<emailofdavis@gmail.com> <davis.goglin@oregonicecream.com>
|
||||||
|
Davis Goglin <emailofdavis@gmail.com> davisgoglin <emailofdavis@gmail.com>
|
||||||
|
Michael Billington <michael.billington@gmail.com> Michael <michael.billington@gmail.com>
|
||||||
|
Cody (Quantified Code Bot) <cody@quantifiedcode.com> Cody <cody@quantifiedcode.com>
|
||||||
|
Renato Lorenzi <renato.lorenzi@senior.com.br> Renato.Lorenzi <renato.lorenzi@senior.com.br>
|
||||||
|
Ahmed Tahri <nyuubi.10@gmail.com> TAHRI Ahmed <nyuubi.10@gmail.com>
|
||||||
|
Michael Elsdörfer <michael@elsdoerfer.com> Michael Elsdörfer <michael@elsdoerfer.info>
|
||||||
|
csoft2k <csoft2k@hotmail.com>
|
@@ -1,6 +1,8 @@
|
|||||||
language: python
|
language: python
|
||||||
sudo: false
|
sudo: false
|
||||||
cache: pip
|
cache: pip
|
||||||
|
git:
|
||||||
|
depth: 100000
|
||||||
addons:
|
addons:
|
||||||
apt:
|
apt:
|
||||||
packages:
|
packages:
|
||||||
@@ -37,6 +39,7 @@ matrix:
|
|||||||
- python: pypy3
|
- python: pypy3
|
||||||
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
|
||||||
script:
|
script:
|
||||||
- tox
|
- tox
|
||||||
- codecov
|
- codecov
|
||||||
|
27
AUTHORS
Normal file
27
AUTHORS
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
Ahmed Tahri
|
||||||
|
Asuki Kono
|
||||||
|
belono
|
||||||
|
Christoph Heuel
|
||||||
|
Cody (Quantified Code Bot)
|
||||||
|
csoft2k
|
||||||
|
Curtis // mashedkeyboard
|
||||||
|
Davis Goglin
|
||||||
|
Dean Rispin
|
||||||
|
Dmytro Katyukha
|
||||||
|
Hark
|
||||||
|
Joel Lehtonen
|
||||||
|
Kristi
|
||||||
|
ldos
|
||||||
|
Manuel F Martinez
|
||||||
|
Michael Billington
|
||||||
|
Michael Elsdörfer
|
||||||
|
Nathan Bookham
|
||||||
|
Patrick Kanzler
|
||||||
|
Qian Linfeng
|
||||||
|
Renato Lorenzi
|
||||||
|
Romain Porte
|
||||||
|
Sam Cheng
|
||||||
|
Stephan Sokolow
|
||||||
|
Thijs Triemstra
|
||||||
|
Thomas van den Berg
|
||||||
|
ysuolmai
|
@@ -12,6 +12,15 @@ The pull requests and issues will be prefilled with templates. Please fill in yo
|
|||||||
This project uses `semantic versioning <http://semver.org/>`_ and tries to adhere to the proposed rules as
|
This project uses `semantic versioning <http://semver.org/>`_ and tries to adhere to the proposed rules as
|
||||||
well as possible.
|
well as possible.
|
||||||
|
|
||||||
|
Author-list
|
||||||
|
-----------
|
||||||
|
|
||||||
|
This project keeps a list of authors. This can be auto-generated by calling `./doc/generate-authors.sh`.
|
||||||
|
When contributing the first time, please include a commit with the output of this script in place.
|
||||||
|
Otherwise the integration-check will fail.
|
||||||
|
|
||||||
|
When you change your username or mail-address, please also update the `.mailmap` and the authors-list.
|
||||||
|
|
||||||
Style-Guide
|
Style-Guide
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
|
@@ -47,10 +47,11 @@ Dependencies
|
|||||||
|
|
||||||
This library makes use of:
|
This library makes use of:
|
||||||
|
|
||||||
* pyusb for USB-printers
|
* `pyusb <https://github.com/walac/pyusb>`_ for USB-printers
|
||||||
* Pillow for image printing
|
* `Pillow <https://github.com/python-pillow/Pillow>`_ for image printing
|
||||||
* qrcode for the generation of QR-codes
|
* `qrcode <https://github.com/lincolnloop/python-qrcode>`_ for the generation of QR-codes
|
||||||
* pyserial for serial printers
|
* `pyserial <https://github.com/pyserial/pyserial>`_ for serial printers
|
||||||
|
* `viivakoodi <https://github.com/kxepal/viivakoodi>`_ for the generation of barcodes
|
||||||
|
|
||||||
Documentation and Usage
|
Documentation and Usage
|
||||||
-----------------------
|
-----------------------
|
||||||
|
125
appveyor.yml
Normal file
125
appveyor.yml
Normal file
@@ -0,0 +1,125 @@
|
|||||||
|
environment:
|
||||||
|
global:
|
||||||
|
# SDK v7.0 MSVC Express 2008's SetEnv.cmd script will fail if the
|
||||||
|
# /E:ON and /V:ON options are not enabled in the batch script intepreter
|
||||||
|
# See: http://stackoverflow.com/a/13751649/163740
|
||||||
|
CMD_IN_ENV: "cmd /E:ON /V:ON /C .\\appveyor\\run_with_env.cmd"
|
||||||
|
|
||||||
|
matrix:
|
||||||
|
|
||||||
|
# Python 2.7.10 is the latest version and is not pre-installed.
|
||||||
|
|
||||||
|
- PYTHON: "C:\\Python27.10"
|
||||||
|
PYTHON_VERSION: "2.7.10"
|
||||||
|
PYTHON_ARCH: "32"
|
||||||
|
|
||||||
|
- PYTHON: "C:\\Python27.10-x64"
|
||||||
|
PYTHON_VERSION: "2.7.10"
|
||||||
|
PYTHON_ARCH: "64"
|
||||||
|
|
||||||
|
# Pre-installed Python versions, which Appveyor may upgrade to
|
||||||
|
# a later point release.
|
||||||
|
# See: http://www.appveyor.com/docs/installed-software#python
|
||||||
|
|
||||||
|
- PYTHON: "C:\\Python27"
|
||||||
|
PYTHON_VERSION: "2.7.x" # currently 2.7.9
|
||||||
|
PYTHON_ARCH: "32"
|
||||||
|
|
||||||
|
- PYTHON: "C:\\Python27-x64"
|
||||||
|
PYTHON_VERSION: "2.7.x" # currently 2.7.9
|
||||||
|
PYTHON_ARCH: "64"
|
||||||
|
|
||||||
|
- PYTHON: "C:\\Python33"
|
||||||
|
PYTHON_VERSION: "3.3.x" # currently 3.3.5
|
||||||
|
PYTHON_ARCH: "32"
|
||||||
|
|
||||||
|
- PYTHON: "C:\\Python33-x64"
|
||||||
|
PYTHON_VERSION: "3.3.x" # currently 3.3.5
|
||||||
|
PYTHON_ARCH: "64"
|
||||||
|
|
||||||
|
- PYTHON: "C:\\Python34"
|
||||||
|
PYTHON_VERSION: "3.4.x" # currently 3.4.3
|
||||||
|
PYTHON_ARCH: "32"
|
||||||
|
|
||||||
|
- PYTHON: "C:\\Python34-x64"
|
||||||
|
PYTHON_VERSION: "3.4.x" # currently 3.4.3
|
||||||
|
PYTHON_ARCH: "64"
|
||||||
|
|
||||||
|
# Python versions not pre-installed
|
||||||
|
|
||||||
|
- PYTHON: "C:\\Python35"
|
||||||
|
PYTHON_VERSION: "3.5.0"
|
||||||
|
PYTHON_ARCH: "32"
|
||||||
|
|
||||||
|
- PYTHON: "C:\\Python35-x64"
|
||||||
|
PYTHON_VERSION: "3.5.0"
|
||||||
|
PYTHON_ARCH: "64"
|
||||||
|
|
||||||
|
# Major and minor releases (i.e x.0.0 and x.y.0) prior to 3.3.0 use
|
||||||
|
# a different naming scheme.
|
||||||
|
|
||||||
|
- PYTHON: "C:\\Python270"
|
||||||
|
PYTHON_VERSION: "2.7.0"
|
||||||
|
PYTHON_ARCH: "32"
|
||||||
|
|
||||||
|
- PYTHON: "C:\\Python270-x64"
|
||||||
|
PYTHON_VERSION: "2.7.0"
|
||||||
|
PYTHON_ARCH: "64"
|
||||||
|
|
||||||
|
install:
|
||||||
|
# If there is a newer build queued for the same PR, cancel this one.
|
||||||
|
# The AppVeyor 'rollout builds' option is supposed to serve the same
|
||||||
|
# purpose but it is problematic because it tends to cancel builds pushed
|
||||||
|
# directly to master instead of just PR builds (or the converse).
|
||||||
|
# credits: JuliaLang developers.
|
||||||
|
- ps: if ($env:APPVEYOR_PULL_REQUEST_NUMBER -and $env:APPVEYOR_BUILD_NUMBER -ne ((Invoke-RestMethod `
|
||||||
|
https://ci.appveyor.com/api/projects/$env:APPVEYOR_ACCOUNT_NAME/$env:APPVEYOR_PROJECT_SLUG/history?recordsNumber=50).builds | `
|
||||||
|
Where-Object pullRequestId -eq $env:APPVEYOR_PULL_REQUEST_NUMBER)[0].buildNumber) { `
|
||||||
|
throw "There are newer queued builds for this pull request, failing early." }
|
||||||
|
- ECHO "Filesystem root:"
|
||||||
|
- ps: "ls \"C:/\""
|
||||||
|
|
||||||
|
- ECHO "Installed SDKs:"
|
||||||
|
- ps: "ls \"C:/Program Files/Microsoft SDKs/Windows\""
|
||||||
|
|
||||||
|
# Install Python (from the official .msi of http://python.org) and pip when
|
||||||
|
# not already installed.
|
||||||
|
- ps: if (-not(Test-Path($env:PYTHON))) { & appveyor\install.ps1 }
|
||||||
|
|
||||||
|
# Prepend newly installed Python to the PATH of this build (this cannot be
|
||||||
|
# done from inside the powershell script as it would require to restart
|
||||||
|
# the parent CMD process).
|
||||||
|
- "SET PATH=%PYTHON%;%PYTHON%\\Scripts;%PATH%"
|
||||||
|
|
||||||
|
# Check that we have the expected version and architecture for Python
|
||||||
|
- "python --version"
|
||||||
|
- "python -c \"import struct; print(struct.calcsize('P') * 8)\""
|
||||||
|
|
||||||
|
# Upgrade to the latest version of pip to avoid it displaying warnings
|
||||||
|
# about it being out of date.
|
||||||
|
- "pip install --disable-pip-version-check --user --upgrade pip"
|
||||||
|
|
||||||
|
# Install the build dependencies of the project. If some dependencies contain
|
||||||
|
# compiled extensions and are not provided as pre-built wheel packages,
|
||||||
|
# pip will build them from source using the MSVC compiler matching the
|
||||||
|
# target Python version and architecture
|
||||||
|
- "%CMD_IN_ENV% pip install -r requirements.txt"
|
||||||
|
|
||||||
|
build_script:
|
||||||
|
# Build the compiled extension
|
||||||
|
- "%CMD_IN_ENV% python setup.py build"
|
||||||
|
|
||||||
|
test_script:
|
||||||
|
# Run the project tests
|
||||||
|
- "%CMD_IN_ENV% python setup.py test"
|
||||||
|
|
||||||
|
after_test:
|
||||||
|
# If tests are successful, create binary packages for the project.
|
||||||
|
- "%CMD_IN_ENV% python setup.py bdist_wheel"
|
||||||
|
- "%CMD_IN_ENV% python setup.py bdist_wininst"
|
||||||
|
- "%CMD_IN_ENV% python setup.py bdist_msi"
|
||||||
|
- ps: "ls dist"
|
||||||
|
|
||||||
|
artifacts:
|
||||||
|
# Archive the generated packages in the ci.appveyor.com build report.
|
||||||
|
- path: dist\*
|
229
appveyor/install.ps1
Normal file
229
appveyor/install.ps1
Normal file
@@ -0,0 +1,229 @@
|
|||||||
|
# Sample script to install Python and pip under Windows
|
||||||
|
# Authors: Olivier Grisel, Jonathan Helmus, Kyle Kastner, and Alex Willmer
|
||||||
|
# License: CC0 1.0 Universal: http://creativecommons.org/publicdomain/zero/1.0/
|
||||||
|
|
||||||
|
$MINICONDA_URL = "http://repo.continuum.io/miniconda/"
|
||||||
|
$BASE_URL = "https://www.python.org/ftp/python/"
|
||||||
|
$GET_PIP_URL = "https://bootstrap.pypa.io/get-pip.py"
|
||||||
|
$GET_PIP_PATH = "C:\get-pip.py"
|
||||||
|
|
||||||
|
$PYTHON_PRERELEASE_REGEX = @"
|
||||||
|
(?x)
|
||||||
|
(?<major>\d+)
|
||||||
|
\.
|
||||||
|
(?<minor>\d+)
|
||||||
|
\.
|
||||||
|
(?<micro>\d+)
|
||||||
|
(?<prerelease>[a-z]{1,2}\d+)
|
||||||
|
"@
|
||||||
|
|
||||||
|
|
||||||
|
function Download ($filename, $url) {
|
||||||
|
$webclient = New-Object System.Net.WebClient
|
||||||
|
|
||||||
|
$basedir = $pwd.Path + "\"
|
||||||
|
$filepath = $basedir + $filename
|
||||||
|
if (Test-Path $filename) {
|
||||||
|
Write-Host "Reusing" $filepath
|
||||||
|
return $filepath
|
||||||
|
}
|
||||||
|
|
||||||
|
# Download and retry up to 3 times in case of network transient errors.
|
||||||
|
Write-Host "Downloading" $filename "from" $url
|
||||||
|
$retry_attempts = 2
|
||||||
|
for ($i = 0; $i -lt $retry_attempts; $i++) {
|
||||||
|
try {
|
||||||
|
$webclient.DownloadFile($url, $filepath)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
Catch [Exception]{
|
||||||
|
Start-Sleep 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (Test-Path $filepath) {
|
||||||
|
Write-Host "File saved at" $filepath
|
||||||
|
} else {
|
||||||
|
# Retry once to get the error message if any at the last try
|
||||||
|
$webclient.DownloadFile($url, $filepath)
|
||||||
|
}
|
||||||
|
return $filepath
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function ParsePythonVersion ($python_version) {
|
||||||
|
if ($python_version -match $PYTHON_PRERELEASE_REGEX) {
|
||||||
|
return ([int]$matches.major, [int]$matches.minor, [int]$matches.micro,
|
||||||
|
$matches.prerelease)
|
||||||
|
}
|
||||||
|
$version_obj = [version]$python_version
|
||||||
|
return ($version_obj.major, $version_obj.minor, $version_obj.build, "")
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function DownloadPython ($python_version, $platform_suffix) {
|
||||||
|
$major, $minor, $micro, $prerelease = ParsePythonVersion $python_version
|
||||||
|
|
||||||
|
if (($major -le 2 -and $micro -eq 0) `
|
||||||
|
-or ($major -eq 3 -and $minor -le 2 -and $micro -eq 0) `
|
||||||
|
) {
|
||||||
|
$dir = "$major.$minor"
|
||||||
|
$python_version = "$major.$minor$prerelease"
|
||||||
|
} else {
|
||||||
|
$dir = "$major.$minor.$micro"
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($prerelease) {
|
||||||
|
if (($major -le 2) `
|
||||||
|
-or ($major -eq 3 -and $minor -eq 1) `
|
||||||
|
-or ($major -eq 3 -and $minor -eq 2) `
|
||||||
|
-or ($major -eq 3 -and $minor -eq 3) `
|
||||||
|
) {
|
||||||
|
$dir = "$dir/prev"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (($major -le 2) -or ($major -le 3 -and $minor -le 4)) {
|
||||||
|
$ext = "msi"
|
||||||
|
if ($platform_suffix) {
|
||||||
|
$platform_suffix = ".$platform_suffix"
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
$ext = "exe"
|
||||||
|
if ($platform_suffix) {
|
||||||
|
$platform_suffix = "-$platform_suffix"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$filename = "python-$python_version$platform_suffix.$ext"
|
||||||
|
$url = "$BASE_URL$dir/$filename"
|
||||||
|
$filepath = Download $filename $url
|
||||||
|
return $filepath
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function InstallPython ($python_version, $architecture, $python_home) {
|
||||||
|
Write-Host "Installing Python" $python_version "for" $architecture "bit architecture to" $python_home
|
||||||
|
if (Test-Path $python_home) {
|
||||||
|
Write-Host $python_home "already exists, skipping."
|
||||||
|
return $false
|
||||||
|
}
|
||||||
|
if ($architecture -eq "32") {
|
||||||
|
$platform_suffix = ""
|
||||||
|
} else {
|
||||||
|
$platform_suffix = "amd64"
|
||||||
|
}
|
||||||
|
$installer_path = DownloadPython $python_version $platform_suffix
|
||||||
|
$installer_ext = [System.IO.Path]::GetExtension($installer_path)
|
||||||
|
Write-Host "Installing $installer_path to $python_home"
|
||||||
|
$install_log = $python_home + ".log"
|
||||||
|
if ($installer_ext -eq '.msi') {
|
||||||
|
InstallPythonMSI $installer_path $python_home $install_log
|
||||||
|
} else {
|
||||||
|
InstallPythonEXE $installer_path $python_home $install_log
|
||||||
|
}
|
||||||
|
if (Test-Path $python_home) {
|
||||||
|
Write-Host "Python $python_version ($architecture) installation complete"
|
||||||
|
} else {
|
||||||
|
Write-Host "Failed to install Python in $python_home"
|
||||||
|
Get-Content -Path $install_log
|
||||||
|
Exit 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function InstallPythonEXE ($exepath, $python_home, $install_log) {
|
||||||
|
$install_args = "/quiet InstallAllUsers=1 TargetDir=$python_home"
|
||||||
|
RunCommand $exepath $install_args
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function InstallPythonMSI ($msipath, $python_home, $install_log) {
|
||||||
|
$install_args = "/qn /log $install_log /i $msipath TARGETDIR=$python_home"
|
||||||
|
$uninstall_args = "/qn /x $msipath"
|
||||||
|
RunCommand "msiexec.exe" $install_args
|
||||||
|
if (-not(Test-Path $python_home)) {
|
||||||
|
Write-Host "Python seems to be installed else-where, reinstalling."
|
||||||
|
RunCommand "msiexec.exe" $uninstall_args
|
||||||
|
RunCommand "msiexec.exe" $install_args
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function RunCommand ($command, $command_args) {
|
||||||
|
Write-Host $command $command_args
|
||||||
|
Start-Process -FilePath $command -ArgumentList $command_args -Wait -Passthru
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function InstallPip ($python_home) {
|
||||||
|
$pip_path = $python_home + "\Scripts\pip.exe"
|
||||||
|
$python_path = $python_home + "\python.exe"
|
||||||
|
if (-not(Test-Path $pip_path)) {
|
||||||
|
Write-Host "Installing pip..."
|
||||||
|
$webclient = New-Object System.Net.WebClient
|
||||||
|
$webclient.DownloadFile($GET_PIP_URL, $GET_PIP_PATH)
|
||||||
|
Write-Host "Executing:" $python_path $GET_PIP_PATH
|
||||||
|
& $python_path $GET_PIP_PATH
|
||||||
|
} else {
|
||||||
|
Write-Host "pip already installed."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function DownloadMiniconda ($python_version, $platform_suffix) {
|
||||||
|
if ($python_version -eq "3.4") {
|
||||||
|
$filename = "Miniconda3-3.5.5-Windows-" + $platform_suffix + ".exe"
|
||||||
|
} else {
|
||||||
|
$filename = "Miniconda-3.5.5-Windows-" + $platform_suffix + ".exe"
|
||||||
|
}
|
||||||
|
$url = $MINICONDA_URL + $filename
|
||||||
|
$filepath = Download $filename $url
|
||||||
|
return $filepath
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function InstallMiniconda ($python_version, $architecture, $python_home) {
|
||||||
|
Write-Host "Installing Python" $python_version "for" $architecture "bit architecture to" $python_home
|
||||||
|
if (Test-Path $python_home) {
|
||||||
|
Write-Host $python_home "already exists, skipping."
|
||||||
|
return $false
|
||||||
|
}
|
||||||
|
if ($architecture -eq "32") {
|
||||||
|
$platform_suffix = "x86"
|
||||||
|
} else {
|
||||||
|
$platform_suffix = "x86_64"
|
||||||
|
}
|
||||||
|
$filepath = DownloadMiniconda $python_version $platform_suffix
|
||||||
|
Write-Host "Installing" $filepath "to" $python_home
|
||||||
|
$install_log = $python_home + ".log"
|
||||||
|
$args = "/S /D=$python_home"
|
||||||
|
Write-Host $filepath $args
|
||||||
|
Start-Process -FilePath $filepath -ArgumentList $args -Wait -Passthru
|
||||||
|
if (Test-Path $python_home) {
|
||||||
|
Write-Host "Python $python_version ($architecture) installation complete"
|
||||||
|
} else {
|
||||||
|
Write-Host "Failed to install Python in $python_home"
|
||||||
|
Get-Content -Path $install_log
|
||||||
|
Exit 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function InstallMinicondaPip ($python_home) {
|
||||||
|
$pip_path = $python_home + "\Scripts\pip.exe"
|
||||||
|
$conda_path = $python_home + "\Scripts\conda.exe"
|
||||||
|
if (-not(Test-Path $pip_path)) {
|
||||||
|
Write-Host "Installing pip..."
|
||||||
|
$args = "install --yes pip"
|
||||||
|
Write-Host $conda_path $args
|
||||||
|
Start-Process -FilePath "$conda_path" -ArgumentList $args -Wait -Passthru
|
||||||
|
} else {
|
||||||
|
Write-Host "pip already installed."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function main () {
|
||||||
|
InstallPython $env:PYTHON_VERSION $env:PYTHON_ARCH $env:PYTHON
|
||||||
|
InstallPip $env:PYTHON
|
||||||
|
}
|
||||||
|
|
||||||
|
main
|
88
appveyor/run_with_env.cmd
Normal file
88
appveyor/run_with_env.cmd
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
:: To build extensions for 64 bit Python 3, we need to configure environment
|
||||||
|
:: variables to use the MSVC 2010 C++ compilers from GRMSDKX_EN_DVD.iso of:
|
||||||
|
:: MS Windows SDK for Windows 7 and .NET Framework 4 (SDK v7.1)
|
||||||
|
::
|
||||||
|
:: To build extensions for 64 bit Python 2, we need to configure environment
|
||||||
|
:: variables to use the MSVC 2008 C++ compilers from GRMSDKX_EN_DVD.iso of:
|
||||||
|
:: MS Windows SDK for Windows 7 and .NET Framework 3.5 (SDK v7.0)
|
||||||
|
::
|
||||||
|
:: 32 bit builds, and 64-bit builds for 3.5 and beyond, do not require specific
|
||||||
|
:: environment configurations.
|
||||||
|
::
|
||||||
|
:: Note: this script needs to be run with the /E:ON and /V:ON flags for the
|
||||||
|
:: cmd interpreter, at least for (SDK v7.0)
|
||||||
|
::
|
||||||
|
:: More details at:
|
||||||
|
:: https://github.com/cython/cython/wiki/64BitCythonExtensionsOnWindows
|
||||||
|
:: http://stackoverflow.com/a/13751649/163740
|
||||||
|
::
|
||||||
|
:: Author: Olivier Grisel
|
||||||
|
:: License: CC0 1.0 Universal: http://creativecommons.org/publicdomain/zero/1.0/
|
||||||
|
::
|
||||||
|
:: Notes about batch files for Python people:
|
||||||
|
::
|
||||||
|
:: Quotes in values are literally part of the values:
|
||||||
|
:: SET FOO="bar"
|
||||||
|
:: FOO is now five characters long: " b a r "
|
||||||
|
:: If you don't want quotes, don't include them on the right-hand side.
|
||||||
|
::
|
||||||
|
:: The CALL lines at the end of this file look redundant, but if you move them
|
||||||
|
:: outside of the IF clauses, they do not run properly in the SET_SDK_64==Y
|
||||||
|
:: case, I don't know why.
|
||||||
|
@ECHO OFF
|
||||||
|
|
||||||
|
SET COMMAND_TO_RUN=%*
|
||||||
|
SET WIN_SDK_ROOT=C:\Program Files\Microsoft SDKs\Windows
|
||||||
|
SET WIN_WDK=c:\Program Files (x86)\Windows Kits\10\Include\wdf
|
||||||
|
|
||||||
|
:: Extract the major and minor versions, and allow for the minor version to be
|
||||||
|
:: more than 9. This requires the version number to have two dots in it.
|
||||||
|
SET MAJOR_PYTHON_VERSION=%PYTHON_VERSION:~0,1%
|
||||||
|
IF "%PYTHON_VERSION:~3,1%" == "." (
|
||||||
|
SET MINOR_PYTHON_VERSION=%PYTHON_VERSION:~2,1%
|
||||||
|
) ELSE (
|
||||||
|
SET MINOR_PYTHON_VERSION=%PYTHON_VERSION:~2,2%
|
||||||
|
)
|
||||||
|
|
||||||
|
:: Based on the Python version, determine what SDK version to use, and whether
|
||||||
|
:: to set the SDK for 64-bit.
|
||||||
|
IF %MAJOR_PYTHON_VERSION% == 2 (
|
||||||
|
SET WINDOWS_SDK_VERSION="v7.0"
|
||||||
|
SET SET_SDK_64=Y
|
||||||
|
) ELSE (
|
||||||
|
IF %MAJOR_PYTHON_VERSION% == 3 (
|
||||||
|
SET WINDOWS_SDK_VERSION="v7.1"
|
||||||
|
IF %MINOR_PYTHON_VERSION% LEQ 4 (
|
||||||
|
SET SET_SDK_64=Y
|
||||||
|
) ELSE (
|
||||||
|
SET SET_SDK_64=N
|
||||||
|
IF EXIST "%WIN_WDK%" (
|
||||||
|
:: See: https://connect.microsoft.com/VisualStudio/feedback/details/1610302/
|
||||||
|
REN "%WIN_WDK%" 0wdf
|
||||||
|
)
|
||||||
|
)
|
||||||
|
) ELSE (
|
||||||
|
ECHO Unsupported Python version: "%MAJOR_PYTHON_VERSION%"
|
||||||
|
EXIT 1
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
IF %PYTHON_ARCH% == 64 (
|
||||||
|
IF %SET_SDK_64% == Y (
|
||||||
|
ECHO Configuring Windows SDK %WINDOWS_SDK_VERSION% for Python %MAJOR_PYTHON_VERSION% on a 64 bit architecture
|
||||||
|
SET DISTUTILS_USE_SDK=1
|
||||||
|
SET MSSdk=1
|
||||||
|
"%WIN_SDK_ROOT%\%WINDOWS_SDK_VERSION%\Setup\WindowsSdkVer.exe" -q -version:%WINDOWS_SDK_VERSION%
|
||||||
|
"%WIN_SDK_ROOT%\%WINDOWS_SDK_VERSION%\Bin\SetEnv.cmd" /x64 /release
|
||||||
|
ECHO Executing: %COMMAND_TO_RUN%
|
||||||
|
call %COMMAND_TO_RUN% || EXIT 1
|
||||||
|
) ELSE (
|
||||||
|
ECHO Using default MSVC build environment for 64 bit architecture
|
||||||
|
ECHO Executing: %COMMAND_TO_RUN%
|
||||||
|
call %COMMAND_TO_RUN% || EXIT 1
|
||||||
|
)
|
||||||
|
) ELSE (
|
||||||
|
ECHO Using default MSVC build environment for 32 bit architecture
|
||||||
|
ECHO Executing: %COMMAND_TO_RUN%
|
||||||
|
call %COMMAND_TO_RUN% || EXIT 1
|
||||||
|
)
|
94
debian/changelog
vendored
94
debian/changelog
vendored
@@ -1,94 +0,0 @@
|
|||||||
python-escpos (1.0.8-3) unstable; urgency=medium
|
|
||||||
|
|
||||||
[ Christoph Heuel ]
|
|
||||||
* Fix text wrapping error after image
|
|
||||||
|
|
||||||
[ Patrick Kanzler ]
|
|
||||||
* moved .hgignore to .gitignore
|
|
||||||
* REFACTOR chained boolean expression in escpos
|
|
||||||
* REFACTOR use new-style class for Escpos
|
|
||||||
* REFACTOR style and PEP8, fixes #66
|
|
||||||
* REFACTOR do not shadow built-ins
|
|
||||||
* ADD requirements.txt and requirements to setup.py
|
|
||||||
* DOC, IMPROVE improve docstrings and add abstract method _raw to Escpos
|
|
||||||
* FIX constant definition for PC1252
|
|
||||||
|
|
||||||
-- Christoph Heuel <mail@christoph-heuel.net> Sun, 13 Dec 2015 14:27:27 +0100
|
|
||||||
|
|
||||||
python-escpos (1.0.8-2) unstable; urgency=low
|
|
||||||
|
|
||||||
* Imported source
|
|
||||||
* First debianization
|
|
||||||
|
|
||||||
-- Christoph Heuel <mail@christoph-heuel.net> Sat, 12 Dec 2015 19:13:33 +0100
|
|
||||||
|
|
||||||
python-escpos (1.0.8-1) unstable; urgency=low
|
|
||||||
|
|
||||||
[ Manuel F Martinez ]
|
|
||||||
* Added donation message
|
|
||||||
|
|
||||||
[ Joel Lehtonen ]
|
|
||||||
* Support for images vertically longer than 256 pixels
|
|
||||||
|
|
||||||
[ Christoph Heuel ]
|
|
||||||
* Fix mixed tabs/space error
|
|
||||||
|
|
||||||
[ Hark ]
|
|
||||||
* Prevent crash when using libusb0 printers
|
|
||||||
|
|
||||||
[ Manuel F Martinez ]
|
|
||||||
* Updated README and documentation
|
|
||||||
|
|
||||||
[ Christoph Heuel ]
|
|
||||||
* Add flush function
|
|
||||||
* Debian packaging
|
|
||||||
|
|
||||||
-- Manuel F Martinez <manpaz@gmail.com> Sat, 12 Dec 2015 20:59:53 +0100
|
|
||||||
|
|
||||||
python-escpos (1.0.7-1) unstable; urgency=low
|
|
||||||
|
|
||||||
[ Kristi ]
|
|
||||||
* Raising the right error when wrong charcode is used
|
|
||||||
|
|
||||||
[ Christoph Heuel ]
|
|
||||||
* After running 2to3 tool
|
|
||||||
* Fix for string operation
|
|
||||||
* Integer is needed, not float
|
|
||||||
* Add text wrapping
|
|
||||||
|
|
||||||
[ Manuel F Martinez ]
|
|
||||||
* Updated URL for the documentation
|
|
||||||
* Updated documentation URL to local wiki
|
|
||||||
* Updated setup URLs
|
|
||||||
|
|
||||||
[ Christoph Heuel ]
|
|
||||||
* Introduce new direct_image
|
|
||||||
|
|
||||||
[ Manuel F Martinez ]
|
|
||||||
* Fixed License version mismatch
|
|
||||||
|
|
||||||
[ Christoph Heuel ]
|
|
||||||
* Use unhexlify
|
|
||||||
* Hexlify text
|
|
||||||
|
|
||||||
[ Manuel F Martinez ]
|
|
||||||
* Updated accordingly to the wiki
|
|
||||||
|
|
||||||
[ ldos ]
|
|
||||||
* Extended params for serial printers
|
|
||||||
|
|
||||||
[ Manuel F Martinez ]
|
|
||||||
* Fixed issues with transparent images
|
|
||||||
* Updated project version
|
|
||||||
|
|
||||||
-- Manuel F Martinez <manpaz@gmail.com> Sat, 12 Dec 2015 20:59:53 +0100
|
|
||||||
|
|
||||||
python-escpos (1.0.4-1) unstable; urgency=medium
|
|
||||||
|
|
||||||
[ Manuel F Martinez ]
|
|
||||||
* Added density support
|
|
||||||
* Added quad support
|
|
||||||
* fixed code tabulators
|
|
||||||
* Updated version
|
|
||||||
|
|
||||||
-- Manuel F Martinez <manpaz@gmail.com> Sat, 12 Dec 2015 20:59:53 +0100
|
|
1
debian/compat
vendored
1
debian/compat
vendored
@@ -1 +0,0 @@
|
|||||||
9
|
|
55
debian/control
vendored
55
debian/control
vendored
@@ -1,55 +0,0 @@
|
|||||||
Source: python-escpos
|
|
||||||
Section: unknown
|
|
||||||
Priority: optional
|
|
||||||
Maintainer: Christoph Heuel <mail@christoph-heuel.net>
|
|
||||||
Build-Depends: debhelper (>= 9), dh-python
|
|
||||||
Standards-Version: 3.9.5
|
|
||||||
Homepage: https://github.com/braveheuel/python-escpos
|
|
||||||
#Vcs-Git: git@github.com:braveheuel/python-escpos.git
|
|
||||||
#Vcs-Browser: https://github.com/braveheuel/python-escpos
|
|
||||||
|
|
||||||
Package: python-escpos
|
|
||||||
Architecture: all
|
|
||||||
Depends: ${misc:Depends}
|
|
||||||
Description: Python library to manipulate ESC/POS Printers (Python 2)
|
|
||||||
Python ESC/POS is a library which lets the user have access to all
|
|
||||||
those printers handled by ESC/POS commands, as defined by Epson,
|
|
||||||
from a Python application.
|
|
||||||
.
|
|
||||||
The standard usage is send raw text to the printer, but in also
|
|
||||||
helps the user to enhance the experience with those printers by
|
|
||||||
facilitating the bar code printing in many different standards,
|
|
||||||
as well as manipulating images so they can be printed as brand
|
|
||||||
logo or any other usage images migh have.
|
|
||||||
.
|
|
||||||
Text can be aligned/justified and fonts can be changed by size,
|
|
||||||
type and weight.
|
|
||||||
.
|
|
||||||
Also, this module handles some hardware functionalities like, cut
|
|
||||||
paper, carrier return, printer reset and others concerned to the
|
|
||||||
carriage alignment.
|
|
||||||
.
|
|
||||||
This package covers Python 2 code.
|
|
||||||
|
|
||||||
Package: python3-escpos
|
|
||||||
Architecture: all
|
|
||||||
Depends: ${misc:Depends}
|
|
||||||
Description: Python library to manipulate ESC/POS Printers (Python 3)
|
|
||||||
Python ESC/POS is a library which lets the user have access to all
|
|
||||||
those printers handled by ESC/POS commands, as defined by Epson,
|
|
||||||
from a Python application.
|
|
||||||
.
|
|
||||||
The standard usage is send raw text to the printer, but in also
|
|
||||||
helps the user to enhance the experience with those printers by
|
|
||||||
facilitating the bar code printing in many different standards,
|
|
||||||
as well as manipulating images so they can be printed as brand
|
|
||||||
logo or any other usage images migh have.
|
|
||||||
.
|
|
||||||
Text can be aligned/justified and fonts can be changed by size,
|
|
||||||
type and weight.
|
|
||||||
.
|
|
||||||
Also, this module handles some hardware functionalities like, cut
|
|
||||||
paper, carrier return, printer reset and others concerned to the
|
|
||||||
carriage alignment.
|
|
||||||
.
|
|
||||||
This package covers Python 3 code.
|
|
26
debian/copyright
vendored
26
debian/copyright
vendored
@@ -1,26 +0,0 @@
|
|||||||
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
|
||||||
Upstream-Name: python-escpos
|
|
||||||
Source: https://github.com/manpaz/python-escpos
|
|
||||||
|
|
||||||
Files: *
|
|
||||||
Copyright: 2015 Manuel F Martinez <manpaz@bashlinux.com>
|
|
||||||
License: GPL v3
|
|
||||||
|
|
||||||
Files: debian/*
|
|
||||||
Copyright: 2015 Christoph Heuel <mail@christoph-heuel.net>
|
|
||||||
License: GPL-2+
|
|
||||||
This package is free software; you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation; either version 2 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
.
|
|
||||||
This package is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
.
|
|
||||||
You should have received a copy of the GNU General Public License
|
|
||||||
along with this program. If not, see <http://www.gnu.org/licenses/>
|
|
||||||
.
|
|
||||||
On Debian systems, the complete text of the GNU General
|
|
||||||
Public License version 2 can be found in "/usr/share/common-licenses/GPL-2".
|
|
1
debian/docs
vendored
1
debian/docs
vendored
@@ -1 +0,0 @@
|
|||||||
README.rst
|
|
6
debian/gbp.conf
vendored
6
debian/gbp.conf
vendored
@@ -1,6 +0,0 @@
|
|||||||
[DEFAULT]
|
|
||||||
upstream-branch=master
|
|
||||||
upstream-tree = tag
|
|
||||||
debian-branch = debian/jessie
|
|
||||||
upstream-tag = v%(version)s
|
|
||||||
debian-tag = v%(version)s
|
|
28
debian/rules
vendored
28
debian/rules
vendored
@@ -1,28 +0,0 @@
|
|||||||
#!/usr/bin/make -f
|
|
||||||
# See debhelper(7) (uncomment to enable)
|
|
||||||
# output every command that modifies files on the build system.
|
|
||||||
#DH_VERBOSE = 1
|
|
||||||
|
|
||||||
# see EXAMPLES in dpkg-buildflags(1) and read /usr/share/dpkg/*
|
|
||||||
DPKG_EXPORT_BUILDFLAGS = 1
|
|
||||||
include /usr/share/dpkg/default.mk
|
|
||||||
|
|
||||||
# see FEATURE AREAS in dpkg-buildflags(1)
|
|
||||||
#export DEB_BUILD_MAINT_OPTIONS = hardening=+all
|
|
||||||
|
|
||||||
# see ENVIRONMENT in dpkg-buildflags(1)
|
|
||||||
# package maintainers to append CFLAGS
|
|
||||||
#export DEB_CFLAGS_MAINT_APPEND = -Wall -pedantic
|
|
||||||
# package maintainers to append LDFLAGS
|
|
||||||
#export DEB_LDFLAGS_MAINT_APPEND = -Wl,--as-needed
|
|
||||||
|
|
||||||
|
|
||||||
# main packaging script based on dh7 syntax
|
|
||||||
%:
|
|
||||||
dh $@ --with python2,python3 --buildsystem=pybuild
|
|
||||||
|
|
||||||
# debmake generated override targets
|
|
||||||
# This is example for Cmake (See http://bugs.debian.org/641051 )
|
|
||||||
#override_dh_auto_configure:
|
|
||||||
# dh_auto_configure -- \
|
|
||||||
# -DCMAKE_LIBRARY_PATH=$(DEB_HOST_MULTIARCH)
|
|
1
debian/source/format
vendored
1
debian/source/format
vendored
@@ -1 +0,0 @@
|
|||||||
3.0 (quilt)
|
|
19
doc/generate_authors.sh
Executable file
19
doc/generate_authors.sh
Executable file
@@ -0,0 +1,19 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
GENLIST=$(git shortlog -s -n | cut -f2 | sort)
|
||||||
|
AUTHORSFILE="$(dirname $0)/../AUTHORS"
|
||||||
|
TEMPAUTHORSFILE="/tmp/python-escpos-authorsfile"
|
||||||
|
|
||||||
|
if [ "$#" -eq 1 ]
|
||||||
|
then
|
||||||
|
echo "$GENLIST">$TEMPAUTHORSFILE
|
||||||
|
echo "\nAuthorsfile in version control:\n"
|
||||||
|
cat $AUTHORSFILE
|
||||||
|
echo "\nNew authorsfile:\n"
|
||||||
|
cat $TEMPAUTHORSFILE
|
||||||
|
echo "\nUsing diff on files...\n"
|
||||||
|
diff -q --from-file $AUTHORSFILE $TEMPAUTHORSFILE
|
||||||
|
else
|
||||||
|
echo "$GENLIST">$AUTHORSFILE
|
||||||
|
fi
|
||||||
|
|
@@ -1,6 +1,7 @@
|
|||||||
*****
|
*****
|
||||||
Usage
|
Usage
|
||||||
*****
|
*****
|
||||||
|
:Last Reviewed: 2017-06-10
|
||||||
|
|
||||||
Define your printer
|
Define your printer
|
||||||
-------------------
|
-------------------
|
||||||
@@ -133,13 +134,13 @@ format. For windows it is probably at::
|
|||||||
|
|
||||||
And for linux::
|
And for linux::
|
||||||
|
|
||||||
$HOME/.config/python-escpos/config.yaml
|
$HOME/.config/python-escpos/config.yaml
|
||||||
|
|
||||||
If you aren't sure, run::
|
If you aren't sure, run::
|
||||||
|
|
||||||
from escpos import config
|
from escpos import config
|
||||||
c = config.Config()
|
c = config.Config()
|
||||||
c.load()
|
c.load()
|
||||||
|
|
||||||
If it can't find the configuration file in the default location, it will tell
|
If it can't find the configuration file in the default location, it will tell
|
||||||
you where it's looking. You can always pass a path, or a list of paths, to
|
you where it's looking. You can always pass a path, or a list of paths, to
|
||||||
@@ -147,9 +148,9 @@ the ``load()`` method.
|
|||||||
|
|
||||||
To load the configured printer, run::
|
To load the configured printer, run::
|
||||||
|
|
||||||
from escpos import config
|
from escpos import config
|
||||||
c = config.Config()
|
c = config.Config()
|
||||||
printer = c.printer()
|
printer = c.printer()
|
||||||
|
|
||||||
|
|
||||||
The printer section
|
The printer section
|
||||||
@@ -157,23 +158,34 @@ The printer section
|
|||||||
|
|
||||||
The ``printer`` configuration section defines a default printer to create.
|
The ``printer`` configuration section defines a default printer to create.
|
||||||
|
|
||||||
The only required paramter is ``type``. The value of this should be one of the
|
The only required paramter is ``type``. The value of this has to be one of the
|
||||||
printers defined in :doc:`/user/printers`.
|
printers defined in :doc:`/user/printers`.
|
||||||
|
|
||||||
The rest of the parameters are whatever you want to pass to the printer.
|
The rest of the given parameters will be passed on to the initialization of the printer class.
|
||||||
|
Use these to overwrite the default values as specified in :doc:`/user/printers`.
|
||||||
|
This implies that the parameters have to match the parameter-names of the respective printer class.
|
||||||
|
|
||||||
An example file printer::
|
An example file printer::
|
||||||
|
|
||||||
printer:
|
printer:
|
||||||
type: File
|
type: File
|
||||||
devfile: /dev/someprinter
|
devfile: /dev/someprinter
|
||||||
|
|
||||||
And for a network printer::
|
And for a network printer::
|
||||||
|
|
||||||
printer:
|
printer:
|
||||||
type: network
|
type: Network
|
||||||
host: 127.0.0.1
|
host: 127.0.0.1
|
||||||
port: 9000
|
port: 9000
|
||||||
|
|
||||||
|
An USB-printer could be defined by::
|
||||||
|
|
||||||
|
printer:
|
||||||
|
type: Usb
|
||||||
|
idVendor: 0x1234
|
||||||
|
idProduct: 0x5678
|
||||||
|
in_ep: 0x66
|
||||||
|
out_ep: 0x01
|
||||||
|
|
||||||
Printing text right
|
Printing text right
|
||||||
-------------------
|
-------------------
|
||||||
|
19
examples/qr_code.py
Normal file
19
examples/qr_code.py
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import sys
|
||||||
|
|
||||||
|
from escpos.printer import Usb
|
||||||
|
|
||||||
|
|
||||||
|
def usage():
|
||||||
|
print("usage: qr_code.py <content>")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
if len(sys.argv) != 2:
|
||||||
|
usage()
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
content = sys.argv[1]
|
||||||
|
|
||||||
|
# Adapt to your needs
|
||||||
|
p = Usb(0x0416, 0x5011, profile="POS-5890")
|
||||||
|
p.qr(content)
|
9
examples/software_barcode.py
Normal file
9
examples/software_barcode.py
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
from escpos.printer import Usb
|
||||||
|
|
||||||
|
|
||||||
|
# Adapt to your needs
|
||||||
|
p = Usb(0x0416, 0x5011, profile="POS-5890")
|
||||||
|
|
||||||
|
# Some software barcodes
|
||||||
|
p.soft_barcode('code128', 'Hello')
|
||||||
|
p.soft_barcode('code39', '123456')
|
5
setup.py
5
setup.py
@@ -100,6 +100,8 @@ setup(
|
|||||||
'Programming Language :: Python :: 3.3',
|
'Programming Language :: Python :: 3.3',
|
||||||
'Programming Language :: Python :: 3.4',
|
'Programming Language :: Python :: 3.4',
|
||||||
'Programming Language :: Python :: 3.5',
|
'Programming Language :: Python :: 3.5',
|
||||||
|
'Programming Language :: Python :: 3.6',
|
||||||
|
'Programming Language :: Python :: 3.7',
|
||||||
'Programming Language :: Python :: Implementation :: CPython',
|
'Programming Language :: Python :: Implementation :: CPython',
|
||||||
'Programming Language :: Python :: Implementation :: PyPy',
|
'Programming Language :: Python :: Implementation :: PyPy',
|
||||||
'Topic :: Software Development :: Libraries :: Python Modules',
|
'Topic :: Software Development :: Libraries :: Python Modules',
|
||||||
@@ -115,7 +117,8 @@ setup(
|
|||||||
'pyyaml',
|
'pyyaml',
|
||||||
'argparse',
|
'argparse',
|
||||||
'argcomplete',
|
'argcomplete',
|
||||||
'future'
|
'future',
|
||||||
|
'viivakoodi>=0.8'
|
||||||
],
|
],
|
||||||
setup_requires=[
|
setup_requires=[
|
||||||
'setuptools_scm',
|
'setuptools_scm',
|
||||||
|
@@ -64,6 +64,11 @@ _PANEL_BUTTON = lambda n: ESC + b'c5' + six.int2byte(n)
|
|||||||
PANEL_BUTTON_ON = _PANEL_BUTTON(0) # enable all panel buttons
|
PANEL_BUTTON_ON = _PANEL_BUTTON(0) # enable all panel buttons
|
||||||
PANEL_BUTTON_OFF = _PANEL_BUTTON(1) # disable all panel buttons
|
PANEL_BUTTON_OFF = _PANEL_BUTTON(1) # disable all panel buttons
|
||||||
|
|
||||||
|
# Line display printing
|
||||||
|
LINE_DISPLAY_OPEN = ESC + b'\x3d\x02'
|
||||||
|
LINE_DISPLAY_CLEAR = ESC + b'\x40'
|
||||||
|
LINE_DISPLAY_CLOSE = ESC + b'\x3d\x01'
|
||||||
|
|
||||||
# Sheet modes
|
# Sheet modes
|
||||||
SHEET_SLIP_MODE = ESC + b'\x63\x30\x04' # slip paper
|
SHEET_SLIP_MODE = ESC + b'\x63\x30\x04' # slip paper
|
||||||
SHEET_ROLL_MODE = ESC + b'\x63\x30\x01' # paper roll
|
SHEET_ROLL_MODE = ESC + b'\x63\x30\x01' # paper roll
|
||||||
@@ -71,51 +76,90 @@ SHEET_ROLL_MODE = ESC + b'\x63\x30\x01' # paper roll
|
|||||||
# Text format
|
# Text format
|
||||||
# TODO: Acquire the "ESC/POS Application Programming Guide for Paper Roll
|
# TODO: Acquire the "ESC/POS Application Programming Guide for Paper Roll
|
||||||
# Printers" and tidy up this stuff too.
|
# Printers" and tidy up this stuff too.
|
||||||
TXT_FLIP_ON = ESC + b'\x7b\x01'
|
|
||||||
TXT_FLIP_OFF = ESC + b'\x7b\x00'
|
|
||||||
TXT_SMOOTH_ON = GS + b'\x62\x01'
|
|
||||||
TXT_SMOOTH_OFF = GS + b'\x62\x00'
|
|
||||||
TXT_SIZE = GS + b'!'
|
TXT_SIZE = GS + b'!'
|
||||||
TXT_WIDTH = {1: 0x00,
|
|
||||||
2: 0x10,
|
|
||||||
3: 0x20,
|
|
||||||
4: 0x30,
|
|
||||||
5: 0x40,
|
|
||||||
6: 0x50,
|
|
||||||
7: 0x60,
|
|
||||||
8: 0x70}
|
|
||||||
TXT_HEIGHT = {1: 0x00,
|
|
||||||
2: 0x01,
|
|
||||||
3: 0x02,
|
|
||||||
4: 0x03,
|
|
||||||
5: 0x04,
|
|
||||||
6: 0x05,
|
|
||||||
7: 0x06,
|
|
||||||
8: 0x07}
|
|
||||||
TXT_NORMAL = ESC + b'!\x00' # Normal text
|
TXT_NORMAL = ESC + b'!\x00' # Normal text
|
||||||
TXT_2HEIGHT = ESC + b'!\x10' # Double height text
|
|
||||||
TXT_2WIDTH = ESC + b'!\x20' # Double width text
|
|
||||||
TXT_4SQUARE = ESC + b'!\x30' # Quad area text
|
TXT_STYLE = {
|
||||||
TXT_UNDERL_OFF = ESC + b'\x2d\x00' # Underline font OFF
|
'bold': {
|
||||||
TXT_UNDERL_ON = ESC + b'\x2d\x01' # Underline font 1-dot ON
|
False: ESC + b'\x45\x00', # Bold font OFF
|
||||||
TXT_UNDERL2_ON = ESC + b'\x2d\x02' # Underline font 2-dot ON
|
True: ESC + b'\x45\x01' # Bold font ON
|
||||||
TXT_BOLD_OFF = ESC + b'\x45\x00' # Bold font OFF
|
},
|
||||||
TXT_BOLD_ON = ESC + b'\x45\x01' # Bold font ON
|
'underline': {
|
||||||
TXT_ALIGN_LT = ESC + b'\x61\x00' # Left justification
|
0: ESC + b'\x2d\x00', # Underline font OFF
|
||||||
TXT_ALIGN_CT = ESC + b'\x61\x01' # Centering
|
1: ESC + b'\x2d\x01', # Underline font 1-dot ON
|
||||||
TXT_ALIGN_RT = ESC + b'\x61\x02' # Right justification
|
2: ESC + b'\x2d\x02' # Underline font 2-dot ON
|
||||||
TXT_INVERT_ON = GS + b'\x42\x01' # Inverse Printing ON
|
},
|
||||||
TXT_INVERT_OFF = GS + b'\x42\x00' # Inverse Printing OFF
|
'size': {
|
||||||
|
'normal': TXT_NORMAL + ESC + b'!\x00', # Normal text
|
||||||
|
'2h': TXT_NORMAL + ESC + b'!\x10', # Double height text
|
||||||
|
'2w': TXT_NORMAL + ESC + b'!\x20', # Double width text
|
||||||
|
'2x': TXT_NORMAL + ESC + b'!\x30' # Quad area text
|
||||||
|
},
|
||||||
|
'font': {
|
||||||
|
'a': ESC + b'\x4d\x00', # Font type A
|
||||||
|
'b': ESC + b'\x4d\x00' # Font type B
|
||||||
|
},
|
||||||
|
'align': {
|
||||||
|
'left': ESC + b'\x61\x00', # Left justification
|
||||||
|
'center': ESC + b'\x61\x01', # Centering
|
||||||
|
'right': ESC + b'\x61\x02' # Right justification
|
||||||
|
},
|
||||||
|
'invert': {
|
||||||
|
True: GS + b'\x42\x01', # Inverse Printing ON
|
||||||
|
False: GS + b'\x42\x00' # Inverse Printing OFF
|
||||||
|
},
|
||||||
|
'color': {
|
||||||
|
'black': ESC + b'\x72\x00', # Default Color
|
||||||
|
'red': ESC + b'\x72\x01' # Alternative Color, Usually Red
|
||||||
|
},
|
||||||
|
'flip': {
|
||||||
|
True: ESC + b'\x7b\x01', # Flip ON
|
||||||
|
False: ESC + b'\x7b\x00' # Flip OFF
|
||||||
|
},
|
||||||
|
'density': {
|
||||||
|
0: GS + b'\x7c\x00', # Printing Density -50%
|
||||||
|
1: GS + b'\x7c\x01', # Printing Density -37.5%
|
||||||
|
2: GS + b'\x7c\x02', # Printing Density -25%
|
||||||
|
3: GS + b'\x7c\x03', # Printing Density -12.5%
|
||||||
|
4: GS + b'\x7c\x04', # Printing Density 0%
|
||||||
|
5: GS + b'\x7c\x08', # Printing Density +50%
|
||||||
|
6: GS + b'\x7c\x07', # Printing Density +37.5%
|
||||||
|
7: GS + b'\x7c\x06', # Printing Density +25%
|
||||||
|
8: GS + b'\x7c\x05' # Printing Density +12.5%
|
||||||
|
},
|
||||||
|
'smooth': {
|
||||||
|
True: GS + b'\x62\x01', # Smooth ON
|
||||||
|
False: GS + b'\x62\x00' # Smooth OFF
|
||||||
|
},
|
||||||
|
'height': { # Custom text height
|
||||||
|
1: 0x00,
|
||||||
|
2: 0x01,
|
||||||
|
3: 0x02,
|
||||||
|
4: 0x03,
|
||||||
|
5: 0x04,
|
||||||
|
6: 0x05,
|
||||||
|
7: 0x06,
|
||||||
|
8: 0x07
|
||||||
|
},
|
||||||
|
'width': { # Custom text width
|
||||||
|
1: 0x00,
|
||||||
|
2: 0x10,
|
||||||
|
3: 0x20,
|
||||||
|
4: 0x30,
|
||||||
|
5: 0x40,
|
||||||
|
6: 0x50,
|
||||||
|
7: 0x60,
|
||||||
|
8: 0x70
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
# Fonts
|
# Fonts
|
||||||
SET_FONT = lambda n: ESC + b'\x4d' + n
|
SET_FONT = lambda n: ESC + b'\x4d' + n
|
||||||
TXT_FONT_A = SET_FONT(b'\x00') # Font type A
|
TXT_FONT_A = SET_FONT(b'\x00') # Font type A
|
||||||
TXT_FONT_B = SET_FONT(b'\x01') # Font type B
|
TXT_FONT_B = SET_FONT(b'\x01') # Font type B
|
||||||
|
|
||||||
# Text colors
|
|
||||||
TXT_COLOR_BLACK = ESC + b'\x72\x00' # Default Color
|
|
||||||
TXT_COLOR_RED = ESC + b'\x72\x01' # Alternative Color (Usually Red)
|
|
||||||
|
|
||||||
# Spacing
|
# Spacing
|
||||||
LINESPACING_RESET = ESC + b'2'
|
LINESPACING_RESET = ESC + b'2'
|
||||||
LINESPACING_FUNCS = {
|
LINESPACING_FUNCS = {
|
||||||
@@ -206,13 +250,6 @@ S_RASTER_2W = _PRINT_RASTER_IMG(b'\x01') # Set raster image double width
|
|||||||
S_RASTER_2H = _PRINT_RASTER_IMG(b'\x02') # Set raster image double height
|
S_RASTER_2H = _PRINT_RASTER_IMG(b'\x02') # Set raster image double height
|
||||||
S_RASTER_Q = _PRINT_RASTER_IMG(b'\x03') # Set raster image quadruple
|
S_RASTER_Q = _PRINT_RASTER_IMG(b'\x03') # Set raster image quadruple
|
||||||
|
|
||||||
# Printing Density
|
# Status Command
|
||||||
PD_N50 = GS + b'\x7c\x00' # Printing Density -50%
|
RT_STATUS_ONLINE = DLE + EOT + b'\x01';
|
||||||
PD_N37 = GS + b'\x7c\x01' # Printing Density -37.5%
|
RT_MASK_ONLINE = 8;
|
||||||
PD_N25 = GS + b'\x7c\x02' # Printing Density -25%
|
|
||||||
PD_N12 = GS + b'\x7c\x03' # Printing Density -12.5%
|
|
||||||
PD_0 = GS + b'\x7c\x04' # Printing Density 0%
|
|
||||||
PD_P50 = GS + b'\x7c\x08' # Printing Density +50%
|
|
||||||
PD_P37 = GS + b'\x7c\x07' # Printing Density +37.5%
|
|
||||||
PD_P25 = GS + b'\x7c\x06' # Printing Density +25%
|
|
||||||
PD_P12 = GS + b'\x7c\x05' # Printing Density +12.5%
|
|
||||||
|
@@ -18,22 +18,28 @@ from __future__ import unicode_literals
|
|||||||
import qrcode
|
import qrcode
|
||||||
import textwrap
|
import textwrap
|
||||||
import six
|
import six
|
||||||
|
import time
|
||||||
|
|
||||||
|
import barcode
|
||||||
|
from barcode.writer import ImageWriter
|
||||||
|
|
||||||
from .constants import ESC, GS, NUL, QR_ECLEVEL_L, QR_ECLEVEL_M, QR_ECLEVEL_H, QR_ECLEVEL_Q
|
from .constants import ESC, GS, NUL, QR_ECLEVEL_L, QR_ECLEVEL_M, QR_ECLEVEL_H, QR_ECLEVEL_Q
|
||||||
from .constants import QR_MODEL_1, QR_MODEL_2, QR_MICRO, BARCODE_TYPES, BARCODE_HEIGHT, BARCODE_WIDTH
|
from .constants import QR_MODEL_1, QR_MODEL_2, QR_MICRO, BARCODE_TYPES, BARCODE_HEIGHT, BARCODE_WIDTH
|
||||||
from .constants import TXT_ALIGN_CT, TXT_ALIGN_LT, TXT_ALIGN_RT, BARCODE_FONT_A, BARCODE_FONT_B
|
from .constants import BARCODE_FONT_A, BARCODE_FONT_B
|
||||||
from .constants import BARCODE_TXT_OFF, BARCODE_TXT_BTH, BARCODE_TXT_ABV, BARCODE_TXT_BLW
|
from .constants import BARCODE_TXT_OFF, BARCODE_TXT_BTH, BARCODE_TXT_ABV, BARCODE_TXT_BLW
|
||||||
from .constants import TXT_HEIGHT, TXT_WIDTH, TXT_SIZE, TXT_NORMAL, TXT_SMOOTH_OFF, TXT_SMOOTH_ON
|
from .constants import TXT_SIZE, TXT_NORMAL
|
||||||
from .constants import TXT_FLIP_OFF, TXT_FLIP_ON, TXT_2WIDTH, TXT_2HEIGHT, TXT_4SQUARE
|
from .constants import SET_FONT
|
||||||
from .constants import TXT_UNDERL_OFF, TXT_UNDERL_ON, TXT_BOLD_OFF, TXT_BOLD_ON, SET_FONT, TXT_UNDERL2_ON
|
from .constants import LINESPACING_FUNCS, LINESPACING_RESET
|
||||||
from .constants import TXT_INVERT_OFF, TXT_INVERT_ON, LINESPACING_FUNCS, LINESPACING_RESET
|
from .constants import LINE_DISPLAY_OPEN, LINE_DISPLAY_CLEAR, LINE_DISPLAY_CLOSE
|
||||||
from .constants import PD_0, PD_N12, PD_N25, PD_N37, PD_N50, PD_P50, PD_P37, PD_P25, PD_P12
|
|
||||||
from .constants import CD_KICK_DEC_SEQUENCE, CD_KICK_5, CD_KICK_2, PAPER_FULL_CUT, PAPER_PART_CUT
|
from .constants import CD_KICK_DEC_SEQUENCE, CD_KICK_5, CD_KICK_2, PAPER_FULL_CUT, PAPER_PART_CUT
|
||||||
from .constants import HW_RESET, HW_SELECT, HW_INIT
|
from .constants import HW_RESET, HW_SELECT, HW_INIT
|
||||||
from .constants import CTL_VT, CTL_HT, CTL_CR, CTL_FF, CTL_LF, CTL_SET_HT, PANEL_BUTTON_OFF, PANEL_BUTTON_ON
|
from .constants import CTL_VT, CTL_CR, CTL_FF, CTL_LF, CTL_SET_HT, PANEL_BUTTON_OFF, PANEL_BUTTON_ON
|
||||||
|
from .constants import TXT_STYLE
|
||||||
|
from .constants import RT_STATUS_ONLINE, RT_MASK_ONLINE
|
||||||
|
|
||||||
from .exceptions import BarcodeTypeError, BarcodeSizeError, TabPosError
|
from .exceptions import BarcodeTypeError, BarcodeSizeError, TabPosError
|
||||||
from .exceptions import CashDrawerError, SetVariableError, BarcodeCodeError
|
from .exceptions import CashDrawerError, SetVariableError, BarcodeCodeError
|
||||||
|
from .exceptions import ImageWidthError
|
||||||
|
|
||||||
from .magicencode import MagicEncode
|
from .magicencode import MagicEncode
|
||||||
|
|
||||||
@@ -73,6 +79,12 @@ class Escpos(object):
|
|||||||
"""
|
"""
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
def _read(self, msg):
|
||||||
|
""" Returns a NotImplementedError if the instance of the class doesn't override this method.
|
||||||
|
:raises 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):
|
fragment_height=960):
|
||||||
""" Print an image
|
""" Print an image
|
||||||
@@ -99,6 +111,17 @@ class Escpos(object):
|
|||||||
"""
|
"""
|
||||||
im = EscposImage(img_source)
|
im = EscposImage(img_source)
|
||||||
|
|
||||||
|
try:
|
||||||
|
max_width = int(self.profile.profile_data['media']['width']['pixels'])
|
||||||
|
if im.width > max_width:
|
||||||
|
raise ImageWidthError('{} > {}'.format(im.width, max_width))
|
||||||
|
except KeyError:
|
||||||
|
# If the printer's pixel width is not known, print anyways...
|
||||||
|
pass
|
||||||
|
except ValueError:
|
||||||
|
# If the max_width cannot be converted to an int, print anyways...
|
||||||
|
pass
|
||||||
|
|
||||||
if im.height > fragment_height:
|
if im.height > fragment_height:
|
||||||
fragments = im.split(fragment_height)
|
fragments = im.split(fragment_height)
|
||||||
for fragment in fragments:
|
for fragment in fragments:
|
||||||
@@ -188,7 +211,10 @@ 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.text('\n')
|
||||||
self.image(im)
|
self.image(im)
|
||||||
|
self.text('\n')
|
||||||
|
self.text('\n')
|
||||||
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
|
||||||
@@ -356,7 +382,7 @@ class Escpos(object):
|
|||||||
|
|
||||||
# Align Bar Code()
|
# Align Bar Code()
|
||||||
if align_ct:
|
if align_ct:
|
||||||
self._raw(TXT_ALIGN_CT)
|
self._raw(TXT_STYLE['align']['center'])
|
||||||
# Height
|
# Height
|
||||||
if 1 <= height <= 255:
|
if 1 <= height <= 255:
|
||||||
self._raw(BARCODE_HEIGHT + six.int2byte(height))
|
self._raw(BARCODE_HEIGHT + six.int2byte(height))
|
||||||
@@ -396,6 +422,31 @@ class Escpos(object):
|
|||||||
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',
|
||||||
|
module_height=5, module_width=0.2, text_distance=1):
|
||||||
|
|
||||||
|
image_writer = ImageWriter()
|
||||||
|
|
||||||
|
# Check if barcode type exists
|
||||||
|
if barcode_type not in barcode.PROVIDED_BARCODES:
|
||||||
|
raise BarcodeTypeError(
|
||||||
|
'Barcode type {} not supported by software barcode renderer'
|
||||||
|
.format(barcode_type))
|
||||||
|
|
||||||
|
# Render the barcode to a fake file
|
||||||
|
barcode_class = barcode.get_barcode_class(barcode_type)
|
||||||
|
my_code = barcode_class(data, writer=image_writer)
|
||||||
|
|
||||||
|
my_code.write("/dev/null", {
|
||||||
|
'module_height': module_height,
|
||||||
|
'module_width': module_width,
|
||||||
|
'text_distance': text_distance
|
||||||
|
})
|
||||||
|
|
||||||
|
# Retrieve the Pillow image and print it
|
||||||
|
image = my_code.writer._image
|
||||||
|
self.image(image, impl=impl)
|
||||||
|
|
||||||
def text(self, txt):
|
def text(self, txt):
|
||||||
""" Print alpha-numeric text
|
""" Print alpha-numeric text
|
||||||
|
|
||||||
@@ -414,126 +465,85 @@ class Escpos(object):
|
|||||||
Text has to be encoded in unicode.
|
Text has to be encoded in unicode.
|
||||||
|
|
||||||
:param txt: text to be printed
|
:param txt: text to be printed
|
||||||
:param font: font to be used, can be :code:`a` or :code`b`
|
:param font: font to be used, can be :code:`a` or :code:`b`
|
||||||
:param columns: amount of columns
|
:param columns: amount of columns
|
||||||
:return: None
|
:return: None
|
||||||
"""
|
"""
|
||||||
col_count = self.profile.get_columns(font) if columns is None else columns
|
col_count = self.profile.get_columns(font) if columns is None else columns
|
||||||
self.text(textwrap.fill(txt, col_count))
|
self.text(textwrap.fill(txt, col_count))
|
||||||
|
|
||||||
def set(self, align='left', font='a', text_type='normal', width=1,
|
def set(self, align='left', font='a', bold=False, underline=0, width=1,
|
||||||
height=1, density=9, invert=False, smooth=False, flip=False):
|
height=1, density=9, invert=False, smooth=False, flip=False,
|
||||||
|
double_width=False, double_height=False, custom_size=False):
|
||||||
""" Set text properties by sending them to the printer
|
""" Set text properties by sending them to the printer
|
||||||
|
|
||||||
:param align: horizontal position for text, possible values are:
|
:param align: horizontal position for text, possible values are:
|
||||||
|
|
||||||
* CENTER
|
* 'center'
|
||||||
* LEFT
|
* 'left'
|
||||||
* RIGHT
|
* 'right'
|
||||||
|
|
||||||
*default*: LEFT
|
*default*: 'left'
|
||||||
|
|
||||||
:param font: font given as an index, a name, or one of the
|
:param font: font given as an index, a name, or one of the
|
||||||
special values 'a' or 'b', refering to fonts 0 and 1.
|
special values 'a' or 'b', referring to fonts 0 and 1.
|
||||||
:param text_type: text type, possible values are:
|
:param bold: text in bold, *default*: False
|
||||||
|
:param underline: underline mode for text, decimal range 0-2, *default*: 0
|
||||||
* B for bold
|
:param double_height: doubles the height of the text
|
||||||
* U for underlined
|
:param double_width: doubles the width of the text
|
||||||
* U2 for underlined, version 2
|
:param custom_size: uses custom size specified by width and height
|
||||||
* BU for bold and underlined
|
parameters. Cannot be used with double_width or double_height.
|
||||||
* BU2 for bold and underlined, version 2
|
:param width: text width multiplier when custom_size is used, decimal range 1-8, *default*: 1
|
||||||
* NORMAL for normal text
|
:param height: text height multiplier when custom_size is used, decimal range 1-8, *default*: 1
|
||||||
|
|
||||||
*default*: NORMAL
|
|
||||||
:param width: text width multiplier, decimal range 1-8, *default*: 1
|
|
||||||
:param height: text height multiplier, decimal range 1-8, *default*: 1
|
|
||||||
:param density: print density, value from 0-8, if something else is supplied the density remains unchanged
|
:param density: print density, value from 0-8, if something else is supplied the density remains unchanged
|
||||||
:param invert: True enables white on black printing, *default*: False
|
:param invert: True enables white on black printing, *default*: False
|
||||||
:param smooth: True enables text smoothing. Effective on 4x4 size text and larger, *default*: False
|
:param smooth: True enables text smoothing. Effective on 4x4 size text and larger, *default*: False
|
||||||
:param flip: True enables upside-down printing, *default*: False
|
:param flip: True enables upside-down printing, *default*: False
|
||||||
:type invert: bool
|
|
||||||
"""
|
|
||||||
# Width
|
|
||||||
if height == 2 and width == 2:
|
|
||||||
self._raw(TXT_NORMAL)
|
|
||||||
self._raw(TXT_4SQUARE)
|
|
||||||
elif height == 2 and width == 1:
|
|
||||||
self._raw(TXT_NORMAL)
|
|
||||||
self._raw(TXT_2HEIGHT)
|
|
||||||
elif width == 2 and height == 1:
|
|
||||||
self._raw(TXT_NORMAL)
|
|
||||||
self._raw(TXT_2WIDTH)
|
|
||||||
elif width == 1 and height == 1:
|
|
||||||
self._raw(TXT_NORMAL)
|
|
||||||
elif 1 <= width <= 8 and 1 <= height <= 8 and isinstance(width, int) and isinstance(height, int):
|
|
||||||
self._raw(TXT_SIZE + six.int2byte(TXT_WIDTH[width] + TXT_HEIGHT[height]))
|
|
||||||
else:
|
|
||||||
raise SetVariableError()
|
|
||||||
# Upside down
|
|
||||||
if flip:
|
|
||||||
self._raw(TXT_FLIP_ON)
|
|
||||||
else:
|
|
||||||
self._raw(TXT_FLIP_OFF)
|
|
||||||
# Smoothing
|
|
||||||
if smooth:
|
|
||||||
self._raw(TXT_SMOOTH_ON)
|
|
||||||
else:
|
|
||||||
self._raw(TXT_SMOOTH_OFF)
|
|
||||||
# Type
|
|
||||||
if text_type.upper() == "B":
|
|
||||||
self._raw(TXT_BOLD_ON)
|
|
||||||
self._raw(TXT_UNDERL_OFF)
|
|
||||||
elif text_type.upper() == "U":
|
|
||||||
self._raw(TXT_BOLD_OFF)
|
|
||||||
self._raw(TXT_UNDERL_ON)
|
|
||||||
elif text_type.upper() == "U2":
|
|
||||||
self._raw(TXT_BOLD_OFF)
|
|
||||||
self._raw(TXT_UNDERL2_ON)
|
|
||||||
elif text_type.upper() == "BU":
|
|
||||||
self._raw(TXT_BOLD_ON)
|
|
||||||
self._raw(TXT_UNDERL_ON)
|
|
||||||
elif text_type.upper() == "BU2":
|
|
||||||
self._raw(TXT_BOLD_ON)
|
|
||||||
self._raw(TXT_UNDERL2_ON)
|
|
||||||
elif text_type.upper() == "NORMAL":
|
|
||||||
self._raw(TXT_BOLD_OFF)
|
|
||||||
self._raw(TXT_UNDERL_OFF)
|
|
||||||
# Font
|
|
||||||
self._raw(SET_FONT(six.int2byte(self.profile.get_font(font))))
|
|
||||||
|
|
||||||
# Align
|
:type font: str
|
||||||
if align.upper() == "CENTER":
|
:type invert: bool
|
||||||
self._raw(TXT_ALIGN_CT)
|
:type bold: bool
|
||||||
elif align.upper() == "RIGHT":
|
:type underline: bool
|
||||||
self._raw(TXT_ALIGN_RT)
|
:type smooth: bool
|
||||||
elif align.upper() == "LEFT":
|
:type flip: bool
|
||||||
self._raw(TXT_ALIGN_LT)
|
:type custom_size: bool
|
||||||
# Density
|
:type double_width: bool
|
||||||
if density == 0:
|
:type double_height: bool
|
||||||
self._raw(PD_N50)
|
:type align: str
|
||||||
elif density == 1:
|
:type width: int
|
||||||
self._raw(PD_N37)
|
:type height: int
|
||||||
elif density == 2:
|
:type density: int
|
||||||
self._raw(PD_N25)
|
"""
|
||||||
elif density == 3:
|
|
||||||
self._raw(PD_N12)
|
if custom_size:
|
||||||
elif density == 4:
|
if 1 <= width <= 8 and 1 <= height <= 8 and isinstance(width, int) and\
|
||||||
self._raw(PD_0)
|
isinstance(height, int):
|
||||||
elif density == 5:
|
size_byte = TXT_STYLE['width'][width] + TXT_STYLE['height'][height]
|
||||||
self._raw(PD_P12)
|
self._raw(TXT_SIZE + six.int2byte(size_byte))
|
||||||
elif density == 6:
|
else:
|
||||||
self._raw(PD_P25)
|
raise SetVariableError()
|
||||||
elif density == 7:
|
|
||||||
self._raw(PD_P37)
|
|
||||||
elif density == 8:
|
|
||||||
self._raw(PD_P50)
|
|
||||||
else: # DEFAULT: DOES NOTHING
|
|
||||||
pass
|
|
||||||
# Invert Printing
|
|
||||||
if invert:
|
|
||||||
self._raw(TXT_INVERT_ON)
|
|
||||||
else:
|
else:
|
||||||
self._raw(TXT_INVERT_OFF)
|
self._raw(TXT_NORMAL)
|
||||||
|
if double_width and double_height:
|
||||||
|
self._raw(TXT_STYLE['size']['2x'])
|
||||||
|
elif double_width:
|
||||||
|
self._raw(TXT_STYLE['size']['2w'])
|
||||||
|
elif double_height:
|
||||||
|
self._raw(TXT_STYLE['size']['2h'])
|
||||||
|
else:
|
||||||
|
self._raw(TXT_STYLE['size']['normal'])
|
||||||
|
|
||||||
|
self._raw(TXT_STYLE['flip'][flip])
|
||||||
|
self._raw(TXT_STYLE['smooth'][smooth])
|
||||||
|
self._raw(TXT_STYLE['bold'][bold])
|
||||||
|
self._raw(TXT_STYLE['underline'][underline])
|
||||||
|
self._raw(SET_FONT(six.int2byte(self.profile.get_font(font))))
|
||||||
|
self._raw(TXT_STYLE['align'][align])
|
||||||
|
|
||||||
|
if density != 9:
|
||||||
|
self._raw(TXT_STYLE['density'][density])
|
||||||
|
|
||||||
|
self._raw(TXT_STYLE['invert'][invert])
|
||||||
|
|
||||||
def line_spacing(self, spacing=None, divisor=180):
|
def line_spacing(self, spacing=None, divisor=180):
|
||||||
""" Set line character spacing.
|
""" Set line character spacing.
|
||||||
@@ -564,7 +574,7 @@ class Escpos(object):
|
|||||||
|
|
||||||
self._raw(LINESPACING_FUNCS[divisor] + six.int2byte(spacing))
|
self._raw(LINESPACING_FUNCS[divisor] + six.int2byte(spacing))
|
||||||
|
|
||||||
def cut(self, mode='FULL'):
|
def cut(self, mode='FULL', feed=True):
|
||||||
""" Cut paper.
|
""" Cut paper.
|
||||||
|
|
||||||
Without any arguments the paper will be cut completely. With 'mode=PART' a partial cut will
|
Without any arguments the paper will be cut completely. With 'mode=PART' a partial cut will
|
||||||
@@ -574,8 +584,14 @@ class Escpos(object):
|
|||||||
.. todo:: Check this function on TM-T88II.
|
.. todo:: Check this function on TM-T88II.
|
||||||
|
|
||||||
:param mode: set to 'PART' for a partial cut. default: 'FULL'
|
:param mode: set to 'PART' for a partial cut. default: 'FULL'
|
||||||
|
:param feed: print and feed before cutting. default: true
|
||||||
:raises ValueError: if mode not in ('FULL', 'PART')
|
:raises ValueError: if mode not in ('FULL', 'PART')
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
if not feed:
|
||||||
|
self._raw(GS + b'V' + six.int2byte(66) + b'\x00')
|
||||||
|
return
|
||||||
|
|
||||||
self.print_and_feed(6)
|
self.print_and_feed(6)
|
||||||
|
|
||||||
mode = mode.upper()
|
mode = mode.upper()
|
||||||
@@ -612,6 +628,41 @@ class Escpos(object):
|
|||||||
except:
|
except:
|
||||||
raise CashDrawerError()
|
raise CashDrawerError()
|
||||||
|
|
||||||
|
def linedisplay_select(self, select_display=False):
|
||||||
|
""" Selects the line display or the printer
|
||||||
|
|
||||||
|
This method is used for line displays that are daisy-chained between your computer and printer.
|
||||||
|
If you set `select_display` to true, only the display is selected and if you set it to false,
|
||||||
|
only the printer is selected.
|
||||||
|
|
||||||
|
:param select_display: whether the display should be selected or the printer
|
||||||
|
:type select_display: bool
|
||||||
|
"""
|
||||||
|
if select_display:
|
||||||
|
self._raw(LINE_DISPLAY_OPEN)
|
||||||
|
else:
|
||||||
|
self._raw(LINE_DISPLAY_CLOSE)
|
||||||
|
|
||||||
|
def linedisplay_clear(self):
|
||||||
|
""" Clears the line display and resets the cursor
|
||||||
|
|
||||||
|
This method is used for line displays that are daisy-chained between your computer and printer.
|
||||||
|
"""
|
||||||
|
self._raw(LINE_DISPLAY_CLEAR)
|
||||||
|
|
||||||
|
def linedisplay(self, text):
|
||||||
|
"""
|
||||||
|
Display text on a line display connected to your printer
|
||||||
|
|
||||||
|
You should connect a line display to your printer. You can do this by daisy-chaining
|
||||||
|
the display between your computer and printer.
|
||||||
|
:param text: Text to display
|
||||||
|
"""
|
||||||
|
self.linedisplay_select(select_display=True)
|
||||||
|
self.linedisplay_clear()
|
||||||
|
self.text(text)
|
||||||
|
self.linedisplay_select(select_display=False)
|
||||||
|
|
||||||
def hw(self, hw):
|
def hw(self, hw):
|
||||||
""" Hardware operations
|
""" Hardware operations
|
||||||
|
|
||||||
@@ -644,7 +695,7 @@ class Escpos(object):
|
|||||||
else:
|
else:
|
||||||
raise ValueError("n must be betwen 0 and 255")
|
raise ValueError("n must be betwen 0 and 255")
|
||||||
|
|
||||||
def control(self, ctl, pos=4):
|
def control(self, ctl, count=5, tab_size=8):
|
||||||
""" Feed control sequences
|
""" Feed control sequences
|
||||||
|
|
||||||
:param ctl: string for the following control sequences:
|
:param ctl: string for the following control sequences:
|
||||||
@@ -655,7 +706,8 @@ class Escpos(object):
|
|||||||
* HT *for Horizontal Tab*
|
* HT *for Horizontal Tab*
|
||||||
* VT *for Vertical Tab*
|
* VT *for Vertical Tab*
|
||||||
|
|
||||||
:param pos: integer between 1 and 16, controls the horizontal tab position
|
:param count: integer between 1 and 32, controls the horizontal tab count. Defaults to 5.
|
||||||
|
:param tab_size: integer between 1 and 255, controls the horizontal tab size in characters. Defaults to 8
|
||||||
:raises: :py:exc:`~escpos.exceptions.TabPosError`
|
:raises: :py:exc:`~escpos.exceptions.TabPosError`
|
||||||
"""
|
"""
|
||||||
# Set position
|
# Set position
|
||||||
@@ -666,13 +718,16 @@ class Escpos(object):
|
|||||||
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 (1 <= pos <= 16):
|
if not (0 <= count <= 32 and
|
||||||
|
1 <= tab_size <= 255 and
|
||||||
|
count * tab_size < 256):
|
||||||
raise TabPosError()
|
raise TabPosError()
|
||||||
else:
|
else:
|
||||||
# Set tab positions
|
# Set tab positions
|
||||||
self._raw(CTL_SET_HT + six.int2byte(pos))
|
self._raw(CTL_SET_HT)
|
||||||
|
for iterator in range(1, count):
|
||||||
self._raw(CTL_HT)
|
self._raw(six.int2byte(iterator * tab_size))
|
||||||
|
self._raw(NUL)
|
||||||
elif ctl.upper() == "VT":
|
elif ctl.upper() == "VT":
|
||||||
self._raw(CTL_VT)
|
self._raw(CTL_VT)
|
||||||
|
|
||||||
@@ -699,6 +754,20 @@ class Escpos(object):
|
|||||||
else:
|
else:
|
||||||
self._raw(PANEL_BUTTON_OFF)
|
self._raw(PANEL_BUTTON_OFF)
|
||||||
|
|
||||||
|
def query_status(self):
|
||||||
|
""" Queries the printer for its status, and returns an array of integers containing it.
|
||||||
|
:rtype: array(integer)"""
|
||||||
|
self._raw(RT_STATUS_ONLINE)
|
||||||
|
time.sleep(1)
|
||||||
|
status = self._read()
|
||||||
|
return status or [RT_MASK_ONLINE]
|
||||||
|
|
||||||
|
def is_online(self):
|
||||||
|
""" Queries the printer its online status.
|
||||||
|
When online, returns True; False otherwise.
|
||||||
|
:rtype: bool: True if online, False if offline."""
|
||||||
|
return not (self.query_status()[0] & RT_MASK_ONLINE)
|
||||||
|
|
||||||
|
|
||||||
class EscposIO(object):
|
class EscposIO(object):
|
||||||
"""ESC/POS Printer IO object
|
"""ESC/POS Printer IO object
|
||||||
|
@@ -8,6 +8,7 @@ Result/Exit codes:
|
|||||||
- `20` = Barcode size values are out of range :py:exc:`~escpos.exceptions.BarcodeSizeError`
|
- `20` = Barcode size values are out of range :py:exc:`~escpos.exceptions.BarcodeSizeError`
|
||||||
- `30` = Barcode text not supplied :py:exc:`~escpos.exceptions.BarcodeCodeError`
|
- `30` = Barcode text not supplied :py:exc:`~escpos.exceptions.BarcodeCodeError`
|
||||||
- `40` = Image height is too large :py:exc:`~escpos.exceptions.ImageSizeError`
|
- `40` = Image height is too large :py:exc:`~escpos.exceptions.ImageSizeError`
|
||||||
|
- `41` = Image width is too large :py:exc:`~escpos.exceptions.ImageWidthError`
|
||||||
- `50` = No string supplied to be printed :py:exc:`~escpos.exceptions.TextError`
|
- `50` = No string supplied to be printed :py:exc:`~escpos.exceptions.TextError`
|
||||||
- `60` = Invalid pin to send Cash Drawer pulse :py:exc:`~escpos.exceptions.CashDrawerError`
|
- `60` = Invalid pin to send Cash Drawer pulse :py:exc:`~escpos.exceptions.CashDrawerError`
|
||||||
- `70` = Invalid number of tab positions :py:exc:`~escpos.exceptions.TabPosError`
|
- `70` = Invalid number of tab positions :py:exc:`~escpos.exceptions.TabPosError`
|
||||||
@@ -104,6 +105,20 @@ class ImageSizeError(Error):
|
|||||||
return "Image height is longer than 255px and can't be printed ({msg})".format(msg=self.msg)
|
return "Image height is longer than 255px and can't be printed ({msg})".format(msg=self.msg)
|
||||||
|
|
||||||
|
|
||||||
|
class ImageWidthError(Error):
|
||||||
|
""" Image width is too large.
|
||||||
|
|
||||||
|
The return code for this exception is `41`.
|
||||||
|
"""
|
||||||
|
def __init__(self, msg=""):
|
||||||
|
Error.__init__(self, msg)
|
||||||
|
self.msg = msg
|
||||||
|
self.resultcode = 41
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return "Image width is too large ({msg})".format(msg=self.msg)
|
||||||
|
|
||||||
|
|
||||||
class TextError(Error):
|
class TextError(Error):
|
||||||
""" Text string must be supplied to the `text()` method.
|
""" Text string must be supplied to the `text()` method.
|
||||||
|
|
||||||
@@ -135,7 +150,8 @@ class CashDrawerError(Error):
|
|||||||
|
|
||||||
|
|
||||||
class TabPosError(Error):
|
class TabPosError(Error):
|
||||||
""" Valid tab positions must be in the range 0 to 16.
|
""" Valid tab positions must be set by using from 1 to 32 tabs, and between 1 and 255 tab size values.
|
||||||
|
Both values multiplied must not exceed 255, since it is the maximum tab value.
|
||||||
|
|
||||||
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`.
|
||||||
|
@@ -84,6 +84,10 @@ class Usb(Escpos):
|
|||||||
"""
|
"""
|
||||||
self.device.write(self.out_ep, msg, self.timeout)
|
self.device.write(self.out_ep, msg, self.timeout)
|
||||||
|
|
||||||
|
def _read(self):
|
||||||
|
""" Reads a data buffer and returns it to the caller. """
|
||||||
|
return self.device.read(self.in_ep, 16)
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
""" Release USB interface """
|
""" Release USB interface """
|
||||||
if self.device:
|
if self.device:
|
||||||
@@ -131,6 +135,8 @@ class Serial(Escpos):
|
|||||||
|
|
||||||
def open(self):
|
def open(self):
|
||||||
""" Setup serial port and set is as escpos device """
|
""" Setup serial port and set is as escpos device """
|
||||||
|
if self.device is not None and self.device.is_open:
|
||||||
|
self.close()
|
||||||
self.device = serial.Serial(port=self.devfile, baudrate=self.baudrate,
|
self.device = serial.Serial(port=self.devfile, baudrate=self.baudrate,
|
||||||
bytesize=self.bytesize, parity=self.parity,
|
bytesize=self.bytesize, parity=self.parity,
|
||||||
stopbits=self.stopbits, timeout=self.timeout,
|
stopbits=self.stopbits, timeout=self.timeout,
|
||||||
@@ -151,7 +157,7 @@ class Serial(Escpos):
|
|||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
""" Close Serial interface """
|
""" Close Serial interface """
|
||||||
if self.device is not None:
|
if self.device is not None and self.device.is_open:
|
||||||
self.device.flush()
|
self.device.flush()
|
||||||
self.device.close()
|
self.device.close()
|
||||||
|
|
||||||
|
17
test/test_function_cut.py
Normal file
17
test/test_function_cut.py
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
from __future__ import absolute_import
|
||||||
|
from __future__ import division
|
||||||
|
from __future__ import print_function
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
import six
|
||||||
|
|
||||||
|
import escpos.printer as printer
|
||||||
|
from escpos.constants import GS
|
||||||
|
|
||||||
|
|
||||||
|
def test_cut_without_feed():
|
||||||
|
"""Test cut without feeding paper"""
|
||||||
|
instance = printer.Dummy()
|
||||||
|
instance.cut(feed=False)
|
||||||
|
expected = GS + b'V' + six.int2byte(66) + b'\x00'
|
||||||
|
assert(instance.output == expected)
|
@@ -12,9 +12,13 @@ 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 escpos.printer as printer
|
import pytest
|
||||||
|
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
|
|
||||||
|
import escpos.printer as printer
|
||||||
|
from escpos.exceptions import ImageWidthError
|
||||||
|
|
||||||
|
|
||||||
# Raster format print
|
# Raster format print
|
||||||
def test_bit_image_black():
|
def test_bit_image_black():
|
||||||
@@ -139,3 +143,22 @@ def test_large_graphics():
|
|||||||
instance = printer.Dummy()
|
instance = printer.Dummy()
|
||||||
instance.image('test/resources/black_white.png', impl="bitImageRaster", fragment_height=1)
|
instance.image('test/resources/black_white.png', impl="bitImageRaster", fragment_height=1)
|
||||||
assert(instance.output == b'\x1dv0\x00\x01\x00\x01\x00\xc0\x1dv0\x00\x01\x00\x01\x00\x00')
|
assert(instance.output == b'\x1dv0\x00\x01\x00\x01\x00\xc0\x1dv0\x00\x01\x00\x01\x00\x00')
|
||||||
|
|
||||||
|
|
||||||
|
def test_width_too_large():
|
||||||
|
"""
|
||||||
|
Test printing an image that is too large in width.
|
||||||
|
"""
|
||||||
|
instance = printer.Dummy()
|
||||||
|
instance.profile.profile_data = {
|
||||||
|
'media': {
|
||||||
|
'width': {
|
||||||
|
'pixels': 384
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
with pytest.raises(ImageWidthError):
|
||||||
|
instance.image(Image.new("RGB", (385, 200)))
|
||||||
|
|
||||||
|
instance.image(Image.new("RGB", (384, 200)))
|
35
test/test_function_linedisplay.py
Normal file
35
test/test_function_linedisplay.py
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
"""tests for line display
|
||||||
|
|
||||||
|
:author: `Patrick Kanzler <patrick.kanzler@fablab.fau.de>`_
|
||||||
|
:organization: `python-escpos <https://github.com/python-escpos>`_
|
||||||
|
:copyright: Copyright (c) 2017 `python-escpos <https://github.com/python-escpos>`_
|
||||||
|
:license: MIT
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import absolute_import
|
||||||
|
from __future__ import division
|
||||||
|
from __future__ import print_function
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
import escpos.printer as printer
|
||||||
|
|
||||||
|
|
||||||
|
def test_function_linedisplay_select_on():
|
||||||
|
"""test the linedisplay_select function (activate)"""
|
||||||
|
instance = printer.Dummy()
|
||||||
|
instance.linedisplay_select(select_display=True)
|
||||||
|
assert(instance.output == b'\x1B\x3D\x02')
|
||||||
|
|
||||||
|
def test_function_linedisplay_select_off():
|
||||||
|
"""test the linedisplay_select function (deactivate)"""
|
||||||
|
instance = printer.Dummy()
|
||||||
|
instance.linedisplay_select(select_display=False)
|
||||||
|
assert(instance.output == b'\x1B\x3D\x01')
|
||||||
|
|
||||||
|
def test_function_linedisplay_clear():
|
||||||
|
"""test the linedisplay_clear function"""
|
||||||
|
instance = printer.Dummy()
|
||||||
|
instance.linedisplay_clear()
|
||||||
|
assert(instance.output == b'\x1B\x40')
|
||||||
|
|
@@ -12,43 +12,18 @@ 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
|
|
||||||
|
|
||||||
import escpos.printer as printer
|
import escpos.printer as printer
|
||||||
import os
|
|
||||||
|
|
||||||
devfile = 'testfile'
|
|
||||||
|
|
||||||
|
|
||||||
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_panel_button_on():
|
def test_function_panel_button_on():
|
||||||
"""test the panel button function (enabling) by comparing output"""
|
"""test the panel button function (enabling) by comparing output"""
|
||||||
instance = printer.File(devfile=devfile)
|
instance = printer.Dummy()
|
||||||
instance.panel_buttons()
|
instance.panel_buttons()
|
||||||
instance.flush()
|
assert(instance.output == b'\x1B\x63\x35\x00')
|
||||||
with open(devfile, "rb") as f:
|
|
||||||
assert(f.read() == b'\x1B\x63\x35\x00')
|
|
||||||
|
|
||||||
|
|
||||||
@with_setup(setup_testfile, teardown_testfile)
|
|
||||||
def test_function_panel_button_off():
|
def test_function_panel_button_off():
|
||||||
"""test the panel button function (disabling) by comparing output"""
|
"""test the panel button function (disabling) by comparing output"""
|
||||||
instance = printer.File(devfile=devfile)
|
instance = printer.Dummy()
|
||||||
instance.panel_buttons(False)
|
instance.panel_buttons(False)
|
||||||
instance.flush()
|
assert(instance.output == b'\x1B\x63\x35\x01')
|
||||||
with open(devfile, "rb") as f:
|
|
||||||
assert(f.read() == b'\x1B\x63\x35\x01')
|
|
||||||
|
@@ -86,9 +86,11 @@ def test_image():
|
|||||||
instance = printer.Dummy()
|
instance = printer.Dummy()
|
||||||
instance.qr("1", native=False, size=1)
|
instance.qr("1", native=False, size=1)
|
||||||
print(instance.output)
|
print(instance.output)
|
||||||
expected = b'\x1dv0\x00\x03\x00\x17\x00\x00\x00\x00\x7f]\xfcA\x19\x04]it]et' \
|
expected = b'\x1bt\x00\n' \
|
||||||
|
b'\x1dv0\x00\x03\x00\x17\x00\x00\x00\x00\x7f]\xfcA\x19\x04]it]et' \
|
||||||
b']ItA=\x04\x7fU\xfc\x00\x0c\x00y~t4\x7f =\xa84j\xd9\xf0\x05\xd4\x90\x00' \
|
b']ItA=\x04\x7fU\xfc\x00\x0c\x00y~t4\x7f =\xa84j\xd9\xf0\x05\xd4\x90\x00' \
|
||||||
b'i(\x7f<\xa8A \xd8]\'\xc4]y\xf8]E\x80Ar\x94\x7fR@\x00\x00\x00'
|
b'i(\x7f<\xa8A \xd8]\'\xc4]y\xf8]E\x80Ar\x94\x7fR@\x00\x00\x00' \
|
||||||
|
b'\n\n'
|
||||||
assert(instance.output == expected)
|
assert(instance.output == expected)
|
||||||
|
|
||||||
|
|
||||||
|
280
test/test_function_set.py
Normal file
280
test/test_function_set.py
Normal file
@@ -0,0 +1,280 @@
|
|||||||
|
from __future__ import absolute_import
|
||||||
|
from __future__ import division
|
||||||
|
from __future__ import print_function
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
import six
|
||||||
|
|
||||||
|
import escpos.printer as printer
|
||||||
|
from escpos.constants import TXT_NORMAL, TXT_STYLE, SET_FONT
|
||||||
|
from escpos.constants import TXT_SIZE
|
||||||
|
|
||||||
|
|
||||||
|
# Default test, please copy and paste this block to test set method calls
|
||||||
|
|
||||||
|
def test_default_values():
|
||||||
|
instance = printer.Dummy()
|
||||||
|
instance.set()
|
||||||
|
|
||||||
|
expected_sequence = (
|
||||||
|
TXT_NORMAL, TXT_STYLE['size']['normal'], # Normal text size
|
||||||
|
TXT_STYLE['flip'][False], # Flip OFF
|
||||||
|
TXT_STYLE['smooth'][False], # Smooth OFF
|
||||||
|
TXT_STYLE['bold'][False], # Bold OFF
|
||||||
|
TXT_STYLE['underline'][0], # Underline OFF
|
||||||
|
SET_FONT(b'\x00'), # Default font
|
||||||
|
TXT_STYLE['align']['left'], # Align left
|
||||||
|
TXT_STYLE['invert'][False] # Inverted OFF
|
||||||
|
)
|
||||||
|
|
||||||
|
assert(instance.output == b''.join(expected_sequence))
|
||||||
|
|
||||||
|
# Size tests
|
||||||
|
|
||||||
|
def test_set_size_2h():
|
||||||
|
instance = printer.Dummy()
|
||||||
|
instance.set(double_height=True)
|
||||||
|
|
||||||
|
expected_sequence = (
|
||||||
|
TXT_NORMAL, TXT_STYLE['size']['2h'], # Double height text size
|
||||||
|
TXT_STYLE['flip'][False], # Flip OFF
|
||||||
|
TXT_STYLE['smooth'][False], # Smooth OFF
|
||||||
|
TXT_STYLE['bold'][False], # Bold OFF
|
||||||
|
TXT_STYLE['underline'][0], # Underline OFF
|
||||||
|
SET_FONT(b'\x00'), # Default font
|
||||||
|
TXT_STYLE['align']['left'], # Align left
|
||||||
|
TXT_STYLE['invert'][False] # Inverted OFF
|
||||||
|
)
|
||||||
|
|
||||||
|
assert (instance.output == b''.join(expected_sequence))
|
||||||
|
|
||||||
|
|
||||||
|
def test_set_size_2w():
|
||||||
|
instance = printer.Dummy()
|
||||||
|
instance.set(double_width=True)
|
||||||
|
|
||||||
|
expected_sequence = (
|
||||||
|
TXT_NORMAL, TXT_STYLE['size']['2w'], # Double width text size
|
||||||
|
TXT_STYLE['flip'][False], # Flip OFF
|
||||||
|
TXT_STYLE['smooth'][False], # Smooth OFF
|
||||||
|
TXT_STYLE['bold'][False], # Bold OFF
|
||||||
|
TXT_STYLE['underline'][0], # Underline OFF
|
||||||
|
SET_FONT(b'\x00'), # Default font
|
||||||
|
TXT_STYLE['align']['left'], # Align left
|
||||||
|
TXT_STYLE['invert'][False] # Inverted OFF
|
||||||
|
)
|
||||||
|
|
||||||
|
assert (instance.output == b''.join(expected_sequence))
|
||||||
|
|
||||||
|
|
||||||
|
def test_set_size_2x():
|
||||||
|
instance = printer.Dummy()
|
||||||
|
instance.set(double_height=True, double_width=True)
|
||||||
|
|
||||||
|
expected_sequence = (
|
||||||
|
TXT_NORMAL, TXT_STYLE['size']['2x'], # Double text size
|
||||||
|
TXT_STYLE['flip'][False], # Flip OFF
|
||||||
|
TXT_STYLE['smooth'][False], # Smooth OFF
|
||||||
|
TXT_STYLE['bold'][False], # Bold OFF
|
||||||
|
TXT_STYLE['underline'][0], # Underline OFF
|
||||||
|
SET_FONT(b'\x00'), # Default font
|
||||||
|
TXT_STYLE['align']['left'], # Align left
|
||||||
|
TXT_STYLE['invert'][False] # Inverted OFF
|
||||||
|
)
|
||||||
|
|
||||||
|
assert (instance.output == b''.join(expected_sequence))
|
||||||
|
|
||||||
|
|
||||||
|
def test_set_size_custom():
|
||||||
|
instance = printer.Dummy()
|
||||||
|
instance.set(custom_size=True, width=8, height=7)
|
||||||
|
|
||||||
|
expected_sequence = (
|
||||||
|
TXT_SIZE, # Custom text size, no normal reset
|
||||||
|
six.int2byte(TXT_STYLE['width'][8] + TXT_STYLE['height'][7]),
|
||||||
|
TXT_STYLE['flip'][False], # Flip OFF
|
||||||
|
TXT_STYLE['smooth'][False], # Smooth OFF
|
||||||
|
TXT_STYLE['bold'][False], # Bold OFF
|
||||||
|
TXT_STYLE['underline'][0], # Underline OFF
|
||||||
|
SET_FONT(b'\x00'), # Default font
|
||||||
|
TXT_STYLE['align']['left'], # Align left
|
||||||
|
TXT_STYLE['invert'][False] # Inverted OFF
|
||||||
|
)
|
||||||
|
|
||||||
|
assert (instance.output == b''.join(expected_sequence))
|
||||||
|
|
||||||
|
# Flip
|
||||||
|
|
||||||
|
def test_set_flip():
|
||||||
|
instance = printer.Dummy()
|
||||||
|
instance.set(flip=True)
|
||||||
|
|
||||||
|
expected_sequence = (
|
||||||
|
TXT_NORMAL, TXT_STYLE['size']['normal'], # Normal text size
|
||||||
|
TXT_STYLE['flip'][True], # Flip ON
|
||||||
|
TXT_STYLE['smooth'][False], # Smooth OFF
|
||||||
|
TXT_STYLE['bold'][False], # Bold OFF
|
||||||
|
TXT_STYLE['underline'][0], # Underline OFF
|
||||||
|
SET_FONT(b'\x00'), # Default font
|
||||||
|
TXT_STYLE['align']['left'], # Align left
|
||||||
|
TXT_STYLE['invert'][False] # Inverted OFF
|
||||||
|
)
|
||||||
|
|
||||||
|
assert (instance.output == b''.join(expected_sequence))
|
||||||
|
|
||||||
|
# Smooth
|
||||||
|
|
||||||
|
def test_smooth():
|
||||||
|
instance = printer.Dummy()
|
||||||
|
instance.set(smooth=True)
|
||||||
|
|
||||||
|
expected_sequence = (
|
||||||
|
TXT_NORMAL, TXT_STYLE['size']['normal'], # Normal text size
|
||||||
|
TXT_STYLE['flip'][False], # Flip OFF
|
||||||
|
TXT_STYLE['smooth'][True], # Smooth ON
|
||||||
|
TXT_STYLE['bold'][False], # Bold OFF
|
||||||
|
TXT_STYLE['underline'][0], # Underline OFF
|
||||||
|
SET_FONT(b'\x00'), # Default font
|
||||||
|
TXT_STYLE['align']['left'], # Align left
|
||||||
|
TXT_STYLE['invert'][False] # Inverted OFF
|
||||||
|
)
|
||||||
|
|
||||||
|
assert(instance.output == b''.join(expected_sequence))
|
||||||
|
|
||||||
|
|
||||||
|
# Type
|
||||||
|
|
||||||
|
|
||||||
|
def test_set_bold():
|
||||||
|
instance = printer.Dummy()
|
||||||
|
instance.set(bold=True)
|
||||||
|
|
||||||
|
expected_sequence = (
|
||||||
|
TXT_NORMAL, TXT_STYLE['size']['normal'], # Normal text size
|
||||||
|
TXT_STYLE['flip'][False], # Flip OFF
|
||||||
|
TXT_STYLE['smooth'][False], # Smooth OFF
|
||||||
|
TXT_STYLE['bold'][True], # Bold ON
|
||||||
|
TXT_STYLE['underline'][0], # Underline OFF
|
||||||
|
SET_FONT(b'\x00'), # Default font
|
||||||
|
TXT_STYLE['align']['left'], # Align left
|
||||||
|
TXT_STYLE['invert'][False] # Inverted OFF
|
||||||
|
)
|
||||||
|
|
||||||
|
assert (instance.output == b''.join(expected_sequence))
|
||||||
|
|
||||||
|
|
||||||
|
def test_set_underline():
|
||||||
|
instance = printer.Dummy()
|
||||||
|
instance.set(underline=1)
|
||||||
|
|
||||||
|
expected_sequence = (
|
||||||
|
TXT_NORMAL, TXT_STYLE['size']['normal'], # Normal text size
|
||||||
|
TXT_STYLE['flip'][False], # Flip OFF
|
||||||
|
TXT_STYLE['smooth'][False], # Smooth OFF
|
||||||
|
TXT_STYLE['bold'][False], # Bold OFF
|
||||||
|
TXT_STYLE['underline'][1], # Underline ON, type 1
|
||||||
|
SET_FONT(b'\x00'), # Default font
|
||||||
|
TXT_STYLE['align']['left'], # Align left
|
||||||
|
TXT_STYLE['invert'][False] # Inverted OFF
|
||||||
|
)
|
||||||
|
|
||||||
|
assert (instance.output == b''.join(expected_sequence))
|
||||||
|
|
||||||
|
|
||||||
|
def test_set_underline2():
|
||||||
|
instance = printer.Dummy()
|
||||||
|
instance.set(underline=2)
|
||||||
|
|
||||||
|
expected_sequence = (
|
||||||
|
TXT_NORMAL, TXT_STYLE['size']['normal'], # Normal text size
|
||||||
|
TXT_STYLE['flip'][False], # Flip OFF
|
||||||
|
TXT_STYLE['smooth'][False], # Smooth OFF
|
||||||
|
TXT_STYLE['bold'][False], # Bold OFF
|
||||||
|
TXT_STYLE['underline'][2], # Underline ON, type 2
|
||||||
|
SET_FONT(b'\x00'), # Default font
|
||||||
|
TXT_STYLE['align']['left'], # Align left
|
||||||
|
TXT_STYLE['invert'][False] # Inverted OFF
|
||||||
|
)
|
||||||
|
|
||||||
|
assert (instance.output == b''.join(expected_sequence))
|
||||||
|
|
||||||
|
|
||||||
|
# Align
|
||||||
|
|
||||||
|
def test_align_center():
|
||||||
|
instance = printer.Dummy()
|
||||||
|
instance.set(align='center')
|
||||||
|
|
||||||
|
expected_sequence = (
|
||||||
|
TXT_NORMAL, TXT_STYLE['size']['normal'], # Normal text size
|
||||||
|
TXT_STYLE['flip'][False], # Flip OFF
|
||||||
|
TXT_STYLE['smooth'][False], # Smooth OFF
|
||||||
|
TXT_STYLE['bold'][False], # Bold OFF
|
||||||
|
TXT_STYLE['underline'][0], # Underline OFF
|
||||||
|
SET_FONT(b'\x00'), # Default font
|
||||||
|
TXT_STYLE['align']['center'], # Align center
|
||||||
|
TXT_STYLE['invert'][False] # Inverted OFF
|
||||||
|
)
|
||||||
|
|
||||||
|
assert(instance.output == b''.join(expected_sequence))
|
||||||
|
|
||||||
|
|
||||||
|
def test_align_right():
|
||||||
|
instance = printer.Dummy()
|
||||||
|
instance.set(align='right')
|
||||||
|
|
||||||
|
expected_sequence = (
|
||||||
|
TXT_NORMAL, TXT_STYLE['size']['normal'], # Normal text size
|
||||||
|
TXT_STYLE['flip'][False], # Flip OFF
|
||||||
|
TXT_STYLE['smooth'][False], # Smooth OFF
|
||||||
|
TXT_STYLE['bold'][False], # Bold OFF
|
||||||
|
TXT_STYLE['underline'][0], # Underline OFF
|
||||||
|
SET_FONT(b'\x00'), # Default font
|
||||||
|
TXT_STYLE['align']['right'], # Align right
|
||||||
|
TXT_STYLE['invert'][False] # Inverted OFF
|
||||||
|
)
|
||||||
|
|
||||||
|
assert(instance.output == b''.join(expected_sequence))
|
||||||
|
|
||||||
|
|
||||||
|
# Densities
|
||||||
|
|
||||||
|
def test_densities():
|
||||||
|
|
||||||
|
for density in range(8):
|
||||||
|
instance = printer.Dummy()
|
||||||
|
instance.set(density=density)
|
||||||
|
|
||||||
|
expected_sequence = (
|
||||||
|
TXT_NORMAL, TXT_STYLE['size']['normal'], # Normal text size
|
||||||
|
TXT_STYLE['flip'][False], # Flip OFF
|
||||||
|
TXT_STYLE['smooth'][False], # Smooth OFF
|
||||||
|
TXT_STYLE['bold'][False], # Bold OFF
|
||||||
|
TXT_STYLE['underline'][0], # Underline OFF
|
||||||
|
SET_FONT(b'\x00'), # Default font
|
||||||
|
TXT_STYLE['align']['left'], # Align left
|
||||||
|
TXT_STYLE['density'][density], # Custom density from 0 to 8
|
||||||
|
TXT_STYLE['invert'][False] # Inverted OFF
|
||||||
|
)
|
||||||
|
|
||||||
|
assert(instance.output == b''.join(expected_sequence))
|
||||||
|
|
||||||
|
|
||||||
|
# Invert
|
||||||
|
|
||||||
|
def test_invert():
|
||||||
|
instance = printer.Dummy()
|
||||||
|
instance.set(invert=True)
|
||||||
|
|
||||||
|
expected_sequence = (
|
||||||
|
TXT_NORMAL, TXT_STYLE['size']['normal'], # Normal text size
|
||||||
|
TXT_STYLE['flip'][False], # Flip OFF
|
||||||
|
TXT_STYLE['smooth'][False], # Smooth OFF
|
||||||
|
TXT_STYLE['bold'][False], # Bold OFF
|
||||||
|
TXT_STYLE['underline'][0], # Underline OFF
|
||||||
|
SET_FONT(b'\x00'), # Default font
|
||||||
|
TXT_STYLE['align']['left'], # Align left
|
||||||
|
TXT_STYLE['invert'][True] # Inverted ON
|
||||||
|
)
|
||||||
|
|
||||||
|
assert(instance.output == b''.join(expected_sequence))
|
@@ -12,30 +12,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
|
||||||
|
|
||||||
from nose.tools import with_setup
|
|
||||||
|
|
||||||
import escpos.printer as printer
|
import escpos.printer as printer
|
||||||
import os
|
|
||||||
|
|
||||||
devfile = 'testfile'
|
|
||||||
|
|
||||||
|
|
||||||
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_instantiation():
|
def test_instantiation():
|
||||||
"""test the instantiation of a escpos-printer class and basic printing"""
|
"""test the instantiation of a escpos-printer class and basic printing"""
|
||||||
instance = printer.File(devfile=devfile)
|
instance = printer.Dummy()
|
||||||
instance.text('This is a test\n')
|
instance.text('This is a test\n')
|
||||||
|
Reference in New Issue
Block a user