Compare commits
816 Commits
Author | SHA1 | Date | |
---|---|---|---|
![]() |
0d22896689 | ||
![]() |
b66dafc90e | ||
![]() |
0c824cf295 | ||
![]() |
66a2e78e16 | ||
![]() |
06bdb56937 | ||
![]() |
91cbc264fc | ||
![]() |
dcc71ce47d | ||
![]() |
d2b213dcdc | ||
![]() |
c91eec544e | ||
![]() |
a9e49c909d | ||
![]() |
815f247df1 | ||
![]() |
5914c7c560 | ||
![]() |
86a715cf02 | ||
![]() |
ac23c083b6 | ||
![]() |
9a1699ab94 | ||
![]() |
8274833255 | ||
![]() |
33d17615a0 | ||
![]() |
90c89e66f0 | ||
![]() |
8f44ae7480 | ||
![]() |
ff5631c989 | ||
![]() |
ecf3fbcc25 | ||
![]() |
678f8d2451 | ||
![]() |
a127c7b9c4 | ||
![]() |
72d26879a0 | ||
![]() |
3b6551004f | ||
![]() |
5d3d2ca34b | ||
![]() |
d2ef5159c5 | ||
![]() |
a50a3b7167 | ||
![]() |
e7dd97554c | ||
![]() |
425d3d209f | ||
![]() |
a00b98937b | ||
![]() |
a8d789fe64 | ||
![]() |
246c4ea6c5 | ||
![]() |
3a8af8a6f5 | ||
![]() |
e4f4844983 | ||
![]() |
a70e1604d6 | ||
![]() |
5018f7f377 | ||
![]() |
ecfeeb9b13 | ||
![]() |
ba0167f1fd | ||
![]() |
87e488ce11 | ||
![]() |
6d0c475b9a | ||
![]() |
adcde8abda | ||
![]() |
89aaae0186 | ||
![]() |
f3ee049ee1 | ||
![]() |
cfa9ecf16d | ||
![]() |
8f07c1da0f | ||
![]() |
24217756f7 | ||
![]() |
e3e1500d35 | ||
![]() |
44444f3c51 | ||
![]() |
c7c01cdbff | ||
![]() |
6c49e4a057 | ||
![]() |
f23bcacabe | ||
![]() |
c11d192e65 | ||
![]() |
3177c8d411 | ||
![]() |
fbabd8ed88 | ||
![]() |
2b62c8e28d | ||
![]() |
4c2dcdfac6 | ||
![]() |
31daabcbea | ||
![]() |
4a0f5855ef | ||
![]() |
60c4f481ae | ||
![]() |
09a598883c | ||
![]() |
df9e8ff394 | ||
![]() |
9ff327d967 | ||
![]() |
e9e8b10582 | ||
![]() |
cb3f4e856b | ||
![]() |
756bf2c6c2 | ||
![]() |
3c11c1b9ab | ||
![]() |
676d2840de | ||
![]() |
e72ebc7986 | ||
![]() |
c67c077a4d | ||
![]() |
fc17391b63 | ||
![]() |
905e37e52e | ||
![]() |
66348ccc0a | ||
![]() |
2b826aa834 | ||
![]() |
3560f8b12b | ||
![]() |
83c7f5745c | ||
![]() |
7bf8d4e4b8 | ||
![]() |
6849dd3979 | ||
![]() |
25867f3196 | ||
![]() |
8bbbf7ceac | ||
![]() |
5b72985b0a | ||
![]() |
ef7d518953 | ||
![]() |
d4d3819d55 | ||
![]() |
98ee06a783 | ||
![]() |
de515a86cc | ||
![]() |
2b0d57a9c7 | ||
![]() |
1626af5def | ||
![]() |
e4a73ad5c5 | ||
![]() |
709d90809c | ||
![]() |
90c340163c | ||
![]() |
757fe3328c | ||
![]() |
0a8d8ae6c4 | ||
![]() |
70d4da1364 | ||
![]() |
cbf887ed02 | ||
![]() |
b1a1204bb8 | ||
![]() |
361afe3555 | ||
![]() |
2bc61d9bf8 | ||
![]() |
67827d8e4d | ||
![]() |
2567e0e12a | ||
![]() |
83cccf0cb9 | ||
![]() |
fe9c0573f8 | ||
![]() |
ea61f287cb | ||
![]() |
69e9dca761 | ||
![]() |
49ab3f35a8 | ||
![]() |
84a3912b34 | ||
![]() |
9a3057c8a8 | ||
![]() |
0b695eff79 | ||
![]() |
f0760ddbc0 | ||
![]() |
39826c3286 | ||
![]() |
7f9878282d | ||
![]() |
5e80764ff5 | ||
![]() |
219b43d35a | ||
![]() |
b16f44257e | ||
![]() |
5bb0642b5d | ||
![]() |
8e5c600e20 | ||
![]() |
435f2bba24 | ||
![]() |
109a5d8a92 | ||
![]() |
4a88bacd3f | ||
![]() |
19abf43448 | ||
![]() |
7b6dbc4db4 | ||
![]() |
53aab73ffc | ||
![]() |
a4e15c6ac2 | ||
![]() |
dcfb8fec30 | ||
![]() |
14edc87206 | ||
![]() |
1e3024eaa9 | ||
![]() |
15c18f225e | ||
![]() |
a526be5ddf | ||
![]() |
92fbcabdd2 | ||
![]() |
27b7ae8629 | ||
![]() |
7c82881f65 | ||
![]() |
05f68b22b4 | ||
![]() |
f9ce777057 | ||
![]() |
c2e3b79e5a | ||
![]() |
b5a999a6ea | ||
![]() |
0b2118e146 | ||
![]() |
69e9b9103e | ||
![]() |
620cf97bbf | ||
![]() |
1ad53eb642 | ||
![]() |
ed8ec0788a | ||
![]() |
dd3c768f13 | ||
![]() |
36bbb6690f | ||
![]() |
0758a79e64 | ||
![]() |
9c41cfc54f | ||
![]() |
75006f62da | ||
![]() |
58e1682448 | ||
![]() |
0057a498bb | ||
![]() |
b3e93020d4 | ||
![]() |
3962bc991f | ||
![]() |
b608d59942 | ||
![]() |
e898413464 | ||
![]() |
357558ae10 | ||
![]() |
809b4f47aa | ||
![]() |
b6516e4b42 | ||
![]() |
8a54d59dbc | ||
![]() |
1275bf90d1 | ||
![]() |
d6639d37f3 | ||
![]() |
21f19b7f7e | ||
![]() |
3c479407dc | ||
![]() |
3f04ff352e | ||
![]() |
6c89e93c22 | ||
![]() |
266b64bf2b | ||
![]() |
a2e348d04a | ||
![]() |
40c8399a68 | ||
![]() |
a279ae7152 | ||
![]() |
a2d553efb1 | ||
![]() |
84a97e5b9f | ||
![]() |
7db3d30f4a | ||
![]() |
c6f93e017a | ||
![]() |
c09c10cb2d | ||
![]() |
af4785d52f | ||
![]() |
e68cdcdac2 | ||
![]() |
18cc1a268a | ||
![]() |
5d62be2be9 | ||
![]() |
1dc79baf82 | ||
![]() |
247211d0ce | ||
![]() |
243eb48b38 | ||
![]() |
21b9dba345 | ||
![]() |
a8941b4a3e | ||
![]() |
04e0a0ce47 | ||
![]() |
8ece137789 | ||
![]() |
d390449400 | ||
![]() |
8488fafd75 | ||
![]() |
818c1313e8 | ||
![]() |
596787554b | ||
![]() |
2d798ca7e5 | ||
![]() |
24105226b2 | ||
![]() |
c57b9c35dc | ||
![]() |
0a8477a888 | ||
![]() |
e3cf088d69 | ||
![]() |
323db98318 | ||
![]() |
ee6eef6db3 | ||
![]() |
ef34cca463 | ||
![]() |
4680fb16b1 | ||
![]() |
544bb4f904 | ||
![]() |
d330dd80fd | ||
![]() |
570661b3c8 | ||
![]() |
aa7f2773eb | ||
![]() |
ff39908674 | ||
![]() |
d960eea4a8 | ||
![]() |
f7962576b4 | ||
![]() |
f4e214ad17 | ||
![]() |
9e406efc86 | ||
![]() |
b9e3827867 | ||
![]() |
cbe412cfdb | ||
![]() |
42554d836c | ||
![]() |
8ca682e3ac | ||
![]() |
ab30ef4a8c | ||
![]() |
725f1254aa | ||
![]() |
1e313cefc6 | ||
![]() |
b0ea9aec41 | ||
![]() |
ab210b5996 | ||
![]() |
f3e1db8da2 | ||
![]() |
1e7b43a92d | ||
![]() |
0e41709703 | ||
![]() |
cb30d7a881 | ||
![]() |
142fc4af71 | ||
![]() |
8f71372bb0 | ||
![]() |
81fb7caa07 | ||
![]() |
6a60b6706e | ||
![]() |
c14a414924 | ||
![]() |
faa9414da5 | ||
![]() |
2c4552a528 | ||
![]() |
c9953c2f56 | ||
![]() |
557991d80b | ||
![]() |
fe08fc1469 | ||
![]() |
6c27222aeb | ||
![]() |
6731057456 | ||
![]() |
f0b1a89c48 | ||
![]() |
fd7bd0710e | ||
![]() |
7ea58625e6 | ||
![]() |
baffd98a22 | ||
![]() |
ecbdd43dff | ||
![]() |
5b6b96d2a0 | ||
![]() |
7aa20a60e3 | ||
![]() |
95ec6d5c08 | ||
![]() |
18c3a5f298 | ||
![]() |
4836dcd486 | ||
![]() |
d9d400da6d | ||
![]() |
fe2e1a6d28 | ||
![]() |
c53575a155 | ||
![]() |
cadf448c38 | ||
![]() |
7c05404ac4 | ||
![]() |
e1e1ccb3f2 | ||
![]() |
32c56e78ea | ||
![]() |
4d106e8659 | ||
![]() |
ddab5318cf | ||
![]() |
9b60e2e3ab | ||
![]() |
34cd1ebde1 | ||
![]() |
a2db415559 | ||
![]() |
4e19b0ca51 | ||
![]() |
a3660a6366 | ||
![]() |
9fa551e6e8 | ||
![]() |
ae0a049efa | ||
![]() |
117d286371 | ||
![]() |
a555a651b4 | ||
![]() |
e350a49cad | ||
![]() |
f49c1dcb89 | ||
![]() |
cc67cb1c1e | ||
![]() |
2ee3ff7f87 | ||
![]() |
ca45d25670 | ||
![]() |
f07d5e0610 | ||
![]() |
5eeff1c16b | ||
![]() |
51d1299285 | ||
![]() |
a30c28baa5 | ||
![]() |
0c0e6b9b4c | ||
![]() |
50437cc9d2 | ||
![]() |
7c7d401f31 | ||
![]() |
2110431d4f | ||
![]() |
c0481f3a9a | ||
![]() |
6161b46d57 | ||
![]() |
c86826101d | ||
![]() |
fa140c2df5 | ||
![]() |
8b3076871f | ||
![]() |
46429b1092 | ||
![]() |
99ca096f82 | ||
![]() |
2d97c0bbbd | ||
![]() |
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 | ||
![]() |
0051c876bf | ||
![]() |
854759d312 | ||
![]() |
a0343c66af | ||
![]() |
6c94f88c24 | ||
![]() |
6fb23d6826 | ||
![]() |
f649814091 | ||
![]() |
47b4d41b28 | ||
![]() |
599f4f3ca5 | ||
![]() |
d085e5c467 | ||
![]() |
b418302311 | ||
![]() |
f6acb72bbe | ||
![]() |
0c9856c1f6 | ||
![]() |
a748563395 | ||
![]() |
b84e280efb | ||
![]() |
4390dc4a9c | ||
![]() |
6e09fd1e97 | ||
![]() |
100c6b5e89 | ||
![]() |
26d72a69f0 | ||
![]() |
01e28bbcf6 | ||
![]() |
2a7e2a6a36 | ||
![]() |
3c3dab95f5 | ||
![]() |
d1e7052fa1 | ||
![]() |
10e1dfe1d1 | ||
![]() |
cd1bcb57b4 | ||
![]() |
d6d12f99d4 | ||
![]() |
128221363f | ||
![]() |
6b0b1371e5 | ||
![]() |
44f01a212b | ||
![]() |
456f5b7aa6 | ||
![]() |
d78a6f1699 | ||
![]() |
5e784c060a | ||
![]() |
1439b14686 | ||
![]() |
b648cfd67f | ||
![]() |
50c627fbb0 | ||
![]() |
99034d0575 | ||
![]() |
19663ec574 | ||
![]() |
281eea125f | ||
![]() |
5bed0bfbb4 | ||
![]() |
f12470d3cd | ||
![]() |
fb0e4c28ba | ||
![]() |
af29fcca77 | ||
![]() |
f8b269d859 | ||
![]() |
c259263f26 | ||
![]() |
27c843935f | ||
![]() |
f3da6a9725 | ||
![]() |
b64b534394 | ||
![]() |
81426ab6dc | ||
![]() |
df1193ab35 | ||
![]() |
b494c9a4bd | ||
![]() |
f8a2174108 | ||
![]() |
1f57b04974 | ||
![]() |
c7080165a7 | ||
![]() |
cf0cf127fe | ||
![]() |
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 | ||
![]() |
df33945458 | ||
![]() |
c1a7d71fd7 | ||
![]() |
a7ee11a78c | ||
![]() |
43e0a87a74 | ||
![]() |
abbe32f845 | ||
![]() |
29cc8baab7 | ||
![]() |
0f33d68f3a | ||
![]() |
a0ef820947 | ||
![]() |
7b24df6581 | ||
![]() |
5078c49b3a | ||
![]() |
4b81a27407 | ||
![]() |
e8aefd8388 | ||
![]() |
3ee787e8b1 | ||
![]() |
b76fb75702 | ||
![]() |
2bcb1766ae | ||
![]() |
e92f00cdf3 | ||
![]() |
1038844567 | ||
![]() |
1579f05cb7 | ||
![]() |
f885de2f2a | ||
![]() |
fc5ad1673c | ||
![]() |
337e8ee19e | ||
![]() |
81028f9a35 | ||
![]() |
fb18bb34cc | ||
![]() |
94a0f2b94b | ||
![]() |
ce94a1fc18 | ||
![]() |
ca880dd8ec | ||
![]() |
fc69754a21 | ||
![]() |
b4920aafe2 | ||
![]() |
43e30707be | ||
![]() |
c48a0bee51 | ||
![]() |
972c7a2238 | ||
![]() |
c2fc464c55 | ||
![]() |
2ea8e69c66 | ||
![]() |
e4a21e94fc | ||
![]() |
e904500312 | ||
![]() |
efff2cbe43 | ||
![]() |
d3f76a5f6d | ||
![]() |
e595bc2150 | ||
![]() |
7bf6a1791b | ||
![]() |
a15d02b50c | ||
![]() |
938f9890ab | ||
![]() |
1e5a41ba4e | ||
![]() |
f8b7238801 | ||
![]() |
e35f551a56 | ||
![]() |
24731f433e | ||
![]() |
6158ba344f | ||
![]() |
78604573f3 | ||
![]() |
bd57c01794 | ||
![]() |
211e7db22c | ||
![]() |
da0d49c787 | ||
![]() |
46305faf30 | ||
![]() |
94e1944d16 | ||
![]() |
13785a5530 | ||
![]() |
10c589ae8d | ||
![]() |
cd38cdf74e | ||
![]() |
f50910f76e | ||
![]() |
398eb424a9 | ||
![]() |
1b2f509758 | ||
![]() |
b795c02dd4 | ||
![]() |
915adf8fd3 | ||
![]() |
a3ca2c2a16 | ||
![]() |
47fd020abe | ||
![]() |
4f2f1cf520 | ||
![]() |
a82fefb301 | ||
![]() |
7b68d97f5f | ||
![]() |
7a7ea23628 | ||
![]() |
83f926758c | ||
![]() |
9a65945fcd | ||
![]() |
d9a6960f07 | ||
![]() |
b5bf1125db | ||
![]() |
2c8bc1180d | ||
![]() |
4166ee2209 | ||
![]() |
95a84d3673 | ||
![]() |
57ed77e332 | ||
![]() |
2b17e16737 | ||
![]() |
f467cacdd8 | ||
![]() |
9662ca6efe | ||
![]() |
587eee2ef0 | ||
![]() |
f5c706db34 | ||
![]() |
b29ef6df69 | ||
![]() |
a435b66006 | ||
![]() |
ddc93d7369 | ||
![]() |
c3e3ec5808 | ||
![]() |
b543ecea58 | ||
![]() |
c850a726cb | ||
![]() |
d246e945a2 | ||
![]() |
1bd53697b9 | ||
![]() |
73ef8c4c0a | ||
![]() |
9aa1335fd2 | ||
![]() |
2f89f3fe3a | ||
![]() |
40be69347c | ||
![]() |
58ea206c36 | ||
![]() |
68c17f1181 | ||
![]() |
b37f4fc8cc | ||
![]() |
630423d24a | ||
![]() |
b92eeed50b | ||
![]() |
3681c5c7bf | ||
![]() |
4496ea91bd | ||
![]() |
3d8626d17e | ||
![]() |
ea7769f8b2 | ||
![]() |
5fa89ff685 | ||
![]() |
a07f84a5bc | ||
![]() |
216184f43f | ||
![]() |
c7864fd785 | ||
![]() |
cbe38648f5 | ||
![]() |
f6ce7e45da | ||
![]() |
3fd1a3de5d | ||
![]() |
214aa0d363 | ||
![]() |
d43bcd187e | ||
![]() |
6b069a4529 | ||
![]() |
cf41069829 | ||
![]() |
bde6eaa336 | ||
![]() |
632a104219 | ||
![]() |
ae9b3785c2 | ||
![]() |
8b5bc9cf8a | ||
![]() |
a8574ad9d7 | ||
![]() |
ed3077f00f | ||
![]() |
07d47765aa | ||
![]() |
854b75be30 | ||
![]() |
df0c874f6e | ||
![]() |
5c3d7dab72 | ||
![]() |
798893caee | ||
![]() |
e8d91a6735 | ||
![]() |
996b3fd332 | ||
![]() |
a38c124bb1 | ||
![]() |
e44d89bd33 | ||
![]() |
7312db4adb | ||
![]() |
59dccd79da | ||
![]() |
603b34cadb | ||
![]() |
340a47d2f6 | ||
![]() |
dfe2cdbff8 | ||
![]() |
eea2a6f9c0 | ||
![]() |
11452034a3 | ||
![]() |
d2e2ea88a6 | ||
![]() |
2416303805 | ||
![]() |
38f9835931 | ||
![]() |
87a6647053 | ||
![]() |
046a08896c | ||
![]() |
f0bdbc4322 | ||
![]() |
13937ab0da | ||
![]() |
0cfedb5706 | ||
![]() |
b0af9e9652 | ||
![]() |
3546e0c4bb | ||
![]() |
7c732ee615 | ||
![]() |
3d98eb8b9c | ||
![]() |
619d80a867 | ||
![]() |
d3f74ced5d | ||
![]() |
0524b0576e | ||
![]() |
c92d4463ae | ||
![]() |
6e74748773 | ||
![]() |
a2e188cecf | ||
![]() |
c1a6da9aaa | ||
![]() |
2ecf73074c | ||
![]() |
37baf5cd34 | ||
![]() |
5c209dd557 | ||
![]() |
bef1a9cccf | ||
![]() |
10977b06e7 | ||
![]() |
042f945a09 | ||
![]() |
2cf30c7f05 | ||
![]() |
34d929806c | ||
![]() |
c5d34cc268 | ||
![]() |
fd3f1067fe | ||
![]() |
80b714fdae | ||
![]() |
457c62cc7f | ||
![]() |
a5cae3adb7 | ||
![]() |
9f5eed0020 | ||
![]() |
57dd60c13f | ||
![]() |
0ec83387d5 | ||
![]() |
36e0a52e2d | ||
![]() |
214b4def14 | ||
![]() |
c13a0715e4 | ||
![]() |
925d19447d | ||
![]() |
5be81e4703 | ||
![]() |
ab39fd2b99 | ||
![]() |
685a1f504c | ||
![]() |
7529642788 | ||
![]() |
0907b6aa8b | ||
![]() |
87438f9efa | ||
![]() |
e8e91eba80 | ||
![]() |
3e5509238e | ||
![]() |
08051d48d0 | ||
![]() |
2676a802bd | ||
![]() |
6697922b74 | ||
![]() |
e814396bd8 | ||
![]() |
adf73f3790 | ||
![]() |
1e490b6de8 | ||
![]() |
910f2fbf2f | ||
![]() |
16569067c2 | ||
![]() |
a0dc993f2f | ||
![]() |
1b00477144 | ||
![]() |
ddaf126c20 | ||
![]() |
6a2673d01d | ||
![]() |
f6ae109bb9 | ||
![]() |
0a8057414c | ||
![]() |
a34e306ea8 | ||
![]() |
2588406831 | ||
![]() |
b6ada13f9b | ||
![]() |
eadd9f7583 | ||
![]() |
471222eda9 | ||
![]() |
c6cc28254e | ||
![]() |
f903af6730 | ||
![]() |
a0d8689141 | ||
![]() |
44c79eaf11 | ||
![]() |
4584e3138a | ||
![]() |
6b445b3fb1 | ||
![]() |
ba03538c50 | ||
![]() |
b45afbb297 | ||
![]() |
59afcf778f | ||
![]() |
36debff72c | ||
![]() |
2aa0878f54 | ||
![]() |
7b18afec75 | ||
![]() |
f39c4227ec | ||
![]() |
481285625b | ||
![]() |
1ee657a750 | ||
![]() |
0121aa0bfb | ||
![]() |
7547bfddd2 | ||
![]() |
f6e0edc7c7 | ||
![]() |
df77b7dec3 | ||
![]() |
bf3012b882 | ||
![]() |
68b3ec4d89 | ||
![]() |
a236ccebe9 | ||
![]() |
1a1c032d6a | ||
![]() |
f5a7d681eb | ||
![]() |
abebf7eb99 | ||
![]() |
fca363119c | ||
![]() |
8ed1441c4c | ||
![]() |
062282bf47 | ||
![]() |
3fe4589b8b | ||
![]() |
b9c9189ca7 | ||
![]() |
5ecae9d585 | ||
![]() |
39da32ca85 | ||
![]() |
e545999aa2 | ||
![]() |
3017c14df2 | ||
![]() |
3831665da4 | ||
![]() |
b6b30d7c82 | ||
![]() |
39165fcb41 | ||
![]() |
fd6a0e4bda | ||
![]() |
38b58eb39a | ||
![]() |
cabb2c930a | ||
![]() |
0c3f273fa1 | ||
![]() |
76f300ea18 | ||
![]() |
f504d2dc15 | ||
![]() |
5a2ca10874 | ||
![]() |
8101e1ec9f | ||
![]() |
1a000d29fd | ||
![]() |
28b82fb54f | ||
![]() |
ee223670bf | ||
![]() |
a445c4205a | ||
![]() |
00ef7f129b | ||
![]() |
8c186d912d | ||
![]() |
14ae1a7d89 | ||
![]() |
ca3b4665a2 | ||
![]() |
4f92247ed6 | ||
![]() |
5ba751d89b | ||
![]() |
8e44c5126e | ||
![]() |
7a58109928 | ||
![]() |
9b40c0860f | ||
![]() |
3ec00ae16e | ||
![]() |
7afd5e75d4 | ||
![]() |
7d74dcac00 | ||
![]() |
cdf8f6be09 | ||
![]() |
d5e3d85c4b | ||
![]() |
2bb9756d28 | ||
![]() |
5dc676bea7 | ||
![]() |
c26c875b61 | ||
![]() |
39e912bef4 | ||
![]() |
c7b36916e7 | ||
![]() |
4548dd3830 | ||
![]() |
d5073626ae | ||
![]() |
1a866f4d1f | ||
![]() |
ef31e58d26 | ||
![]() |
01328db808 | ||
![]() |
1adc66992d | ||
![]() |
73be1f2c48 | ||
![]() |
27352b071c | ||
![]() |
87a73beb31 | ||
![]() |
6096c15b80 | ||
![]() |
133241e7e9 | ||
![]() |
eea3e76eed | ||
![]() |
28be6a2041 | ||
![]() |
d523b4d342 | ||
![]() |
99291abd10 | ||
![]() |
81b3c1a63a | ||
![]() |
323b205f70 | ||
![]() |
2dc70677d7 | ||
![]() |
e355d2cbdf | ||
![]() |
126e0e269a | ||
![]() |
309866f8c9 | ||
![]() |
8596148271 | ||
![]() |
8b454c4765 | ||
![]() |
f76db4e0d4 | ||
![]() |
e43e95bcff | ||
![]() |
b2ff39b6b1 | ||
![]() |
64e63b0180 | ||
![]() |
e49c35abc1 | ||
![]() |
f676782130 | ||
![]() |
086b407b62 | ||
![]() |
1a2b8f1df2 | ||
![]() |
68641572f9 | ||
![]() |
7fdccb7245 | ||
![]() |
fee650faba | ||
![]() |
1009cf8988 | ||
![]() |
916b09a84c | ||
![]() |
80f6200915 | ||
![]() |
f354791285 | ||
![]() |
205728f5be | ||
![]() |
046cf1ff5b | ||
![]() |
75252a3797 | ||
![]() |
21992d7017 | ||
![]() |
4c406c1775 | ||
![]() |
5b5c2c0dba | ||
![]() |
6b56de67a7 | ||
![]() |
c9ea90cd82 | ||
![]() |
5d5412ba73 | ||
![]() |
7005ba5899 | ||
![]() |
18518fa901 | ||
![]() |
bda7f85346 | ||
![]() |
70307d0f24 | ||
![]() |
5a03f0fc7c | ||
![]() |
4cfc4fd564 | ||
![]() |
d96dcd8e7e | ||
![]() |
9d12c7faab | ||
![]() |
39d1c1d587 | ||
![]() |
dbb0081287 | ||
![]() |
68a9dcc47b | ||
![]() |
7f921c667b | ||
![]() |
d888a39b6f | ||
![]() |
250455ae23 | ||
![]() |
d9ffb03089 | ||
![]() |
5c49e0103c | ||
![]() |
60bc6b7d5c | ||
![]() |
cdf997aff5 | ||
![]() |
8b8162c1a9 | ||
![]() |
870144aac6 | ||
![]() |
e48755f7d0 | ||
![]() |
8d00e63b87 | ||
![]() |
7c98de6727 | ||
![]() |
8000cf258b | ||
![]() |
b7c6edc9e1 | ||
![]() |
f303a38a8d | ||
![]() |
d672ca1268 | ||
![]() |
3e200a86b9 | ||
![]() |
95f5b5ed48 | ||
![]() |
331fe6a93a | ||
![]() |
ae37de2577 | ||
![]() |
720545979c | ||
![]() |
0c56f5c831 | ||
![]() |
248ddf8456 | ||
![]() |
713380baf9 | ||
![]() |
cd2da59fc2 | ||
![]() |
d00fc5016b | ||
![]() |
939e66834e | ||
![]() |
198b50ac5e | ||
![]() |
41c6afd3b8 | ||
![]() |
f25521f22f | ||
![]() |
0e907644d9 | ||
![]() |
a6ec674828 | ||
![]() |
598c893943 | ||
![]() |
1614298863 | ||
![]() |
a921061b40 | ||
![]() |
050419f117 | ||
![]() |
3e89a10bed | ||
![]() |
e988873999 | ||
![]() |
f7a2caee72 | ||
![]() |
4e1f9db5c7 | ||
![]() |
9159aafd18 | ||
![]() |
020ba4145c | ||
![]() |
592dbe15f6 | ||
![]() |
69680b04e9 | ||
![]() |
e88a19ef2d | ||
![]() |
c2b45748e1 | ||
![]() |
8b8ca76af6 | ||
![]() |
e5cd37bfbc | ||
![]() |
3d61445e2c | ||
![]() |
8b8ab80e5f | ||
![]() |
029549aaae | ||
![]() |
6cc325b395 | ||
![]() |
a9844b1a1b | ||
![]() |
e16e666dce | ||
![]() |
50fbf2873f | ||
![]() |
ce0b0d5ba3 | ||
![]() |
2aafc34ae1 | ||
![]() |
c3fbdf28d4 | ||
![]() |
8a77c963c3 | ||
![]() |
b68a5782fe | ||
![]() |
06a68d1c97 | ||
![]() |
aa4ffdd21b | ||
![]() |
05ea0e929e | ||
![]() |
50b0691e68 | ||
![]() |
06f2e1e731 | ||
![]() |
577de10cb4 | ||
![]() |
242399ebe2 | ||
![]() |
8fd05eb02b | ||
![]() |
c1d985eeaf | ||
![]() |
0dacc35d94 | ||
![]() |
8b5798eedf | ||
![]() |
ef8035527c | ||
![]() |
07d8e073ae | ||
![]() |
096445631f | ||
![]() |
3ea52e52fd | ||
![]() |
371d5e78bd | ||
![]() |
7e3b6ce586 | ||
![]() |
4bb94c2662 | ||
![]() |
ef84a5150f | ||
![]() |
cd5969e843 | ||
![]() |
1a1ed5e7fc | ||
![]() |
e23ce9bfc2 | ||
![]() |
546f47edcc | ||
![]() |
3f6528da07 | ||
![]() |
5eaa6f26d0 | ||
![]() |
25b650c935 | ||
![]() |
6734864a5b | ||
![]() |
0ef2951c7e | ||
![]() |
dd228c9fda | ||
![]() |
7da2e32e3c | ||
![]() |
b99c076bae | ||
![]() |
afc6834082 |
2
.coveragerc
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
[run]
|
||||||
|
branch = True
|
27
.github/ISSUE_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
<!--
|
||||||
|
Please feel free to delete any sections that aren't relevant.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!-- mark with x between the [ ] -->
|
||||||
|
I have:
|
||||||
|
- [ ] searched open and closed issues for duplicates
|
||||||
|
|
||||||
|
### Bug description
|
||||||
|
|
||||||
|
### Steps to reproduce
|
||||||
|
- add your steps here
|
||||||
|
- as a list
|
||||||
|
- using hyphens
|
||||||
|
|
||||||
|
### Device info
|
||||||
|
<!-- Replace examples with your info -->
|
||||||
|
**Printer:** Manufacturer Model XVI
|
||||||
|
|
||||||
|
<!-- since version 2.0.1 you can type 'python-escpos version' in your shell.
|
||||||
|
Starting with python-escpos version 3.0, please replace the information below
|
||||||
|
with the output of `python-escpos version_extended`. -->
|
||||||
|
**python-escpos version:** 0.0.0
|
||||||
|
|
||||||
|
**python version:** 0.0
|
||||||
|
|
||||||
|
**operating system:**
|
5
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
### Description
|
||||||
|
|
||||||
|
|
||||||
|
### Tested with
|
||||||
|
_If applicable, please describe with which device you have tested._
|
23
.github/dependabot.yml
vendored
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
# To get started with Dependabot version updates, you'll need to specify which
|
||||||
|
# package ecosystems to update and where the package manifests are located.
|
||||||
|
# Please see the documentation for all configuration options:
|
||||||
|
# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
|
||||||
|
|
||||||
|
version: 2
|
||||||
|
updates:
|
||||||
|
- package-ecosystem: "pip" # See documentation for possible values
|
||||||
|
directory: "/" # Location of package manifests
|
||||||
|
schedule:
|
||||||
|
interval: "daily"
|
||||||
|
- package-ecosystem: "pip"
|
||||||
|
directory: "/doc"
|
||||||
|
schedule:
|
||||||
|
interval: "daily"
|
||||||
|
- package-ecosystem: "gitsubmodule"
|
||||||
|
directory: "/"
|
||||||
|
schedule:
|
||||||
|
interval: "daily"
|
||||||
|
- package-ecosystem: "github-actions"
|
||||||
|
directory: "/"
|
||||||
|
schedule:
|
||||||
|
interval: "daily"
|
13
.github/workflows/black.yml
vendored
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
name: Lint (Black code style)
|
||||||
|
|
||||||
|
on: [push, pull_request]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
black-code-style:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: psf/black@stable
|
||||||
|
with:
|
||||||
|
version: "23.12.0"
|
||||||
|
|
66
.github/workflows/codeql-analysis.yml
vendored
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
# For most projects, this workflow file will not need changing; you simply need
|
||||||
|
# to commit it to your repository.
|
||||||
|
#
|
||||||
|
# You may wish to alter this file to override the set of languages analyzed,
|
||||||
|
# or to provide custom queries or build logic.
|
||||||
|
name: "CodeQL"
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [master]
|
||||||
|
pull_request:
|
||||||
|
# The branches below must be a subset of the branches above
|
||||||
|
branches: [master]
|
||||||
|
schedule:
|
||||||
|
- cron: '0 1 * * 5'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
analyze:
|
||||||
|
name: Analyze
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
# Override automatic language detection by changing the below list
|
||||||
|
# Supported options are ['csharp', 'cpp', 'go', 'java', 'javascript', 'python']
|
||||||
|
language: ['python']
|
||||||
|
# Learn more...
|
||||||
|
# https://docs.github.com/en/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#overriding-automatic-language-detection
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout repository
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
# We must fetch at least the immediate parents so that if this is
|
||||||
|
# a pull request then we can checkout the head.
|
||||||
|
fetch-depth: 2
|
||||||
|
|
||||||
|
# Initializes the CodeQL tools for scanning.
|
||||||
|
- name: Initialize CodeQL
|
||||||
|
uses: github/codeql-action/init@v3
|
||||||
|
with:
|
||||||
|
languages: ${{ matrix.language }}
|
||||||
|
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||||
|
# By default, queries listed here will override any specified in a config file.
|
||||||
|
# Prefix the list here with "+" to use these queries and those in the config file.
|
||||||
|
# queries: ./path/to/local/query, your-org/your-repo/queries@main
|
||||||
|
|
||||||
|
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||||
|
# If this step fails, then you should remove it and run the build manually (see below)
|
||||||
|
- name: Autobuild
|
||||||
|
uses: github/codeql-action/autobuild@v3
|
||||||
|
|
||||||
|
# ℹ️ Command-line programs to run using the OS shell.
|
||||||
|
# 📚 https://git.io/JvXDl
|
||||||
|
|
||||||
|
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
|
||||||
|
# and modify them (or add more) to build your code if your project
|
||||||
|
# uses a compiled language
|
||||||
|
|
||||||
|
#- run: |
|
||||||
|
# make bootstrap
|
||||||
|
# make release
|
||||||
|
|
||||||
|
- name: Perform CodeQL Analysis
|
||||||
|
uses: github/codeql-action/analyze@v3
|
32
.github/workflows/documentation.yml
vendored
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
# This is a basic workflow to help you get started with Actions
|
||||||
|
|
||||||
|
name: Documentation build
|
||||||
|
|
||||||
|
# Controls when the action will run. Triggers the workflow on push or pull request
|
||||||
|
# events but only for the master branch
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ master ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ master ]
|
||||||
|
|
||||||
|
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
|
||||||
|
jobs:
|
||||||
|
# This workflow contains a single job called "docs"
|
||||||
|
docs:
|
||||||
|
# The type of runner that the job will run on
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
# Steps represent a sequence of tasks that will be executed as part of the job
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: 'recursive'
|
||||||
|
- name: Install packages
|
||||||
|
run:
|
||||||
|
sudo apt-get update -y &&
|
||||||
|
sudo apt-get install -y git python3-sphinx graphviz libenchant-2-2 &&
|
||||||
|
sudo apt-get install -y gcc libcups2-dev python3-dev python3-setuptools &&
|
||||||
|
sudo pip install tox pycups
|
||||||
|
- name: Test doc build
|
||||||
|
run: tox -e docs
|
55
.github/workflows/pythonpackage-windows.yml
vendored
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
name: Python package on Windows
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ master ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ master ]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
|
||||||
|
runs-on: windows-latest
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
python-version: ['3.11', '3.12']
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: 'recursive'
|
||||||
|
- name: Set up Python ${{ matrix.python-version }}
|
||||||
|
uses: actions/setup-python@v5.0.0
|
||||||
|
with:
|
||||||
|
python-version: ${{ matrix.python-version }}
|
||||||
|
- name: Install dependencies
|
||||||
|
run: |
|
||||||
|
python -m pip install --upgrade pip
|
||||||
|
pip install flake8 pytest tox tox-gh-actions
|
||||||
|
If (Test-Path .\requirements.txt) { pip install -r .\requirements.txt }
|
||||||
|
- name: Lint with flake8
|
||||||
|
run: |
|
||||||
|
# stop the build if there are Python syntax errors or undefined names
|
||||||
|
flake8 . --count --select=E,F,W --show-source --statistics
|
||||||
|
# exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
|
||||||
|
flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
|
||||||
|
- name: Test with tox
|
||||||
|
run: |
|
||||||
|
tox
|
||||||
|
env:
|
||||||
|
ESCPOS_CAPABILITIES_FILE: D:\a\python-escpos\python-escpos\capabilities-data\dist\capabilities.json
|
||||||
|
- name: Test mypy with tox
|
||||||
|
run: |
|
||||||
|
tox -e mypy
|
||||||
|
env:
|
||||||
|
ESCPOS_CAPABILITIES_FILE: D:\a\python-escpos\python-escpos\capabilities-data\dist\capabilities.json
|
||||||
|
- name: Upload coverage to Codecov
|
||||||
|
uses: codecov/codecov-action@v3
|
||||||
|
with:
|
||||||
|
directory: ./coverage/reports/
|
||||||
|
env_vars: OS,PYTHON
|
||||||
|
fail_ci_if_error: true
|
||||||
|
files: ./coverage.xml,!./cache
|
||||||
|
flags: unittests
|
||||||
|
name: coverage-tox-${{ matrix.python-version }}
|
||||||
|
verbose: true
|
65
.github/workflows/pythonpackage.yml
vendored
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
# This workflow will install Python dependencies, run tests and lint with a variety of Python versions
|
||||||
|
# For more information see: https://help.github.com/actions/language-and-framework-guides/using-python-with-github-actions
|
||||||
|
|
||||||
|
name: Python package
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ master ]
|
||||||
|
pull_request:
|
||||||
|
branches: [ master ]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
matrix:
|
||||||
|
python-version: ['3.8', '3.9', '3.10', '3.11', '3.12']
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: 'recursive'
|
||||||
|
- name: Set up Python ${{ matrix.python-version }}
|
||||||
|
uses: actions/setup-python@v5.0.0
|
||||||
|
with:
|
||||||
|
python-version: ${{ matrix.python-version }}
|
||||||
|
- name: Install dependencies
|
||||||
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y graphviz libenchant-2-2 gcc libcups2-dev python3-dev xindy
|
||||||
|
python -m pip install --upgrade pip
|
||||||
|
pip install flake8 pytest tox tox-gh-actions
|
||||||
|
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
|
||||||
|
- name: Check sorting of imports
|
||||||
|
uses: isort/isort-action@master
|
||||||
|
with:
|
||||||
|
requirementsFiles: "requirements.txt doc/requirements.txt"
|
||||||
|
sortPaths: "./doc ./src ./examples ./test ./setup.py"
|
||||||
|
- name: Lint with flake8
|
||||||
|
run: |
|
||||||
|
# stop the build if there are Python syntax errors or undefined names
|
||||||
|
flake8 . --count --select=E,F,W --show-source --statistics
|
||||||
|
# exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide
|
||||||
|
flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
|
||||||
|
- name: Test with tox
|
||||||
|
run: |
|
||||||
|
tox
|
||||||
|
env:
|
||||||
|
ESCPOS_CAPABILITIES_FILE: /home/runner/work/python-escpos/python-escpos/capabilities-data/dist/capabilities.json
|
||||||
|
- name: Test mypy with tox
|
||||||
|
run: |
|
||||||
|
tox -e mypy
|
||||||
|
env:
|
||||||
|
ESCPOS_CAPABILITIES_FILE: /home/runner/work/python-escpos/python-escpos/capabilities-data/dist/capabilities.json
|
||||||
|
- name: Upload coverage to Codecov
|
||||||
|
uses: codecov/codecov-action@v3
|
||||||
|
with:
|
||||||
|
directory: ./coverage/reports/
|
||||||
|
env_vars: OS,PYTHON
|
||||||
|
fail_ci_if_error: true
|
||||||
|
files: ./coverage.xml,!./cache
|
||||||
|
flags: unittests
|
||||||
|
name: coverage-tox-${{ matrix.python-version }}
|
||||||
|
verbose: true
|
44
.gitignore
vendored
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
# python temporary files
|
||||||
|
*.pyc
|
||||||
|
|
||||||
|
# editor autosaves, data and file browser files
|
||||||
|
$~
|
||||||
|
.idea/
|
||||||
|
.directory
|
||||||
|
.cache/
|
||||||
|
settings.json
|
||||||
|
|
||||||
|
# temporary data
|
||||||
|
temp
|
||||||
|
|
||||||
|
# packaging and testing
|
||||||
|
.tox/
|
||||||
|
*.egg-info/
|
||||||
|
.eggs/
|
||||||
|
*.egg
|
||||||
|
build/
|
||||||
|
dist/
|
||||||
|
.coverage
|
||||||
|
src/escpos/version.py
|
||||||
|
.hypothesis
|
||||||
|
.pytest_cache/
|
||||||
|
coverage.xml
|
||||||
|
|
||||||
|
# pyenv
|
||||||
|
.python-version
|
||||||
|
|
||||||
|
# testing temporary directories
|
||||||
|
test/test-cli-output/
|
||||||
|
|
||||||
|
# vim swap files
|
||||||
|
*.swp
|
||||||
|
*.swn
|
||||||
|
*.swo
|
||||||
|
|
||||||
|
# vscode
|
||||||
|
.vscode/*
|
||||||
|
!.vscode/settings.json
|
||||||
|
!.vscode/tasks.json
|
||||||
|
!.vscode/launch.json
|
||||||
|
!.vscode/extensions.json
|
||||||
|
|
4
.gitmodules
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
[submodule "capabilities-data"]
|
||||||
|
path = capabilities-data
|
||||||
|
url = https://github.com/receipt-print-hq/escpos-printer-db.git
|
||||||
|
branch = master
|
10
.hgignore
@@ -1,10 +0,0 @@
|
|||||||
# python temporary files
|
|
||||||
syntax: glob
|
|
||||||
*.pyc
|
|
||||||
|
|
||||||
# editor autosaves
|
|
||||||
$~
|
|
||||||
|
|
||||||
# temporary data
|
|
||||||
syntax: regexp
|
|
||||||
temp
|
|
20
.mailmap
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
<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>
|
||||||
|
Juanmi Taboada <juanmi@juanmitaboada.com> Juanmi Taboada <juanmi@juanmitaboada.com>
|
||||||
|
csoft2k <csoft2k@hotmail.com>
|
||||||
|
Sergio Pulgarin <sergio.pulgarin@gmail.com>
|
||||||
|
reck31 <rakesh.gunduka@gmail.com>
|
||||||
|
Alex Debiasio <alex.debiasio@thinkin.io> <alex.debiasio@studenti.unitn.it>
|
||||||
|
白月秋见心 <ourweijiang@gmail.com>
|
||||||
|
Maximilian Wagenbach <maximilian.wagenbach@native-instruments.de>
|
||||||
|
<belono@users.noreply.github.com> <tiotil.lindeman@gmail.com>
|
||||||
|
belono <belono@users.noreply.github.com> Benito López <belono@users.noreply.github.com>
|
||||||
|
Alfredo Orozco <alfredoopa@gmail.com> Alfredo orozco <alfreedom@users.noreply.github.com>
|
27
.readthedocs.yml
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
version: 2
|
||||||
|
formats:
|
||||||
|
- epub
|
||||||
|
- pdf
|
||||||
|
build:
|
||||||
|
os: ubuntu-22.04
|
||||||
|
tools:
|
||||||
|
python: "3.11"
|
||||||
|
apt_packages:
|
||||||
|
- graphviz
|
||||||
|
- libenchant-2-2
|
||||||
|
- gcc
|
||||||
|
- libcups2-dev
|
||||||
|
- python3-dev
|
||||||
|
- xindy
|
||||||
|
sphinx:
|
||||||
|
configuration: doc/conf.py
|
||||||
|
submodules:
|
||||||
|
include:
|
||||||
|
- capabilities-data
|
||||||
|
recursive: true
|
||||||
|
|
||||||
|
python:
|
||||||
|
install:
|
||||||
|
- requirements: doc/requirements.txt
|
||||||
|
- method: pip
|
||||||
|
path: .
|
19
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
{
|
||||||
|
"esbonio.sphinx.confDir": "${workspaceFolder}/doc",
|
||||||
|
"files.watcherExclude": {
|
||||||
|
"**/.git/objects/**": true,
|
||||||
|
"**/.git/subtree-cache/**": true,
|
||||||
|
"**/node_modules/*/**": true,
|
||||||
|
"**/.eggs/**": true,
|
||||||
|
"**/.hypothesis/**": true,
|
||||||
|
"**/.tox/**": true,
|
||||||
|
},
|
||||||
|
"editor.formatOnSave": true,
|
||||||
|
"editor.formatOnPaste": true,
|
||||||
|
"python.formatting.provider": "black",
|
||||||
|
"editor.codeActionsOnSave": {
|
||||||
|
"source.organizeImports": true
|
||||||
|
},
|
||||||
|
"python.testing.unittestEnabled": false,
|
||||||
|
"python.testing.pytestEnabled": true,
|
||||||
|
}
|
16
.vscode/tasks.json
vendored
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
// See https://go.microsoft.com/fwlink/?LinkId=733558
|
||||||
|
// for the documentation about the tasks.json format
|
||||||
|
"version": "2.0.0",
|
||||||
|
"tasks": [
|
||||||
|
{
|
||||||
|
"label": "test with tox",
|
||||||
|
"type": "shell",
|
||||||
|
"command": "tox",
|
||||||
|
"group": {
|
||||||
|
"kind": "test",
|
||||||
|
"isDefault": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
54
AUTHORS
Normal file
@@ -0,0 +1,54 @@
|
|||||||
|
Ahmed Tahri
|
||||||
|
akeonly
|
||||||
|
Alejandro Hernández
|
||||||
|
Alexander Bougakov
|
||||||
|
Alexandre Detiste
|
||||||
|
Alex Debiasio
|
||||||
|
Alfredo Orozco
|
||||||
|
Asuki Kono
|
||||||
|
belono
|
||||||
|
B. Howell
|
||||||
|
Brian
|
||||||
|
Christoph Heuel
|
||||||
|
Cody (Quantified Code Bot)
|
||||||
|
csoft2k
|
||||||
|
Curtis // mashedkeyboard
|
||||||
|
Davis Goglin
|
||||||
|
Dean Rispin
|
||||||
|
dependabot[bot]
|
||||||
|
Dmytro Katyukha
|
||||||
|
Florent de Labarre
|
||||||
|
Gerard Marull-Paretas
|
||||||
|
Hark
|
||||||
|
Joel Lehtonen
|
||||||
|
Justin Vieira
|
||||||
|
kennedy
|
||||||
|
Kristi
|
||||||
|
ldos
|
||||||
|
Lucy Linder
|
||||||
|
Manuel F Martinez
|
||||||
|
Mathieu Poussin
|
||||||
|
Maximilian Wagenbach
|
||||||
|
Michael Billington
|
||||||
|
Michael Elsdörfer
|
||||||
|
mrwunderbar666
|
||||||
|
Nathan Bookham
|
||||||
|
Omer Akram
|
||||||
|
Patrick Kanzler
|
||||||
|
primax79
|
||||||
|
Qian Linfeng
|
||||||
|
Ramon Poca
|
||||||
|
reck31
|
||||||
|
Renato Lorenzi
|
||||||
|
Ricardo Sánchez Alba
|
||||||
|
Romain Porte
|
||||||
|
Sam Cheng
|
||||||
|
Sergio Pulgarin
|
||||||
|
Stephan Sokolow
|
||||||
|
Thijs Triemstra
|
||||||
|
Thomas van den Berg
|
||||||
|
tuxmaster
|
||||||
|
vendryan
|
||||||
|
Yaisel Hurtado
|
||||||
|
ysuolmai
|
||||||
|
白月秋见心
|
37
CHANGELOG
@@ -1,37 +0,0 @@
|
|||||||
CHANGELOG
|
|
||||||
|
|
||||||
* 2012-11-15 - Version 1.0
|
|
||||||
- Issue #2: Added ethernet support
|
|
||||||
- Issue #3: Added compatibility with libusb-1.0.1
|
|
||||||
- Issue #4: Fixed typo in escpos.py
|
|
||||||
|
|
||||||
* 2013-03-14 - Version 1.0.1
|
|
||||||
- Issue #8: Fixed set font
|
|
||||||
- Added QR support
|
|
||||||
|
|
||||||
* 2013-12-30 - Version 1.0.2
|
|
||||||
- Issue #5: Fixed vertical tab
|
|
||||||
- Issue #9: Fixed identation inconsistence
|
|
||||||
|
|
||||||
* 2014-02-23 - Version 1.0.3
|
|
||||||
- Issue #18: Added quad-area characters (Sent by syncman1x@gmail.com)
|
|
||||||
- Added exception for PIL import
|
|
||||||
|
|
||||||
* 2014-05-20 - Version 1.0.4
|
|
||||||
- Issue #20: Added Density support (Sent by thomas.erbacher@ragapack.de)
|
|
||||||
- Added charcode tables
|
|
||||||
- Fixed Horizontal Tab
|
|
||||||
- Fixed code tabulators
|
|
||||||
|
|
||||||
* 2015-04-21 - Version 1.0.5
|
|
||||||
- Merge pull request #45 from Krispy2009/master
|
|
||||||
. Raising the right error when wrong charcode is used
|
|
||||||
. Sent by Krispy2009@gmail.com
|
|
||||||
|
|
||||||
* 2015-07-06 - Version 1.0.6
|
|
||||||
- Merge pull request #53 from ldos/master
|
|
||||||
. Extended params for serial printers
|
|
||||||
. Sent by cafeteria.ldosalzira@gmail.com
|
|
||||||
|
|
||||||
* 2015-08-22 - Version 1.0.7
|
|
||||||
- Issue #57: Fixed transparent images
|
|
511
CHANGELOG.rst
Normal file
@@ -0,0 +1,511 @@
|
|||||||
|
Changelog
|
||||||
|
=========
|
||||||
|
|
||||||
|
2023-12-17 - Version 3.1 - "Rubric Of Ruin"
|
||||||
|
-------------------------------------------
|
||||||
|
This is the minor release of the new version 3.1.
|
||||||
|
It adds a modification of the API of the qr-method,
|
||||||
|
hence the minor release.
|
||||||
|
|
||||||
|
changes
|
||||||
|
^^^^^^^
|
||||||
|
- extend API of the qr-method to allow passing image
|
||||||
|
parameters in non-native mode
|
||||||
|
- use version 0.15 and upwards of python-barcode
|
||||||
|
- fix an issue in the config provider that prevented
|
||||||
|
config files to be found when only a path was supplied
|
||||||
|
- Improve type annotations, usage of six and other
|
||||||
|
packaging relevant parts.
|
||||||
|
|
||||||
|
contributors
|
||||||
|
^^^^^^^^^^^^
|
||||||
|
- Patrick Kanzler
|
||||||
|
- Alexandre Detiste
|
||||||
|
- tuxmaster
|
||||||
|
- belono
|
||||||
|
|
||||||
|
|
||||||
|
2023-11-17 - Version 3.0 - "Quietly Confident"
|
||||||
|
----------------------------------------------
|
||||||
|
This is the major release of the new version 3.0.
|
||||||
|
A big thank you to @belono for their many contributions
|
||||||
|
for the finalization of v3!
|
||||||
|
|
||||||
|
The third major release of this library drops support for
|
||||||
|
Python 2 and requires a Python version of at least 3.8.
|
||||||
|
The API has been reworked to be more consistent and two
|
||||||
|
new concepts have been introduced:
|
||||||
|
|
||||||
|
`Capabilities` allow the library to know which features
|
||||||
|
the currently used printer implements and send fitting
|
||||||
|
commands.
|
||||||
|
`Magic Encode` is a new feature that uses the
|
||||||
|
capability information and encodes Unicode automatically
|
||||||
|
with the correct code page while sending also the
|
||||||
|
code page change commands.
|
||||||
|
|
||||||
|
The license of the project has been changed to MIT
|
||||||
|
in accordance with its contributors.
|
||||||
|
|
||||||
|
The changes listed here are a summary of the changes
|
||||||
|
of the previous alpha releases. For details please
|
||||||
|
read the changelog of the alpha releases.
|
||||||
|
|
||||||
|
|
||||||
|
changes
|
||||||
|
^^^^^^^
|
||||||
|
- change the project's license to MIT in accordance with the contributors (see python-escpos/python-escpos#171)
|
||||||
|
- feature: add "capabilities" which are shared with escpos-php, capabilities are stored in
|
||||||
|
`escpos-printer-db <https://github.com/receipt-print-hq/escpos-printer-db>`_
|
||||||
|
- feature: the driver tries now to guess the appropriate codepage and sets it automatically (called "magic encode")
|
||||||
|
- as an alternative you can force the codepage with the old API
|
||||||
|
- fix the encoding search so that lower encodings are found first
|
||||||
|
- automatically handle cases where full cut or partial cut is not available
|
||||||
|
- refactor of the set-method
|
||||||
|
- preliminary support of POS "line display" printing
|
||||||
|
- add support for software-based barcode-rendering
|
||||||
|
- make feed for cut optional
|
||||||
|
- implemented paper sensor querying command
|
||||||
|
- Include support for CUPS based printer interfaces
|
||||||
|
- add Win32Raw-Printer on Windows-platforms
|
||||||
|
- add and improve Windows support of USB-class
|
||||||
|
- pickle capabilities for faster startup
|
||||||
|
|
||||||
|
contributors
|
||||||
|
^^^^^^^^^^^^
|
||||||
|
This is a list of contributors since the last v2 release.
|
||||||
|
|
||||||
|
- Ahmed Tahri
|
||||||
|
- akeonly
|
||||||
|
- Alexander Bougakov
|
||||||
|
- AlexandroJaez
|
||||||
|
- Asuki Kono
|
||||||
|
- belono
|
||||||
|
- brendanhowell
|
||||||
|
- Brian
|
||||||
|
- Christoph Heuel
|
||||||
|
- csoft2k
|
||||||
|
- Curtis // mashedkeyboard
|
||||||
|
- Dmytro Katyukha
|
||||||
|
- Foaly
|
||||||
|
- Gerard Marull-Paretas
|
||||||
|
- Justin Vieira
|
||||||
|
- kedare
|
||||||
|
- kennedy
|
||||||
|
- Lucy Linder
|
||||||
|
- Maximilian Wagenbach
|
||||||
|
- Michael Billington
|
||||||
|
- Michael Elsdörfer
|
||||||
|
- mrwunderbar666
|
||||||
|
- NullYing
|
||||||
|
- Omer Akram
|
||||||
|
- Patrick Kanzler
|
||||||
|
- primax79
|
||||||
|
- Ramon Poca
|
||||||
|
- reck31
|
||||||
|
- Romain Porte
|
||||||
|
- Sam Cheng
|
||||||
|
- Scott Rotondo
|
||||||
|
- Sergio Pulgarin
|
||||||
|
- Thijs Triemstra
|
||||||
|
- Yaisel Hurtado
|
||||||
|
- ysuolmai
|
||||||
|
|
||||||
|
and others
|
||||||
|
|
||||||
|
2023-05-11 - Version 3.0a9 - "Pride Comes Before A Fall"
|
||||||
|
--------------------------------------------------------
|
||||||
|
This release is the 10th alpha release of the new version 3.0.
|
||||||
|
After three years hiatus, a new release is in work in order to
|
||||||
|
finally get a version 3.0 out.
|
||||||
|
|
||||||
|
changes
|
||||||
|
^^^^^^^
|
||||||
|
- Include support for CUPS based printer interfaces
|
||||||
|
- Move the build tool chain to GitHub
|
||||||
|
|
||||||
|
contributors
|
||||||
|
^^^^^^^^^^^^
|
||||||
|
- belono
|
||||||
|
- brendanhowell
|
||||||
|
- AlexandroJaez
|
||||||
|
- NullYing
|
||||||
|
- kedare
|
||||||
|
- Foaly
|
||||||
|
- patkan
|
||||||
|
- and others
|
||||||
|
|
||||||
|
2020-05-12 - Version 3.0a8 - "Only Slightly Bent"
|
||||||
|
-------------------------------------------------
|
||||||
|
This release is the ninth alpha release of the new version 3.0.
|
||||||
|
Please be aware that the API is subject to change until v3.0 is
|
||||||
|
released.
|
||||||
|
|
||||||
|
This release drops support for Python 2, requiring at least
|
||||||
|
version 3.5 of Python.
|
||||||
|
|
||||||
|
changes
|
||||||
|
^^^^^^^
|
||||||
|
- Drop support for Python 2 and mark in setuptools as only supporting 3.5 and upwards
|
||||||
|
- remove landscape.io badge
|
||||||
|
- replace viivakoodi with python-barcode which is maintained
|
||||||
|
- add configuration for Visual Studio Code
|
||||||
|
- use pkg_resources for the retrieval of the capabilities.json
|
||||||
|
|
||||||
|
contributors
|
||||||
|
^^^^^^^^^^^^
|
||||||
|
- Romain Porte
|
||||||
|
- Patrick Kanzler
|
||||||
|
|
||||||
|
2020-05-09 - Version 3.0a7 - "No Fixed Abode"
|
||||||
|
---------------------------------------------
|
||||||
|
This release is the eight alpha release of the new version 3.0.
|
||||||
|
Please be aware that the API is subject to change until v3.0
|
||||||
|
is released.
|
||||||
|
|
||||||
|
This release also marks the point at which the project transitioned
|
||||||
|
to having only a master-branch (and not an additional development branch).
|
||||||
|
|
||||||
|
changes
|
||||||
|
^^^^^^^
|
||||||
|
- add Exception for NotImplementedError in detach_kernel_driver
|
||||||
|
- update installation information
|
||||||
|
- update and improve documentation
|
||||||
|
- add error handling to image centering flag
|
||||||
|
- update and fix tox and CI environment, preparing drop of support for Python 2
|
||||||
|
|
||||||
|
contributors
|
||||||
|
^^^^^^^^^^^^
|
||||||
|
- Alexander Bougakov
|
||||||
|
- Brian
|
||||||
|
- Yaisel Hurtado
|
||||||
|
- Maximilian Wagenbach
|
||||||
|
- Patrick Kanzler
|
||||||
|
|
||||||
|
2019-06-19 - Version 3.0a6 - "Mistake not..."
|
||||||
|
---------------------------------------------
|
||||||
|
This release is the seventh alpha release of the new version 3.0.
|
||||||
|
Please be aware that the API is subject to change until v3.0 is
|
||||||
|
released.
|
||||||
|
|
||||||
|
changes
|
||||||
|
^^^^^^^
|
||||||
|
- fix inclusion of the capabilities-file
|
||||||
|
- execute CI jobs also on Windows and MacOS-targets
|
||||||
|
- improve documentation
|
||||||
|
|
||||||
|
contributors
|
||||||
|
^^^^^^^^^^^^
|
||||||
|
- Patrick Kanzler
|
||||||
|
|
||||||
|
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"
|
||||||
|
------------------------------------------
|
||||||
|
This release is the fifth alpha release of the new version 3.0. Please
|
||||||
|
be aware that the API will still change until v3.0 is released.
|
||||||
|
|
||||||
|
changes
|
||||||
|
^^^^^^^
|
||||||
|
- raise exception when TypeError occurs in cashdraw (#268)
|
||||||
|
- Feature/clear content in dummy printer (#271)
|
||||||
|
- fix is_online() (#282)
|
||||||
|
- improve documentation
|
||||||
|
- Modified submodule to always pull from master branch (#283)
|
||||||
|
- parameter for implementation of nonnative qrcode (#289)
|
||||||
|
- improve platform independence (#296)
|
||||||
|
|
||||||
|
contributors
|
||||||
|
^^^^^^^^^^^^
|
||||||
|
- Christoph Heuel
|
||||||
|
- Patrick Kanzler
|
||||||
|
- kennedy
|
||||||
|
- primax79
|
||||||
|
- reck31
|
||||||
|
- Thijs Triemstra
|
||||||
|
|
||||||
|
2017-10-08 - Version 3.0a3 - "Just Testing"
|
||||||
|
-------------------------------------------
|
||||||
|
This release is the fourth alpha release of the new version 3.0. Please
|
||||||
|
be aware that the API will still change until v3.0 is released.
|
||||||
|
|
||||||
|
changes
|
||||||
|
^^^^^^^
|
||||||
|
- minor changes in documentation, tests and examples
|
||||||
|
- pickle capabilities for faster startup
|
||||||
|
- first implementation of centering images and QR
|
||||||
|
- check barcodes based on regex
|
||||||
|
|
||||||
|
contributors
|
||||||
|
^^^^^^^^^^^^
|
||||||
|
- Patrick Kanzler
|
||||||
|
- Lucy Linder
|
||||||
|
- Romain Porte
|
||||||
|
- Sergio Pulgarin
|
||||||
|
|
||||||
|
2017-08-04 - Version 3.0a2 - "It's My Party And I'll Sing If I Want To"
|
||||||
|
-----------------------------------------------------------------------
|
||||||
|
This release is the third alpha release of the new version 3.0. Please
|
||||||
|
be aware that the API will still change until v3.0 is released.
|
||||||
|
|
||||||
|
changes
|
||||||
|
^^^^^^^
|
||||||
|
- refactor of the set-method
|
||||||
|
- preliminary support of POS "line display" printing
|
||||||
|
- improvement of tests
|
||||||
|
- added ImageWidthError
|
||||||
|
- list authors in repository
|
||||||
|
- add support for software-based barcode-rendering
|
||||||
|
- fix SerialException when trying to close device on __del__
|
||||||
|
- added the DLE EOT querying command for USB and Serial
|
||||||
|
- ensure QR codes have a large enough border
|
||||||
|
- make feed for cut optional
|
||||||
|
- fix the behavior of horizontal tabs
|
||||||
|
- added test script for hard an soft barcodes
|
||||||
|
- implemented paper sensor querying command
|
||||||
|
- added weather forecast example script
|
||||||
|
- added a method for simpler newlines
|
||||||
|
|
||||||
|
contributors
|
||||||
|
^^^^^^^^^^^^
|
||||||
|
- csoft2k
|
||||||
|
- Patrick Kanzler
|
||||||
|
- mrwunderbar666
|
||||||
|
- Romain Porte
|
||||||
|
- Ahmed Tahri
|
||||||
|
|
||||||
|
2017-03-29 - Version 3.0a1 - "Headcrash"
|
||||||
|
----------------------------------------
|
||||||
|
This release is the second alpha release of the new version 3.0. Please
|
||||||
|
be aware that the API will still change until v3.0 is released.
|
||||||
|
|
||||||
|
changes
|
||||||
|
^^^^^^^
|
||||||
|
- automatically upload releases to GitHub
|
||||||
|
- add environment variable ESCPOS_CAPABILITIES_FILE
|
||||||
|
- automatically handle cases where full cut or partial cut is not available
|
||||||
|
- add print_and_feed
|
||||||
|
|
||||||
|
contributors
|
||||||
|
^^^^^^^^^^^^
|
||||||
|
- Sam Cheng
|
||||||
|
- Patrick Kanzler
|
||||||
|
- Dmytro Katyukha
|
||||||
|
|
||||||
|
2017-01-31 - Version 3.0a - "Grey Area"
|
||||||
|
---------------------------------------
|
||||||
|
This release is the first alpha release of the new version 3.0. Please
|
||||||
|
be aware that the API will still change until v3.0 is released.
|
||||||
|
|
||||||
|
changes
|
||||||
|
^^^^^^^
|
||||||
|
- change the project's license to MIT in accordance with the contributors (see python-escpos/python-escpos#171)
|
||||||
|
- feature: add "capabilities" which are shared with escpos-php, capabilities are stored in
|
||||||
|
`escpos-printer-db <https://github.com/receipt-print-hq/escpos-printer-db>`_
|
||||||
|
- feature: the driver tries now to guess the appropriate codepage and sets it automatically (called "magic encode")
|
||||||
|
- as an alternative you can force the codepage with the old API
|
||||||
|
- updated and improved documentation
|
||||||
|
- changed constructor of main class due to introduction of capabilities
|
||||||
|
- changed interface of method `blocktext`, changed behavior of multiple methods, for details refer to the documentation
|
||||||
|
on `python-escpos.readthedocs.io <https://python-escpos.readthedocs.io>`_
|
||||||
|
- add support for custom cash drawer sequence
|
||||||
|
- enforce flake8 on the src-files, test py36 and py37 on travis
|
||||||
|
|
||||||
|
contributors
|
||||||
|
^^^^^^^^^^^^
|
||||||
|
- Michael Billington
|
||||||
|
- Michael Elsdörfer
|
||||||
|
- Patrick Kanzler (with code by Frédéric Van der Essen)
|
||||||
|
- Asuki Kono
|
||||||
|
- Benito López
|
||||||
|
- Curtis // mashedkeyboard
|
||||||
|
- Thijs Triemstra
|
||||||
|
- ysuolmai
|
||||||
|
|
||||||
|
2016-08-26 - Version 2.2.0 - "Fate Amenable To Change"
|
||||||
|
------------------------------------------------------
|
||||||
|
|
||||||
|
changes
|
||||||
|
^^^^^^^
|
||||||
|
- fix improper API-use in qrcode()
|
||||||
|
- change setup.py shebang to make it compatible with virtualenvs.
|
||||||
|
- add constants for sheet mode and colors
|
||||||
|
- support changing the line spacing
|
||||||
|
|
||||||
|
contributors
|
||||||
|
^^^^^^^^^^^^
|
||||||
|
- Michael Elsdörfer
|
||||||
|
- Patrick Kanzler
|
||||||
|
|
||||||
|
2016-08-10 - Version 2.1.3 - "Ethics Gradient"
|
||||||
|
----------------------------------------------
|
||||||
|
|
||||||
|
changes
|
||||||
|
^^^^^^^
|
||||||
|
- configure readthedocs and travis
|
||||||
|
- update doc with hint on image preprocessing
|
||||||
|
- add fix for printing large images (by splitting them into multiple images)
|
||||||
|
|
||||||
|
contributors
|
||||||
|
^^^^^^^^^^^^
|
||||||
|
- Patrick Kanzler
|
||||||
|
|
||||||
|
2016-08-02 - Version 2.1.2 - "Death and Gravity"
|
||||||
|
------------------------------------------------
|
||||||
|
|
||||||
|
changes
|
||||||
|
^^^^^^^
|
||||||
|
- fix File-printer: flush after every call of _raw()
|
||||||
|
- fix lists in documentation
|
||||||
|
- fix CODE128: by adding the control character to the barcode-selection-sequence the barcode became unusable
|
||||||
|
|
||||||
|
contributors
|
||||||
|
^^^^^^^^^^^^
|
||||||
|
- Patrick Kanzler
|
||||||
|
|
||||||
|
2016-08-02 - Version 2.1.1 - "Contents May Differ"
|
||||||
|
--------------------------------------------------
|
||||||
|
|
||||||
|
changes
|
||||||
|
^^^^^^^
|
||||||
|
- rename variable interface in USB-class to timeout
|
||||||
|
- add support for hypothesis and move pypy3 to the allowed failures (pypy3 is not supported by hypothesis)
|
||||||
|
|
||||||
|
contributors
|
||||||
|
^^^^^^^^^^^^
|
||||||
|
- Patrick Kanzler
|
||||||
|
- Renato Lorenzi
|
||||||
|
|
||||||
|
2016-07-23 - Version 2.1.0 - "But Who's Counting?"
|
||||||
|
--------------------------------------------------
|
||||||
|
|
||||||
|
changes
|
||||||
|
^^^^^^^
|
||||||
|
- packaging: configured the coverage-analysis codecov.io
|
||||||
|
- GitHub: improved issues-template
|
||||||
|
- documentation: add troubleshooting tip to network-interface
|
||||||
|
- the module, CLI and documentation is now aware of the version of python-escpos
|
||||||
|
- the CLI does now support basic tab completion
|
||||||
|
|
||||||
|
contributors
|
||||||
|
^^^^^^^^^^^^
|
||||||
|
- Patrick Kanzler
|
||||||
|
|
||||||
|
2016-06-24 - Version 2.0.0 - "Attitude Adjuster"
|
||||||
|
------------------------------------------------
|
||||||
|
|
||||||
|
This version is based on the original version of python-escpos by Manuel F Martinez. However, many contributions have
|
||||||
|
greatly improved the old codebase. Since this version does not completely match the interface of the version published
|
||||||
|
on PyPi and has many improvements, it will be released as version 2.0.0.
|
||||||
|
|
||||||
|
changes
|
||||||
|
^^^^^^^
|
||||||
|
- refactor complete code in order to be compatible with Python 2 and 3
|
||||||
|
- modernize packaging
|
||||||
|
- add testing and CI
|
||||||
|
- merge various forks into codebase, fixing multiple issues with barcode-, QR-printing, cash-draw and structure
|
||||||
|
- improve the documentation
|
||||||
|
- extend support of barcode-codes to type B
|
||||||
|
- add function to disable panel-buttons
|
||||||
|
- the text-functions are now intended for unicode, the driver will automatically encode the string based on the selected
|
||||||
|
codepage
|
||||||
|
- the image-functions are now much more flexible
|
||||||
|
- added a CLI
|
||||||
|
- restructured the constants
|
||||||
|
|
||||||
|
contributors
|
||||||
|
^^^^^^^^^^^^
|
||||||
|
- Thomas van den Berg
|
||||||
|
- Michael Billington
|
||||||
|
- Nate Bookham
|
||||||
|
- Davis Goglin
|
||||||
|
- Christoph Heuel
|
||||||
|
- Patrick Kanzler
|
||||||
|
- Qian LinFeng
|
||||||
|
|
||||||
|
2016-01-24 - Version 1.0.9
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
- fix constant definition for PC1252
|
||||||
|
- move documentation to Sphinx
|
||||||
|
|
||||||
|
2015-10-27 - Version 1.0.8
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
- Merge pull request #59 from zouppen/master
|
||||||
|
- Support for images vertically longer than 256 pixels
|
||||||
|
- Sent by Joel Lehtonen <joel.lehtonen@koodilehto.fi>
|
||||||
|
- Updated README
|
||||||
|
|
||||||
|
2015-08-22 - Version 1.0.7
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
- Issue #57: Fixed transparent images
|
||||||
|
|
||||||
|
2015-07-06 - Version 1.0.6
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
- Merge pull request #53 from ldos/master
|
||||||
|
- Extended params for serial printers
|
||||||
|
- Sent by ldos <cafeteria.ldosalzira@gmail.com>
|
||||||
|
|
||||||
|
2015-04-21 - Version 1.0.5
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
- Merge pull request #45 from Krispy2009/master
|
||||||
|
- Raising the right error when wrong charcode is used
|
||||||
|
- Sent by Kristi <Krispy2009@gmail.com>
|
||||||
|
|
||||||
|
2014-05-20 - Version 1.0.4
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
- Issue #20: Added Density support (Sent by thomas.erbacher@ragapack.de)
|
||||||
|
- Added charcode tables
|
||||||
|
- Fixed Horizontal Tab
|
||||||
|
- Fixed code tabulators
|
||||||
|
|
||||||
|
2014-02-23 - Version 1.0.3
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
- Issue #18: Added quad-area characters (Sent by syncman1x@gmail.com)
|
||||||
|
- Added exception for PIL import
|
||||||
|
|
||||||
|
2013-12-30 - Version 1.0.2
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
- Issue #5: Fixed vertical tab
|
||||||
|
- Issue #9: Fixed indentation inconsistency
|
||||||
|
|
||||||
|
2013-03-14 - Version 1.0.1
|
||||||
|
--------------------------
|
||||||
|
|
||||||
|
- Issue #8: Fixed set font
|
||||||
|
- Added QR support
|
||||||
|
|
||||||
|
2012-11-15 - Version 1.0
|
||||||
|
------------------------
|
||||||
|
|
||||||
|
- Issue #2: Added Ethernet support
|
||||||
|
- Issue #3: Added compatibility with libusb-1.0.1
|
||||||
|
- Issue #4: Fixed typo in escpos.py
|
84
CONTRIBUTING.rst
Normal file
@@ -0,0 +1,84 @@
|
|||||||
|
Contributing
|
||||||
|
============
|
||||||
|
|
||||||
|
:Last Reviewed: 2023-08-10
|
||||||
|
|
||||||
|
This project is open to any kind of contribution.
|
||||||
|
You can help with improving the documentation, adding fixes to the
|
||||||
|
code, providing test cases in code or as a description or just
|
||||||
|
spreading the word.
|
||||||
|
Please feel free to create an issue or pull request.
|
||||||
|
In order to reduce the amount of work for everyone please try
|
||||||
|
to adhere to good practice.
|
||||||
|
|
||||||
|
The pull requests and issues will be prefilled with templates.
|
||||||
|
Please fill in your information where applicable.
|
||||||
|
|
||||||
|
This project uses `semantic versioning <https://semver.org/>`_
|
||||||
|
and tries to adhere to the proposed rules as 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.
|
||||||
|
|
||||||
|
When you change your username or mail-address, please also
|
||||||
|
update the `.mailmap` and the authors-list.
|
||||||
|
You can find a good documentation on the mapping-feature in the
|
||||||
|
`documentation of git-shortlog <https://git-scm.com/docs/git-shortlog#_mapping_authors>`_.
|
||||||
|
|
||||||
|
Style-Guide
|
||||||
|
-----------
|
||||||
|
|
||||||
|
When writing code please try to stick to these rules.
|
||||||
|
|
||||||
|
Black Code Style
|
||||||
|
^^^^^^^^^^^^^^^^
|
||||||
|
This project is formatted with the auto formatter `black <https://github.com/psf/black>`_.
|
||||||
|
Please format your contributions with black, otherwise they will be rejected.
|
||||||
|
|
||||||
|
GIT
|
||||||
|
^^^
|
||||||
|
The master-branch contains the main development of the project.
|
||||||
|
A release to PyPi is marked with a tag corresponding to the version.
|
||||||
|
Issues are closed when they have been resolved by merging
|
||||||
|
into the master-branch.
|
||||||
|
When you have a change to make, begin by creating a new branch
|
||||||
|
from the HEAD of `python-escpos/master`.
|
||||||
|
|
||||||
|
Please try to group your commits into logical units.
|
||||||
|
If you need to tidy up your branch, you can make use of a
|
||||||
|
git feature called an 'interactive rebase' before making a pull request.
|
||||||
|
A small, self-contained change-set is easier to review, and
|
||||||
|
improves the chance of your code being merged.
|
||||||
|
Please also make sure that before creating your PR, your branch
|
||||||
|
is rebased on a recent commit or you merged a recent
|
||||||
|
commit into your branch.
|
||||||
|
This way you can ensure that your PR is without merge conflicts.
|
||||||
|
|
||||||
|
Docstrings
|
||||||
|
^^^^^^^^^^
|
||||||
|
This project tries to have a good documentation.
|
||||||
|
Please add a docstring to every method and class.
|
||||||
|
Have a look at existing methods and classes for the style.
|
||||||
|
We use basically standard rst-docstrings for Sphinx.
|
||||||
|
|
||||||
|
Test
|
||||||
|
^^^^
|
||||||
|
Try to write tests whenever possible.
|
||||||
|
Our goal for the future is 100% coverage.
|
||||||
|
You can copy the structure from other testcases.
|
||||||
|
Please remember to adapt the docstrings.
|
||||||
|
|
||||||
|
Further reading
|
||||||
|
^^^^^^^^^^^^^^^
|
||||||
|
For further best practices and hints on contributing please see the
|
||||||
|
`contribution-guide <https://www.contribution-guide.org/>`_.
|
||||||
|
Should there be any contradictions between this guide
|
||||||
|
and the linked one, please stick to this text.
|
||||||
|
Aside from that feel free to create an issue or write an email if anything is unclear.
|
||||||
|
|
||||||
|
Thank you for your contribution!
|
674
COPYING
@@ -1,674 +0,0 @@
|
|||||||
GNU GENERAL PUBLIC LICENSE
|
|
||||||
Version 3, 29 June 2007
|
|
||||||
|
|
||||||
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
|
||||||
Everyone is permitted to copy and distribute verbatim copies
|
|
||||||
of this license document, but changing it is not allowed.
|
|
||||||
|
|
||||||
Preamble
|
|
||||||
|
|
||||||
The GNU General Public License is a free, copyleft license for
|
|
||||||
software and other kinds of works.
|
|
||||||
|
|
||||||
The licenses for most software and other practical works are designed
|
|
||||||
to take away your freedom to share and change the works. By contrast,
|
|
||||||
the GNU General Public License is intended to guarantee your freedom to
|
|
||||||
share and change all versions of a program--to make sure it remains free
|
|
||||||
software for all its users. We, the Free Software Foundation, use the
|
|
||||||
GNU General Public License for most of our software; it applies also to
|
|
||||||
any other work released this way by its authors. You can apply it to
|
|
||||||
your programs, too.
|
|
||||||
|
|
||||||
When we speak of free software, we are referring to freedom, not
|
|
||||||
price. Our General Public Licenses are designed to make sure that you
|
|
||||||
have the freedom to distribute copies of free software (and charge for
|
|
||||||
them if you wish), that you receive source code or can get it if you
|
|
||||||
want it, that you can change the software or use pieces of it in new
|
|
||||||
free programs, and that you know you can do these things.
|
|
||||||
|
|
||||||
To protect your rights, we need to prevent others from denying you
|
|
||||||
these rights or asking you to surrender the rights. Therefore, you have
|
|
||||||
certain responsibilities if you distribute copies of the software, or if
|
|
||||||
you modify it: responsibilities to respect the freedom of others.
|
|
||||||
|
|
||||||
For example, if you distribute copies of such a program, whether
|
|
||||||
gratis or for a fee, you must pass on to the recipients the same
|
|
||||||
freedoms that you received. You must make sure that they, too, receive
|
|
||||||
or can get the source code. And you must show them these terms so they
|
|
||||||
know their rights.
|
|
||||||
|
|
||||||
Developers that use the GNU GPL protect your rights with two steps:
|
|
||||||
(1) assert copyright on the software, and (2) offer you this License
|
|
||||||
giving you legal permission to copy, distribute and/or modify it.
|
|
||||||
|
|
||||||
For the developers' and authors' protection, the GPL clearly explains
|
|
||||||
that there is no warranty for this free software. For both users' and
|
|
||||||
authors' sake, the GPL requires that modified versions be marked as
|
|
||||||
changed, so that their problems will not be attributed erroneously to
|
|
||||||
authors of previous versions.
|
|
||||||
|
|
||||||
Some devices are designed to deny users access to install or run
|
|
||||||
modified versions of the software inside them, although the manufacturer
|
|
||||||
can do so. This is fundamentally incompatible with the aim of
|
|
||||||
protecting users' freedom to change the software. The systematic
|
|
||||||
pattern of such abuse occurs in the area of products for individuals to
|
|
||||||
use, which is precisely where it is most unacceptable. Therefore, we
|
|
||||||
have designed this version of the GPL to prohibit the practice for those
|
|
||||||
products. If such problems arise substantially in other domains, we
|
|
||||||
stand ready to extend this provision to those domains in future versions
|
|
||||||
of the GPL, as needed to protect the freedom of users.
|
|
||||||
|
|
||||||
Finally, every program is threatened constantly by software patents.
|
|
||||||
States should not allow patents to restrict development and use of
|
|
||||||
software on general-purpose computers, but in those that do, we wish to
|
|
||||||
avoid the special danger that patents applied to a free program could
|
|
||||||
make it effectively proprietary. To prevent this, the GPL assures that
|
|
||||||
patents cannot be used to render the program non-free.
|
|
||||||
|
|
||||||
The precise terms and conditions for copying, distribution and
|
|
||||||
modification follow.
|
|
||||||
|
|
||||||
TERMS AND CONDITIONS
|
|
||||||
|
|
||||||
0. Definitions.
|
|
||||||
|
|
||||||
"This License" refers to version 3 of the GNU General Public License.
|
|
||||||
|
|
||||||
"Copyright" also means copyright-like laws that apply to other kinds of
|
|
||||||
works, such as semiconductor masks.
|
|
||||||
|
|
||||||
"The Program" refers to any copyrightable work licensed under this
|
|
||||||
License. Each licensee is addressed as "you". "Licensees" and
|
|
||||||
"recipients" may be individuals or organizations.
|
|
||||||
|
|
||||||
To "modify" a work means to copy from or adapt all or part of the work
|
|
||||||
in a fashion requiring copyright permission, other than the making of an
|
|
||||||
exact copy. The resulting work is called a "modified version" of the
|
|
||||||
earlier work or a work "based on" the earlier work.
|
|
||||||
|
|
||||||
A "covered work" means either the unmodified Program or a work based
|
|
||||||
on the Program.
|
|
||||||
|
|
||||||
To "propagate" a work means to do anything with it that, without
|
|
||||||
permission, would make you directly or secondarily liable for
|
|
||||||
infringement under applicable copyright law, except executing it on a
|
|
||||||
computer or modifying a private copy. Propagation includes copying,
|
|
||||||
distribution (with or without modification), making available to the
|
|
||||||
public, and in some countries other activities as well.
|
|
||||||
|
|
||||||
To "convey" a work means any kind of propagation that enables other
|
|
||||||
parties to make or receive copies. Mere interaction with a user through
|
|
||||||
a computer network, with no transfer of a copy, is not conveying.
|
|
||||||
|
|
||||||
An interactive user interface displays "Appropriate Legal Notices"
|
|
||||||
to the extent that it includes a convenient and prominently visible
|
|
||||||
feature that (1) displays an appropriate copyright notice, and (2)
|
|
||||||
tells the user that there is no warranty for the work (except to the
|
|
||||||
extent that warranties are provided), that licensees may convey the
|
|
||||||
work under this License, and how to view a copy of this License. If
|
|
||||||
the interface presents a list of user commands or options, such as a
|
|
||||||
menu, a prominent item in the list meets this criterion.
|
|
||||||
|
|
||||||
1. Source Code.
|
|
||||||
|
|
||||||
The "source code" for a work means the preferred form of the work
|
|
||||||
for making modifications to it. "Object code" means any non-source
|
|
||||||
form of a work.
|
|
||||||
|
|
||||||
A "Standard Interface" means an interface that either is an official
|
|
||||||
standard defined by a recognized standards body, or, in the case of
|
|
||||||
interfaces specified for a particular programming language, one that
|
|
||||||
is widely used among developers working in that language.
|
|
||||||
|
|
||||||
The "System Libraries" of an executable work include anything, other
|
|
||||||
than the work as a whole, that (a) is included in the normal form of
|
|
||||||
packaging a Major Component, but which is not part of that Major
|
|
||||||
Component, and (b) serves only to enable use of the work with that
|
|
||||||
Major Component, or to implement a Standard Interface for which an
|
|
||||||
implementation is available to the public in source code form. A
|
|
||||||
"Major Component", in this context, means a major essential component
|
|
||||||
(kernel, window system, and so on) of the specific operating system
|
|
||||||
(if any) on which the executable work runs, or a compiler used to
|
|
||||||
produce the work, or an object code interpreter used to run it.
|
|
||||||
|
|
||||||
The "Corresponding Source" for a work in object code form means all
|
|
||||||
the source code needed to generate, install, and (for an executable
|
|
||||||
work) run the object code and to modify the work, including scripts to
|
|
||||||
control those activities. However, it does not include the work's
|
|
||||||
System Libraries, or general-purpose tools or generally available free
|
|
||||||
programs which are used unmodified in performing those activities but
|
|
||||||
which are not part of the work. For example, Corresponding Source
|
|
||||||
includes interface definition files associated with source files for
|
|
||||||
the work, and the source code for shared libraries and dynamically
|
|
||||||
linked subprograms that the work is specifically designed to require,
|
|
||||||
such as by intimate data communication or control flow between those
|
|
||||||
subprograms and other parts of the work.
|
|
||||||
|
|
||||||
The Corresponding Source need not include anything that users
|
|
||||||
can regenerate automatically from other parts of the Corresponding
|
|
||||||
Source.
|
|
||||||
|
|
||||||
The Corresponding Source for a work in source code form is that
|
|
||||||
same work.
|
|
||||||
|
|
||||||
2. Basic Permissions.
|
|
||||||
|
|
||||||
All rights granted under this License are granted for the term of
|
|
||||||
copyright on the Program, and are irrevocable provided the stated
|
|
||||||
conditions are met. This License explicitly affirms your unlimited
|
|
||||||
permission to run the unmodified Program. The output from running a
|
|
||||||
covered work is covered by this License only if the output, given its
|
|
||||||
content, constitutes a covered work. This License acknowledges your
|
|
||||||
rights of fair use or other equivalent, as provided by copyright law.
|
|
||||||
|
|
||||||
You may make, run and propagate covered works that you do not
|
|
||||||
convey, without conditions so long as your license otherwise remains
|
|
||||||
in force. You may convey covered works to others for the sole purpose
|
|
||||||
of having them make modifications exclusively for you, or provide you
|
|
||||||
with facilities for running those works, provided that you comply with
|
|
||||||
the terms of this License in conveying all material for which you do
|
|
||||||
not control copyright. Those thus making or running the covered works
|
|
||||||
for you must do so exclusively on your behalf, under your direction
|
|
||||||
and control, on terms that prohibit them from making any copies of
|
|
||||||
your copyrighted material outside their relationship with you.
|
|
||||||
|
|
||||||
Conveying under any other circumstances is permitted solely under
|
|
||||||
the conditions stated below. Sublicensing is not allowed; section 10
|
|
||||||
makes it unnecessary.
|
|
||||||
|
|
||||||
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
|
|
||||||
|
|
||||||
No covered work shall be deemed part of an effective technological
|
|
||||||
measure under any applicable law fulfilling obligations under article
|
|
||||||
11 of the WIPO copyright treaty adopted on 20 December 1996, or
|
|
||||||
similar laws prohibiting or restricting circumvention of such
|
|
||||||
measures.
|
|
||||||
|
|
||||||
When you convey a covered work, you waive any legal power to forbid
|
|
||||||
circumvention of technological measures to the extent such circumvention
|
|
||||||
is effected by exercising rights under this License with respect to
|
|
||||||
the covered work, and you disclaim any intention to limit operation or
|
|
||||||
modification of the work as a means of enforcing, against the work's
|
|
||||||
users, your or third parties' legal rights to forbid circumvention of
|
|
||||||
technological measures.
|
|
||||||
|
|
||||||
4. Conveying Verbatim Copies.
|
|
||||||
|
|
||||||
You may convey verbatim copies of the Program's source code as you
|
|
||||||
receive it, in any medium, provided that you conspicuously and
|
|
||||||
appropriately publish on each copy an appropriate copyright notice;
|
|
||||||
keep intact all notices stating that this License and any
|
|
||||||
non-permissive terms added in accord with section 7 apply to the code;
|
|
||||||
keep intact all notices of the absence of any warranty; and give all
|
|
||||||
recipients a copy of this License along with the Program.
|
|
||||||
|
|
||||||
You may charge any price or no price for each copy that you convey,
|
|
||||||
and you may offer support or warranty protection for a fee.
|
|
||||||
|
|
||||||
5. Conveying Modified Source Versions.
|
|
||||||
|
|
||||||
You may convey a work based on the Program, or the modifications to
|
|
||||||
produce it from the Program, in the form of source code under the
|
|
||||||
terms of section 4, provided that you also meet all of these conditions:
|
|
||||||
|
|
||||||
a) The work must carry prominent notices stating that you modified
|
|
||||||
it, and giving a relevant date.
|
|
||||||
|
|
||||||
b) The work must carry prominent notices stating that it is
|
|
||||||
released under this License and any conditions added under section
|
|
||||||
7. This requirement modifies the requirement in section 4 to
|
|
||||||
"keep intact all notices".
|
|
||||||
|
|
||||||
c) You must license the entire work, as a whole, under this
|
|
||||||
License to anyone who comes into possession of a copy. This
|
|
||||||
License will therefore apply, along with any applicable section 7
|
|
||||||
additional terms, to the whole of the work, and all its parts,
|
|
||||||
regardless of how they are packaged. This License gives no
|
|
||||||
permission to license the work in any other way, but it does not
|
|
||||||
invalidate such permission if you have separately received it.
|
|
||||||
|
|
||||||
d) If the work has interactive user interfaces, each must display
|
|
||||||
Appropriate Legal Notices; however, if the Program has interactive
|
|
||||||
interfaces that do not display Appropriate Legal Notices, your
|
|
||||||
work need not make them do so.
|
|
||||||
|
|
||||||
A compilation of a covered work with other separate and independent
|
|
||||||
works, which are not by their nature extensions of the covered work,
|
|
||||||
and which are not combined with it such as to form a larger program,
|
|
||||||
in or on a volume of a storage or distribution medium, is called an
|
|
||||||
"aggregate" if the compilation and its resulting copyright are not
|
|
||||||
used to limit the access or legal rights of the compilation's users
|
|
||||||
beyond what the individual works permit. Inclusion of a covered work
|
|
||||||
in an aggregate does not cause this License to apply to the other
|
|
||||||
parts of the aggregate.
|
|
||||||
|
|
||||||
6. Conveying Non-Source Forms.
|
|
||||||
|
|
||||||
You may convey a covered work in object code form under the terms
|
|
||||||
of sections 4 and 5, provided that you also convey the
|
|
||||||
machine-readable Corresponding Source under the terms of this License,
|
|
||||||
in one of these ways:
|
|
||||||
|
|
||||||
a) Convey the object code in, or embodied in, a physical product
|
|
||||||
(including a physical distribution medium), accompanied by the
|
|
||||||
Corresponding Source fixed on a durable physical medium
|
|
||||||
customarily used for software interchange.
|
|
||||||
|
|
||||||
b) Convey the object code in, or embodied in, a physical product
|
|
||||||
(including a physical distribution medium), accompanied by a
|
|
||||||
written offer, valid for at least three years and valid for as
|
|
||||||
long as you offer spare parts or customer support for that product
|
|
||||||
model, to give anyone who possesses the object code either (1) a
|
|
||||||
copy of the Corresponding Source for all the software in the
|
|
||||||
product that is covered by this License, on a durable physical
|
|
||||||
medium customarily used for software interchange, for a price no
|
|
||||||
more than your reasonable cost of physically performing this
|
|
||||||
conveying of source, or (2) access to copy the
|
|
||||||
Corresponding Source from a network server at no charge.
|
|
||||||
|
|
||||||
c) Convey individual copies of the object code with a copy of the
|
|
||||||
written offer to provide the Corresponding Source. This
|
|
||||||
alternative is allowed only occasionally and noncommercially, and
|
|
||||||
only if you received the object code with such an offer, in accord
|
|
||||||
with subsection 6b.
|
|
||||||
|
|
||||||
d) Convey the object code by offering access from a designated
|
|
||||||
place (gratis or for a charge), and offer equivalent access to the
|
|
||||||
Corresponding Source in the same way through the same place at no
|
|
||||||
further charge. You need not require recipients to copy the
|
|
||||||
Corresponding Source along with the object code. If the place to
|
|
||||||
copy the object code is a network server, the Corresponding Source
|
|
||||||
may be on a different server (operated by you or a third party)
|
|
||||||
that supports equivalent copying facilities, provided you maintain
|
|
||||||
clear directions next to the object code saying where to find the
|
|
||||||
Corresponding Source. Regardless of what server hosts the
|
|
||||||
Corresponding Source, you remain obligated to ensure that it is
|
|
||||||
available for as long as needed to satisfy these requirements.
|
|
||||||
|
|
||||||
e) Convey the object code using peer-to-peer transmission, provided
|
|
||||||
you inform other peers where the object code and Corresponding
|
|
||||||
Source of the work are being offered to the general public at no
|
|
||||||
charge under subsection 6d.
|
|
||||||
|
|
||||||
A separable portion of the object code, whose source code is excluded
|
|
||||||
from the Corresponding Source as a System Library, need not be
|
|
||||||
included in conveying the object code work.
|
|
||||||
|
|
||||||
A "User Product" is either (1) a "consumer product", which means any
|
|
||||||
tangible personal property which is normally used for personal, family,
|
|
||||||
or household purposes, or (2) anything designed or sold for incorporation
|
|
||||||
into a dwelling. In determining whether a product is a consumer product,
|
|
||||||
doubtful cases shall be resolved in favor of coverage. For a particular
|
|
||||||
product received by a particular user, "normally used" refers to a
|
|
||||||
typical or common use of that class of product, regardless of the status
|
|
||||||
of the particular user or of the way in which the particular user
|
|
||||||
actually uses, or expects or is expected to use, the product. A product
|
|
||||||
is a consumer product regardless of whether the product has substantial
|
|
||||||
commercial, industrial or non-consumer uses, unless such uses represent
|
|
||||||
the only significant mode of use of the product.
|
|
||||||
|
|
||||||
"Installation Information" for a User Product means any methods,
|
|
||||||
procedures, authorization keys, or other information required to install
|
|
||||||
and execute modified versions of a covered work in that User Product from
|
|
||||||
a modified version of its Corresponding Source. The information must
|
|
||||||
suffice to ensure that the continued functioning of the modified object
|
|
||||||
code is in no case prevented or interfered with solely because
|
|
||||||
modification has been made.
|
|
||||||
|
|
||||||
If you convey an object code work under this section in, or with, or
|
|
||||||
specifically for use in, a User Product, and the conveying occurs as
|
|
||||||
part of a transaction in which the right of possession and use of the
|
|
||||||
User Product is transferred to the recipient in perpetuity or for a
|
|
||||||
fixed term (regardless of how the transaction is characterized), the
|
|
||||||
Corresponding Source conveyed under this section must be accompanied
|
|
||||||
by the Installation Information. But this requirement does not apply
|
|
||||||
if neither you nor any third party retains the ability to install
|
|
||||||
modified object code on the User Product (for example, the work has
|
|
||||||
been installed in ROM).
|
|
||||||
|
|
||||||
The requirement to provide Installation Information does not include a
|
|
||||||
requirement to continue to provide support service, warranty, or updates
|
|
||||||
for a work that has been modified or installed by the recipient, or for
|
|
||||||
the User Product in which it has been modified or installed. Access to a
|
|
||||||
network may be denied when the modification itself materially and
|
|
||||||
adversely affects the operation of the network or violates the rules and
|
|
||||||
protocols for communication across the network.
|
|
||||||
|
|
||||||
Corresponding Source conveyed, and Installation Information provided,
|
|
||||||
in accord with this section must be in a format that is publicly
|
|
||||||
documented (and with an implementation available to the public in
|
|
||||||
source code form), and must require no special password or key for
|
|
||||||
unpacking, reading or copying.
|
|
||||||
|
|
||||||
7. Additional Terms.
|
|
||||||
|
|
||||||
"Additional permissions" are terms that supplement the terms of this
|
|
||||||
License by making exceptions from one or more of its conditions.
|
|
||||||
Additional permissions that are applicable to the entire Program shall
|
|
||||||
be treated as though they were included in this License, to the extent
|
|
||||||
that they are valid under applicable law. If additional permissions
|
|
||||||
apply only to part of the Program, that part may be used separately
|
|
||||||
under those permissions, but the entire Program remains governed by
|
|
||||||
this License without regard to the additional permissions.
|
|
||||||
|
|
||||||
When you convey a copy of a covered work, you may at your option
|
|
||||||
remove any additional permissions from that copy, or from any part of
|
|
||||||
it. (Additional permissions may be written to require their own
|
|
||||||
removal in certain cases when you modify the work.) You may place
|
|
||||||
additional permissions on material, added by you to a covered work,
|
|
||||||
for which you have or can give appropriate copyright permission.
|
|
||||||
|
|
||||||
Notwithstanding any other provision of this License, for material you
|
|
||||||
add to a covered work, you may (if authorized by the copyright holders of
|
|
||||||
that material) supplement the terms of this License with terms:
|
|
||||||
|
|
||||||
a) Disclaiming warranty or limiting liability differently from the
|
|
||||||
terms of sections 15 and 16 of this License; or
|
|
||||||
|
|
||||||
b) Requiring preservation of specified reasonable legal notices or
|
|
||||||
author attributions in that material or in the Appropriate Legal
|
|
||||||
Notices displayed by works containing it; or
|
|
||||||
|
|
||||||
c) Prohibiting misrepresentation of the origin of that material, or
|
|
||||||
requiring that modified versions of such material be marked in
|
|
||||||
reasonable ways as different from the original version; or
|
|
||||||
|
|
||||||
d) Limiting the use for publicity purposes of names of licensors or
|
|
||||||
authors of the material; or
|
|
||||||
|
|
||||||
e) Declining to grant rights under trademark law for use of some
|
|
||||||
trade names, trademarks, or service marks; or
|
|
||||||
|
|
||||||
f) Requiring indemnification of licensors and authors of that
|
|
||||||
material by anyone who conveys the material (or modified versions of
|
|
||||||
it) with contractual assumptions of liability to the recipient, for
|
|
||||||
any liability that these contractual assumptions directly impose on
|
|
||||||
those licensors and authors.
|
|
||||||
|
|
||||||
All other non-permissive additional terms are considered "further
|
|
||||||
restrictions" within the meaning of section 10. If the Program as you
|
|
||||||
received it, or any part of it, contains a notice stating that it is
|
|
||||||
governed by this License along with a term that is a further
|
|
||||||
restriction, you may remove that term. If a license document contains
|
|
||||||
a further restriction but permits relicensing or conveying under this
|
|
||||||
License, you may add to a covered work material governed by the terms
|
|
||||||
of that license document, provided that the further restriction does
|
|
||||||
not survive such relicensing or conveying.
|
|
||||||
|
|
||||||
If you add terms to a covered work in accord with this section, you
|
|
||||||
must place, in the relevant source files, a statement of the
|
|
||||||
additional terms that apply to those files, or a notice indicating
|
|
||||||
where to find the applicable terms.
|
|
||||||
|
|
||||||
Additional terms, permissive or non-permissive, may be stated in the
|
|
||||||
form of a separately written license, or stated as exceptions;
|
|
||||||
the above requirements apply either way.
|
|
||||||
|
|
||||||
8. Termination.
|
|
||||||
|
|
||||||
You may not propagate or modify a covered work except as expressly
|
|
||||||
provided under this License. Any attempt otherwise to propagate or
|
|
||||||
modify it is void, and will automatically terminate your rights under
|
|
||||||
this License (including any patent licenses granted under the third
|
|
||||||
paragraph of section 11).
|
|
||||||
|
|
||||||
However, if you cease all violation of this License, then your
|
|
||||||
license from a particular copyright holder is reinstated (a)
|
|
||||||
provisionally, unless and until the copyright holder explicitly and
|
|
||||||
finally terminates your license, and (b) permanently, if the copyright
|
|
||||||
holder fails to notify you of the violation by some reasonable means
|
|
||||||
prior to 60 days after the cessation.
|
|
||||||
|
|
||||||
Moreover, your license from a particular copyright holder is
|
|
||||||
reinstated permanently if the copyright holder notifies you of the
|
|
||||||
violation by some reasonable means, this is the first time you have
|
|
||||||
received notice of violation of this License (for any work) from that
|
|
||||||
copyright holder, and you cure the violation prior to 30 days after
|
|
||||||
your receipt of the notice.
|
|
||||||
|
|
||||||
Termination of your rights under this section does not terminate the
|
|
||||||
licenses of parties who have received copies or rights from you under
|
|
||||||
this License. If your rights have been terminated and not permanently
|
|
||||||
reinstated, you do not qualify to receive new licenses for the same
|
|
||||||
material under section 10.
|
|
||||||
|
|
||||||
9. Acceptance Not Required for Having Copies.
|
|
||||||
|
|
||||||
You are not required to accept this License in order to receive or
|
|
||||||
run a copy of the Program. Ancillary propagation of a covered work
|
|
||||||
occurring solely as a consequence of using peer-to-peer transmission
|
|
||||||
to receive a copy likewise does not require acceptance. However,
|
|
||||||
nothing other than this License grants you permission to propagate or
|
|
||||||
modify any covered work. These actions infringe copyright if you do
|
|
||||||
not accept this License. Therefore, by modifying or propagating a
|
|
||||||
covered work, you indicate your acceptance of this License to do so.
|
|
||||||
|
|
||||||
10. Automatic Licensing of Downstream Recipients.
|
|
||||||
|
|
||||||
Each time you convey a covered work, the recipient automatically
|
|
||||||
receives a license from the original licensors, to run, modify and
|
|
||||||
propagate that work, subject to this License. You are not responsible
|
|
||||||
for enforcing compliance by third parties with this License.
|
|
||||||
|
|
||||||
An "entity transaction" is a transaction transferring control of an
|
|
||||||
organization, or substantially all assets of one, or subdividing an
|
|
||||||
organization, or merging organizations. If propagation of a covered
|
|
||||||
work results from an entity transaction, each party to that
|
|
||||||
transaction who receives a copy of the work also receives whatever
|
|
||||||
licenses to the work the party's predecessor in interest had or could
|
|
||||||
give under the previous paragraph, plus a right to possession of the
|
|
||||||
Corresponding Source of the work from the predecessor in interest, if
|
|
||||||
the predecessor has it or can get it with reasonable efforts.
|
|
||||||
|
|
||||||
You may not impose any further restrictions on the exercise of the
|
|
||||||
rights granted or affirmed under this License. For example, you may
|
|
||||||
not impose a license fee, royalty, or other charge for exercise of
|
|
||||||
rights granted under this License, and you may not initiate litigation
|
|
||||||
(including a cross-claim or counterclaim in a lawsuit) alleging that
|
|
||||||
any patent claim is infringed by making, using, selling, offering for
|
|
||||||
sale, or importing the Program or any portion of it.
|
|
||||||
|
|
||||||
11. Patents.
|
|
||||||
|
|
||||||
A "contributor" is a copyright holder who authorizes use under this
|
|
||||||
License of the Program or a work on which the Program is based. The
|
|
||||||
work thus licensed is called the contributor's "contributor version".
|
|
||||||
|
|
||||||
A contributor's "essential patent claims" are all patent claims
|
|
||||||
owned or controlled by the contributor, whether already acquired or
|
|
||||||
hereafter acquired, that would be infringed by some manner, permitted
|
|
||||||
by this License, of making, using, or selling its contributor version,
|
|
||||||
but do not include claims that would be infringed only as a
|
|
||||||
consequence of further modification of the contributor version. For
|
|
||||||
purposes of this definition, "control" includes the right to grant
|
|
||||||
patent sublicenses in a manner consistent with the requirements of
|
|
||||||
this License.
|
|
||||||
|
|
||||||
Each contributor grants you a non-exclusive, worldwide, royalty-free
|
|
||||||
patent license under the contributor's essential patent claims, to
|
|
||||||
make, use, sell, offer for sale, import and otherwise run, modify and
|
|
||||||
propagate the contents of its contributor version.
|
|
||||||
|
|
||||||
In the following three paragraphs, a "patent license" is any express
|
|
||||||
agreement or commitment, however denominated, not to enforce a patent
|
|
||||||
(such as an express permission to practice a patent or covenant not to
|
|
||||||
sue for patent infringement). To "grant" such a patent license to a
|
|
||||||
party means to make such an agreement or commitment not to enforce a
|
|
||||||
patent against the party.
|
|
||||||
|
|
||||||
If you convey a covered work, knowingly relying on a patent license,
|
|
||||||
and the Corresponding Source of the work is not available for anyone
|
|
||||||
to copy, free of charge and under the terms of this License, through a
|
|
||||||
publicly available network server or other readily accessible means,
|
|
||||||
then you must either (1) cause the Corresponding Source to be so
|
|
||||||
available, or (2) arrange to deprive yourself of the benefit of the
|
|
||||||
patent license for this particular work, or (3) arrange, in a manner
|
|
||||||
consistent with the requirements of this License, to extend the patent
|
|
||||||
license to downstream recipients. "Knowingly relying" means you have
|
|
||||||
actual knowledge that, but for the patent license, your conveying the
|
|
||||||
covered work in a country, or your recipient's use of the covered work
|
|
||||||
in a country, would infringe one or more identifiable patents in that
|
|
||||||
country that you have reason to believe are valid.
|
|
||||||
|
|
||||||
If, pursuant to or in connection with a single transaction or
|
|
||||||
arrangement, you convey, or propagate by procuring conveyance of, a
|
|
||||||
covered work, and grant a patent license to some of the parties
|
|
||||||
receiving the covered work authorizing them to use, propagate, modify
|
|
||||||
or convey a specific copy of the covered work, then the patent license
|
|
||||||
you grant is automatically extended to all recipients of the covered
|
|
||||||
work and works based on it.
|
|
||||||
|
|
||||||
A patent license is "discriminatory" if it does not include within
|
|
||||||
the scope of its coverage, prohibits the exercise of, or is
|
|
||||||
conditioned on the non-exercise of one or more of the rights that are
|
|
||||||
specifically granted under this License. You may not convey a covered
|
|
||||||
work if you are a party to an arrangement with a third party that is
|
|
||||||
in the business of distributing software, under which you make payment
|
|
||||||
to the third party based on the extent of your activity of conveying
|
|
||||||
the work, and under which the third party grants, to any of the
|
|
||||||
parties who would receive the covered work from you, a discriminatory
|
|
||||||
patent license (a) in connection with copies of the covered work
|
|
||||||
conveyed by you (or copies made from those copies), or (b) primarily
|
|
||||||
for and in connection with specific products or compilations that
|
|
||||||
contain the covered work, unless you entered into that arrangement,
|
|
||||||
or that patent license was granted, prior to 28 March 2007.
|
|
||||||
|
|
||||||
Nothing in this License shall be construed as excluding or limiting
|
|
||||||
any implied license or other defenses to infringement that may
|
|
||||||
otherwise be available to you under applicable patent law.
|
|
||||||
|
|
||||||
12. No Surrender of Others' Freedom.
|
|
||||||
|
|
||||||
If conditions are imposed on you (whether by court order, agreement or
|
|
||||||
otherwise) that contradict the conditions of this License, they do not
|
|
||||||
excuse you from the conditions of this License. If you cannot convey a
|
|
||||||
covered work so as to satisfy simultaneously your obligations under this
|
|
||||||
License and any other pertinent obligations, then as a consequence you may
|
|
||||||
not convey it at all. For example, if you agree to terms that obligate you
|
|
||||||
to collect a royalty for further conveying from those to whom you convey
|
|
||||||
the Program, the only way you could satisfy both those terms and this
|
|
||||||
License would be to refrain entirely from conveying the Program.
|
|
||||||
|
|
||||||
13. Use with the GNU Affero General Public License.
|
|
||||||
|
|
||||||
Notwithstanding any other provision of this License, you have
|
|
||||||
permission to link or combine any covered work with a work licensed
|
|
||||||
under version 3 of the GNU Affero General Public License into a single
|
|
||||||
combined work, and to convey the resulting work. The terms of this
|
|
||||||
License will continue to apply to the part which is the covered work,
|
|
||||||
but the special requirements of the GNU Affero General Public License,
|
|
||||||
section 13, concerning interaction through a network will apply to the
|
|
||||||
combination as such.
|
|
||||||
|
|
||||||
14. Revised Versions of this License.
|
|
||||||
|
|
||||||
The Free Software Foundation may publish revised and/or new versions of
|
|
||||||
the GNU General Public License from time to time. Such new versions will
|
|
||||||
be similar in spirit to the present version, but may differ in detail to
|
|
||||||
address new problems or concerns.
|
|
||||||
|
|
||||||
Each version is given a distinguishing version number. If the
|
|
||||||
Program specifies that a certain numbered version of the GNU General
|
|
||||||
Public License "or any later version" applies to it, you have the
|
|
||||||
option of following the terms and conditions either of that numbered
|
|
||||||
version or of any later version published by the Free Software
|
|
||||||
Foundation. If the Program does not specify a version number of the
|
|
||||||
GNU General Public License, you may choose any version ever published
|
|
||||||
by the Free Software Foundation.
|
|
||||||
|
|
||||||
If the Program specifies that a proxy can decide which future
|
|
||||||
versions of the GNU General Public License can be used, that proxy's
|
|
||||||
public statement of acceptance of a version permanently authorizes you
|
|
||||||
to choose that version for the Program.
|
|
||||||
|
|
||||||
Later license versions may give you additional or different
|
|
||||||
permissions. However, no additional obligations are imposed on any
|
|
||||||
author or copyright holder as a result of your choosing to follow a
|
|
||||||
later version.
|
|
||||||
|
|
||||||
15. Disclaimer of Warranty.
|
|
||||||
|
|
||||||
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
|
|
||||||
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
|
|
||||||
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
|
|
||||||
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
|
|
||||||
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
||||||
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
|
|
||||||
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
|
|
||||||
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
|
|
||||||
|
|
||||||
16. Limitation of Liability.
|
|
||||||
|
|
||||||
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
|
||||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
|
|
||||||
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
|
|
||||||
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
|
|
||||||
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
|
|
||||||
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
|
|
||||||
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
|
|
||||||
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
|
|
||||||
SUCH DAMAGES.
|
|
||||||
|
|
||||||
17. Interpretation of Sections 15 and 16.
|
|
||||||
|
|
||||||
If the disclaimer of warranty and limitation of liability provided
|
|
||||||
above cannot be given local legal effect according to their terms,
|
|
||||||
reviewing courts shall apply local law that most closely approximates
|
|
||||||
an absolute waiver of all civil liability in connection with the
|
|
||||||
Program, unless a warranty or assumption of liability accompanies a
|
|
||||||
copy of the Program in return for a fee.
|
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
|
||||||
|
|
||||||
How to Apply These Terms to Your New Programs
|
|
||||||
|
|
||||||
If you develop a new program, and you want it to be of the greatest
|
|
||||||
possible use to the public, the best way to achieve this is to make it
|
|
||||||
free software which everyone can redistribute and change under these terms.
|
|
||||||
|
|
||||||
To do so, attach the following notices to the program. It is safest
|
|
||||||
to attach them to the start of each source file to most effectively
|
|
||||||
state the exclusion of warranty; and each file should have at least
|
|
||||||
the "copyright" line and a pointer to where the full notice is found.
|
|
||||||
|
|
||||||
<one line to give the program's name and a brief idea of what it does.>
|
|
||||||
Copyright (C) <year> <name of author>
|
|
||||||
|
|
||||||
This program 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 3 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program 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/>.
|
|
||||||
|
|
||||||
Also add information on how to contact you by electronic and paper mail.
|
|
||||||
|
|
||||||
If the program does terminal interaction, make it output a short
|
|
||||||
notice like this when it starts in an interactive mode:
|
|
||||||
|
|
||||||
<program> Copyright (C) <year> <name of author>
|
|
||||||
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
|
||||||
This is free software, and you are welcome to redistribute it
|
|
||||||
under certain conditions; type `show c' for details.
|
|
||||||
|
|
||||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
|
||||||
parts of the General Public License. Of course, your program's commands
|
|
||||||
might be different; for a GUI interface, you would use an "about box".
|
|
||||||
|
|
||||||
You should also get your employer (if you work as a programmer) or school,
|
|
||||||
if any, to sign a "copyright disclaimer" for the program, if necessary.
|
|
||||||
For more information on this, and how to apply and follow the GNU GPL, see
|
|
||||||
<http://www.gnu.org/licenses/>.
|
|
||||||
|
|
||||||
The GNU General Public License does not permit incorporating your program
|
|
||||||
into proprietary programs. If your program is a subroutine library, you
|
|
||||||
may consider it more useful to permit linking proprietary applications with
|
|
||||||
the library. If this is what you want to do, use the GNU Lesser General
|
|
||||||
Public License instead of this License. But first, please read
|
|
||||||
<http://www.gnu.org/philosophy/why-not-lgpl.html>.
|
|
23
INSTALL
@@ -1,23 +1,10 @@
|
|||||||
python-escpos
|
python-escpos
|
||||||
=============
|
=============
|
||||||
|
|
||||||
Ensure the library is installed on ${lib_arch}/${python_ver}/site-packages/escpos
|
This library is available over pypi. So for most of the use-cases it should be sufficient to run
|
||||||
|
|
||||||
On CLi you must run:
|
```
|
||||||
# python setup.py build
|
pip install python-escpos[all] --user # add --pre if you want to install pre-releases
|
||||||
# sudo python setup.py install
|
```
|
||||||
|
|
||||||
On Linux, ensure you belongs to the proper group so you can have access to the printer.
|
For more information please read the documentation at https://python-escpos.readthedocs.io/en/latest/user/installation.html
|
||||||
This can be done, by adding yourself to 'dialout' group, this might require to re-login
|
|
||||||
so the changes make effect.
|
|
||||||
|
|
||||||
Then, add the following rule to /etc/udev/rules.d/99-escpos.rules
|
|
||||||
SUBSYSTEM=="usb", ATTRS{idVendor}=="04b8", ATTRS{idProduct}=="0202", MODE="0664", GROUP="dialout"
|
|
||||||
|
|
||||||
and restar udev rules.
|
|
||||||
# sudo service udev restart
|
|
||||||
|
|
||||||
Enjoy !!!
|
|
||||||
And please, don't forget to ALWAYS add Epson.cut() at the end of your printing :)
|
|
||||||
|
|
||||||
Manuel F Martinez <manpaz@bashlinux.com>
|
|
||||||
|
21
LICENSE
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2012-2017 python-escpos and Manuel F Martinez
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
8
MANIFEST
@@ -1,8 +0,0 @@
|
|||||||
# file GENERATED by distutils, do NOT edit
|
|
||||||
README
|
|
||||||
setup.py
|
|
||||||
escpos/__init__.py
|
|
||||||
escpos/constants.py
|
|
||||||
escpos/escpos.py
|
|
||||||
escpos/exceptions.py
|
|
||||||
escpos/printer.py
|
|
13
MANIFEST.in
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
include *.rst
|
||||||
|
include *.txt
|
||||||
|
include LICENSE
|
||||||
|
include INSTALL
|
||||||
|
include tox.ini
|
||||||
|
include capabilities-data/dist/capabilities.json
|
||||||
|
include src/escpos/capabilities.json
|
||||||
|
recursive-include doc *.bat
|
||||||
|
recursive-include doc *.ico
|
||||||
|
recursive-include doc *.py
|
||||||
|
recursive-include doc *.rst
|
||||||
|
recursive-include doc *.txt
|
||||||
|
recursive-include doc Makefile
|
89
README
@@ -1,89 +0,0 @@
|
|||||||
ESCPOS
|
|
||||||
======
|
|
||||||
|
|
||||||
Python library to manipulate ESC/POS Printers.
|
|
||||||
|
|
||||||
------------------------------------------------------------------
|
|
||||||
1. Dependencies
|
|
||||||
|
|
||||||
In order to start getting access to your printer, you must ensure
|
|
||||||
you have previously installed the following python modules:
|
|
||||||
|
|
||||||
* pyusb (python-usb)
|
|
||||||
* PIL (Python Image Library)
|
|
||||||
|
|
||||||
------------------------------------------------------------------
|
|
||||||
2. Description
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
------------------------------------------------------------------
|
|
||||||
3. Define your printer
|
|
||||||
|
|
||||||
Before start create your Python ESC/POS printer instance, you must
|
|
||||||
see at your system for the printer parameters. This is done with
|
|
||||||
the 'lsusb' command.
|
|
||||||
|
|
||||||
First run the command to look for the "Vendor ID" and "Product ID",
|
|
||||||
then write down the values, these values are displayed just before
|
|
||||||
the name of the device with the following format:
|
|
||||||
|
|
||||||
xxxx:xxxx
|
|
||||||
|
|
||||||
Example:
|
|
||||||
Bus 002 Device 001: ID 1a2b:1a2b Device name
|
|
||||||
|
|
||||||
Write down the the values in question, then issue the following
|
|
||||||
command so you can get the "Interface" number and "End Point"
|
|
||||||
|
|
||||||
lsusb -vvv -d xxxx:xxxx | grep iInterface
|
|
||||||
lsusb -vvv -d xxxx:xxxx | grep bEndpointAddress | grep OUT
|
|
||||||
|
|
||||||
The first command will yields the "Interface" number that must
|
|
||||||
be handy to have and the second yields the "Output Endpoint"
|
|
||||||
address.
|
|
||||||
|
|
||||||
By default the "Interface" number is "0" and the "Output Endpoint"
|
|
||||||
address is "0x82", if you have other values then you can define
|
|
||||||
with your instance.
|
|
||||||
|
|
||||||
------------------------------------------------------------------
|
|
||||||
4. Define your instance
|
|
||||||
|
|
||||||
The following example shows how to initialize the Epson TM-TI88IV
|
|
||||||
*** NOTE: Always finish the sequence with Epson.cut() otherwise
|
|
||||||
you will endup with weird chars being printed.
|
|
||||||
|
|
||||||
from escpos import *
|
|
||||||
|
|
||||||
""" Seiko Epson Corp. Receipt Printer M129 Definitions (EPSON TM-T88IV) """
|
|
||||||
Epson = escpos.Escpos(0x04b8,0x0202)
|
|
||||||
Epson.text("Hello World")
|
|
||||||
Epson.image("logo.gif")
|
|
||||||
Epson.barcode
|
|
||||||
Epson.barcode('1324354657687','EAN13',64,2,'','')
|
|
||||||
Epson.cut()
|
|
||||||
|
|
||||||
------------------------------------------------------------------
|
|
||||||
5. Links
|
|
||||||
|
|
||||||
Please visit project documentation at:
|
|
||||||
https://github.com/manpaz/python-escpos/wiki
|
|
||||||
|
|
||||||
Manuel F Martinez <manpaz@bashlinux.com>
|
|
||||||
|
|
103
README.rst
Normal file
@@ -0,0 +1,103 @@
|
|||||||
|
#############################################################
|
||||||
|
python-escpos - Python library to manipulate ESC/POS Printers
|
||||||
|
#############################################################
|
||||||
|
|
||||||
|
Description
|
||||||
|
===========
|
||||||
|
|
||||||
|
.. image:: https://readthedocs.org/projects/python-escpos/badge/?version=latest
|
||||||
|
:target: https://python-escpos.readthedocs.io/en/latest/?badge=latest
|
||||||
|
:alt: Documentation Status
|
||||||
|
|
||||||
|
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 library tries to implement the functions provided by the ESC/POS-command-set and supports sending text, images,
|
||||||
|
barcodes and qr-codes to the printer.
|
||||||
|
|
||||||
|
Text can be aligned/justified and fonts can be changed by size, type and weight.
|
||||||
|
|
||||||
|
Also, this module handles some hardware functionalities like cutting paper, control characters, printer reset
|
||||||
|
and similar functions.
|
||||||
|
|
||||||
|
Since supported commands differ from printer to printer the software tries to automatically apply the right
|
||||||
|
settings for the printer that you set. These settings are handled by
|
||||||
|
`escpos-printer-db <https://github.com/receipt-print-hq/escpos-printer-db>`_ which is also used in
|
||||||
|
`escpos-php <https://github.com/mike42/escpos-php>`_.
|
||||||
|
|
||||||
|
Dependencies
|
||||||
|
------------
|
||||||
|
|
||||||
|
This library makes use of:
|
||||||
|
|
||||||
|
* `pyusb <https://github.com/walac/pyusb>`_ for USB-printers
|
||||||
|
* `Pillow <https://github.com/python-pillow/Pillow>`_ for image printing
|
||||||
|
* `qrcode <https://github.com/lincolnloop/python-qrcode>`_ for the generation of QR-codes
|
||||||
|
* `pyserial <https://github.com/pyserial/pyserial>`_ for serial printers
|
||||||
|
* `python-barcode <https://github.com/WhyNotHugo/python-barcode>`_ for the generation of barcodes
|
||||||
|
|
||||||
|
Documentation and Usage
|
||||||
|
-----------------------
|
||||||
|
|
||||||
|
The basic usage is:
|
||||||
|
|
||||||
|
.. code:: python
|
||||||
|
|
||||||
|
from escpos.printer import Usb
|
||||||
|
|
||||||
|
""" Seiko Epson Corp. Receipt Printer (EPSON TM-T88III) """
|
||||||
|
p = Usb(0x04b8, 0x0202, 0, profile="TM-T88III")
|
||||||
|
p.text("Hello World\n")
|
||||||
|
p.image("logo.gif")
|
||||||
|
p.barcode('4006381333931', 'EAN13', 64, 2, '', '')
|
||||||
|
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('4006381333931', 'EAN13', 64, 2, '', '')
|
||||||
|
kitchen.cut()
|
||||||
|
|
||||||
|
Another example based on the Serial printer class:
|
||||||
|
|
||||||
|
.. code:: python
|
||||||
|
|
||||||
|
from escpos.printer import Serial
|
||||||
|
|
||||||
|
""" 9600 Baud, 8N1, Flow Control Enabled """
|
||||||
|
p = Serial(devfile='/dev/tty.usbserial',
|
||||||
|
baudrate=9600,
|
||||||
|
bytesize=8,
|
||||||
|
parity='N',
|
||||||
|
stopbits=1,
|
||||||
|
timeout=1.00,
|
||||||
|
dsrdtr=True)
|
||||||
|
|
||||||
|
p.text("Hello World\n")
|
||||||
|
p.qr("You can readme from your smartphone")
|
||||||
|
p.cut()
|
||||||
|
|
||||||
|
|
||||||
|
The full project-documentation is available on
|
||||||
|
`Read the Docs <https://python-escpos.readthedocs.io>`_.
|
||||||
|
|
||||||
|
Contributing
|
||||||
|
------------
|
||||||
|
|
||||||
|
This project is open for any contribution! Please see
|
||||||
|
`CONTRIBUTING.rst <https://python-escpos.readthedocs.io/en/latest/dev/contributing.html>`_
|
||||||
|
for more information.
|
||||||
|
|
||||||
|
|
||||||
|
Disclaimer
|
||||||
|
----------
|
||||||
|
|
||||||
|
None of the vendors cited in this project agree or endorse any of the
|
||||||
|
patterns or implementations.
|
||||||
|
Its names are used only to maintain context.
|
1
capabilities-data
Submodule
17
codecov.yml
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
codecov:
|
||||||
|
bot: patkan
|
||||||
|
|
||||||
|
coverage:
|
||||||
|
status:
|
||||||
|
project: off
|
||||||
|
patch: off
|
||||||
|
changes: off
|
||||||
|
range: "60...100"
|
||||||
|
|
||||||
|
comment:
|
||||||
|
layout: " diff, flags, files"
|
||||||
|
behavior: default
|
||||||
|
require_changes: false # if true: only post the comment if coverage changes
|
||||||
|
require_base: false # [true :: must have a base report to post]
|
||||||
|
require_head: true # [true :: must have a head report to post]
|
||||||
|
|
1
doc/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
_build/
|
183
doc/Makefile
Normal file
@@ -0,0 +1,183 @@
|
|||||||
|
# Makefile for Sphinx documentation
|
||||||
|
#
|
||||||
|
|
||||||
|
# You can set these variables from the command line.
|
||||||
|
SPHINXOPTS =
|
||||||
|
SPHINXBUILD = sphinx-build
|
||||||
|
PAPER =
|
||||||
|
BUILDDIR = _build
|
||||||
|
|
||||||
|
# User-friendly check for sphinx-build
|
||||||
|
ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1)
|
||||||
|
$(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from https://sphinx-doc.org/)
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Internal variables.
|
||||||
|
PAPEROPT_a4 = -D latex_paper_size=a4
|
||||||
|
PAPEROPT_letter = -D latex_paper_size=letter
|
||||||
|
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
|
||||||
|
# the i18n builder cannot share the environment and doctrees with the others
|
||||||
|
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
|
||||||
|
|
||||||
|
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext spelling
|
||||||
|
|
||||||
|
help:
|
||||||
|
@echo "Please use \`make <target>' where <target> is one of"
|
||||||
|
@echo " html to make standalone HTML files"
|
||||||
|
@echo " dirhtml to make HTML files named index.html in directories"
|
||||||
|
@echo " singlehtml to make a single large HTML file"
|
||||||
|
@echo " pickle to make pickle files"
|
||||||
|
@echo " json to make JSON files"
|
||||||
|
@echo " htmlhelp to make HTML files and a HTML help project"
|
||||||
|
@echo " qthelp to make HTML files and a qthelp project"
|
||||||
|
@echo " devhelp to make HTML files and a Devhelp project"
|
||||||
|
@echo " epub to make an epub"
|
||||||
|
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
|
||||||
|
@echo " latexpdf to make LaTeX files and run them through pdflatex"
|
||||||
|
@echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx"
|
||||||
|
@echo " text to make text files"
|
||||||
|
@echo " man to make manual pages"
|
||||||
|
@echo " texinfo to make Texinfo files"
|
||||||
|
@echo " info to make Texinfo files and run them through makeinfo"
|
||||||
|
@echo " gettext to make PO message catalogs"
|
||||||
|
@echo " changes to make an overview of all changed/added/deprecated items"
|
||||||
|
@echo " xml to make Docutils-native XML files"
|
||||||
|
@echo " pseudoxml to make pseudoxml-XML files for display purposes"
|
||||||
|
@echo " linkcheck to check all external links for integrity"
|
||||||
|
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
|
||||||
|
@echo " spelling to run the spellchecker"
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf $(BUILDDIR)/*
|
||||||
|
|
||||||
|
html:
|
||||||
|
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
|
||||||
|
@echo
|
||||||
|
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
|
||||||
|
|
||||||
|
dirhtml:
|
||||||
|
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
|
||||||
|
@echo
|
||||||
|
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
|
||||||
|
|
||||||
|
singlehtml:
|
||||||
|
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
|
||||||
|
@echo
|
||||||
|
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
|
||||||
|
|
||||||
|
pickle:
|
||||||
|
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
|
||||||
|
@echo
|
||||||
|
@echo "Build finished; now you can process the pickle files."
|
||||||
|
|
||||||
|
json:
|
||||||
|
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
|
||||||
|
@echo
|
||||||
|
@echo "Build finished; now you can process the JSON files."
|
||||||
|
|
||||||
|
htmlhelp:
|
||||||
|
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
|
||||||
|
@echo
|
||||||
|
@echo "Build finished; now you can run HTML Help Workshop with the" \
|
||||||
|
".hhp project file in $(BUILDDIR)/htmlhelp."
|
||||||
|
|
||||||
|
qthelp:
|
||||||
|
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
|
||||||
|
@echo
|
||||||
|
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
|
||||||
|
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
|
||||||
|
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/python-escpos.qhcp"
|
||||||
|
@echo "To view the help file:"
|
||||||
|
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/python-escpos.qhc"
|
||||||
|
|
||||||
|
devhelp:
|
||||||
|
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
|
||||||
|
@echo
|
||||||
|
@echo "Build finished."
|
||||||
|
@echo "To view the help file:"
|
||||||
|
@echo "# mkdir -p $$HOME/.local/share/devhelp/python-escpos"
|
||||||
|
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/python-escpos"
|
||||||
|
@echo "# devhelp"
|
||||||
|
|
||||||
|
epub:
|
||||||
|
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
|
||||||
|
@echo
|
||||||
|
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
|
||||||
|
|
||||||
|
latex:
|
||||||
|
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
||||||
|
@echo
|
||||||
|
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
|
||||||
|
@echo "Run \`make' in that directory to run these through (pdf)latex" \
|
||||||
|
"(use \`make latexpdf' here to do that automatically)."
|
||||||
|
|
||||||
|
latexpdf:
|
||||||
|
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
||||||
|
@echo "Running LaTeX files through pdflatex..."
|
||||||
|
$(MAKE) -C $(BUILDDIR)/latex all-pdf
|
||||||
|
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
|
||||||
|
|
||||||
|
latexpdfja:
|
||||||
|
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
||||||
|
@echo "Running LaTeX files through platex and dvipdfmx..."
|
||||||
|
$(MAKE) -C $(BUILDDIR)/latex all-pdf-ja
|
||||||
|
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
|
||||||
|
|
||||||
|
text:
|
||||||
|
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
|
||||||
|
@echo
|
||||||
|
@echo "Build finished. The text files are in $(BUILDDIR)/text."
|
||||||
|
|
||||||
|
man:
|
||||||
|
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
|
||||||
|
@echo
|
||||||
|
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
|
||||||
|
|
||||||
|
texinfo:
|
||||||
|
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
|
||||||
|
@echo
|
||||||
|
@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
|
||||||
|
@echo "Run \`make' in that directory to run these through makeinfo" \
|
||||||
|
"(use \`make info' here to do that automatically)."
|
||||||
|
|
||||||
|
info:
|
||||||
|
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
|
||||||
|
@echo "Running Texinfo files through makeinfo..."
|
||||||
|
make -C $(BUILDDIR)/texinfo info
|
||||||
|
@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
|
||||||
|
|
||||||
|
gettext:
|
||||||
|
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
|
||||||
|
@echo
|
||||||
|
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
|
||||||
|
|
||||||
|
changes:
|
||||||
|
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
|
||||||
|
@echo
|
||||||
|
@echo "The overview file is in $(BUILDDIR)/changes."
|
||||||
|
|
||||||
|
linkcheck:
|
||||||
|
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
|
||||||
|
@echo
|
||||||
|
@echo "Link check complete; look for any errors in the above output " \
|
||||||
|
"or in $(BUILDDIR)/linkcheck/output.txt."
|
||||||
|
|
||||||
|
doctest:
|
||||||
|
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
|
||||||
|
@echo "Testing of doctests in the sources finished, look at the " \
|
||||||
|
"results in $(BUILDDIR)/doctest/output.txt."
|
||||||
|
|
||||||
|
xml:
|
||||||
|
$(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml
|
||||||
|
@echo
|
||||||
|
@echo "Build finished. The XML files are in $(BUILDDIR)/xml."
|
||||||
|
|
||||||
|
pseudoxml:
|
||||||
|
$(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml
|
||||||
|
@echo
|
||||||
|
@echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml."
|
||||||
|
|
||||||
|
spelling:
|
||||||
|
$(SPHINXBUILD) -b spelling $(ALLSPHINXOPTS) $(BUILDDIR)/spelling
|
||||||
|
@echo
|
||||||
|
@echo "Spellchecker finished."
|
0
doc/_static/.gitignore
vendored
Normal file
10
doc/api/capabilities.rst
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
Capabilities
|
||||||
|
------------
|
||||||
|
Module :py:mod:`escpos.capabilities`
|
||||||
|
|
||||||
|
.. automodule:: escpos.capabilities
|
||||||
|
:members:
|
||||||
|
:inherited-members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:member-order: bysource
|
10
doc/api/cli.rst
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
CLI
|
||||||
|
---
|
||||||
|
Module :py:mod:`escpos.cli`
|
||||||
|
|
||||||
|
.. automodule:: escpos.cli
|
||||||
|
:members:
|
||||||
|
:inherited-members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:member-order: bysource
|
10
doc/api/codepages.rst
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
Codepages
|
||||||
|
---------
|
||||||
|
Module :py:mod:`escpos.codepages`
|
||||||
|
|
||||||
|
.. automodule:: escpos.codepages
|
||||||
|
:members:
|
||||||
|
:inherited-members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:member-order: bysource
|
10
doc/api/config.rst
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
Config
|
||||||
|
------
|
||||||
|
Module :py:mod:`escpos.config`
|
||||||
|
|
||||||
|
.. automodule:: escpos.config
|
||||||
|
:members:
|
||||||
|
:inherited-members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:member-order: bysource
|
10
doc/api/constants.rst
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
Constants
|
||||||
|
---------
|
||||||
|
Module :py:mod:`escpos.constants`
|
||||||
|
|
||||||
|
.. automodule:: escpos.constants
|
||||||
|
:members:
|
||||||
|
:inherited-members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:member-order: bysource
|
10
doc/api/escpos.rst
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
Esc/Pos
|
||||||
|
-------
|
||||||
|
Module :py:mod:`escpos.escpos`
|
||||||
|
|
||||||
|
.. automodule:: escpos.escpos
|
||||||
|
:members:
|
||||||
|
:inherited-members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:member-order: bysource
|
9
doc/api/exceptions.rst
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
Exceptions
|
||||||
|
----------
|
||||||
|
Module :py:mod:`escpos.exceptions`
|
||||||
|
|
||||||
|
.. automodule:: escpos.exceptions
|
||||||
|
:members:
|
||||||
|
:inherited-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:member-order: bysource
|
10
doc/api/image.rst
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
Image helper
|
||||||
|
------------
|
||||||
|
Module :py:mod:`escpos.image`
|
||||||
|
|
||||||
|
.. automodule:: escpos.image
|
||||||
|
:members:
|
||||||
|
:inherited-members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:member-order: bysource
|
10
doc/api/katakana.rst
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
Katakana
|
||||||
|
--------
|
||||||
|
Module :py:mod:`escpos.katakana`
|
||||||
|
|
||||||
|
.. automodule:: escpos.katakana
|
||||||
|
:members:
|
||||||
|
:inherited-members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:member-order: bysource
|
10
doc/api/magicencode.rst
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
Magic Encode
|
||||||
|
------------
|
||||||
|
Module :py:mod:`escpos.magicencode`
|
||||||
|
|
||||||
|
.. automodule:: escpos.magicencode
|
||||||
|
:members:
|
||||||
|
:inherited-members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:member-order: bysource
|
9
doc/api/printer.rst
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
Printer implementations
|
||||||
|
-----------------------
|
||||||
|
Module :py:mod:`escpos.printer`
|
||||||
|
|
||||||
|
.. automodule:: escpos.printer
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
:member-order: bysource
|
@@ -0,0 +1,28 @@
|
|||||||
|
{% for item in data.encodings %}
|
||||||
|
{% set encoding = data.encodings[item] %}
|
||||||
|
{% macro draw_with_underline(text, symbol='-') -%}
|
||||||
|
{{ escape_rst(text) }}
|
||||||
|
{{ escape_rst(text) | length * symbol }}
|
||||||
|
{%- endmacro %}
|
||||||
|
|
||||||
|
{{ '.. _encoding-label-' + item + ':' }}
|
||||||
|
|
||||||
|
{{ draw_with_underline(encoding.name) }}
|
||||||
|
|
||||||
|
{{ escape_rst(encoding.notes) }}
|
||||||
|
|
||||||
|
Mapping Information
|
||||||
|
^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
====================== ================================================================
|
||||||
|
identifier {{ escape_rst(item) }}
|
||||||
|
Name {{ escape_rst(encoding.name|default('Unknown')) }}
|
||||||
|
Iconv Name {{ escape_rst(encoding.iconv|default('Unknown')) }}
|
||||||
|
``python_encode`` Name {{ escape_rst(encoding.python_encode|default('Unknown')) }}
|
||||||
|
====================== ================================================================
|
||||||
|
|
||||||
|
{% if encoding.data is defined %}
|
||||||
|
{{ draw_with_underline('Code page data', symbol='^') }}
|
||||||
|
{{ encoding.data }}
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
83
doc/capability_templates/capabilities-template.jinja
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
{% for item in data.profiles %}
|
||||||
|
{% set printer = data.profiles[item] %}
|
||||||
|
{% macro draw_with_underline(text, symbol='-') -%}
|
||||||
|
{{ escape_rst(text) }}
|
||||||
|
{{ escape_rst(text) | length * symbol }}
|
||||||
|
{%- endmacro %}
|
||||||
|
{% macro abort(error) %}
|
||||||
|
{{ None['[ERROR] ' ~ error][0] }}
|
||||||
|
{% endmacro %}
|
||||||
|
{% macro fill_line(text, total, symbol=' ') -%}
|
||||||
|
{%- if total < text|length -%}
|
||||||
|
{{- abort("Line cannot be filled: must be longer") -}}
|
||||||
|
{%- endif -%}
|
||||||
|
{{- text + ((total - text|length ) * symbol ) -}}
|
||||||
|
{%- endmacro %}
|
||||||
|
|
||||||
|
{{ '.. _printer-label-' + item + ':' }}
|
||||||
|
|
||||||
|
{{ draw_with_underline(printer.name) }}
|
||||||
|
{{ escape_rst(printer.notes) }}
|
||||||
|
|
||||||
|
You can select this profile in python-escpos with this identifier: ``{{ item }}``.
|
||||||
|
(Set parameter to `profile='{{ item }}'`.)
|
||||||
|
|
||||||
|
Basic information
|
||||||
|
^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
====================== ================================================================
|
||||||
|
Name {{ escape_rst(printer.name|default('Unknown')) }}
|
||||||
|
Vendor {{ escape_rst(printer.vendor|default('Unknown')) }}
|
||||||
|
Media width (mm) {{ escape_rst(printer.media.width.mm|default('Unknown')|string) }}
|
||||||
|
Media width (pixels) {{ escape_rst(printer.media.width.pixels|default('Unknown')|string) }}
|
||||||
|
DPI {{ escape_rst(printer.media.dpi|default('Unknown')|string) }}
|
||||||
|
====================== ================================================================
|
||||||
|
|
||||||
|
Fonts
|
||||||
|
^^^^^
|
||||||
|
|
||||||
|
+------------------+------------------------------+-----------------------+
|
||||||
|
| ID | Name | Columns |
|
||||||
|
+==================+==============================+=======================+
|
||||||
|
{% for id in printer.fonts -%}
|
||||||
|
| {{ fill_line(escape_rst(id), 16) }} | {{ fill_line(escape_rst(printer.fonts[id].name), 28) }} | {{ fill_line(printer.fonts[id].columns|string, 21) }} |
|
||||||
|
+------------------+------------------------------+-----------------------+
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
|
||||||
|
Colors
|
||||||
|
^^^^^^
|
||||||
|
|
||||||
|
+------------------+----------------------------------------------------------------+
|
||||||
|
| ID | Color |
|
||||||
|
+==================+================================================================+
|
||||||
|
{% for id in printer.colors -%}
|
||||||
|
| {{ fill_line(escape_rst(id), 16) }} | {{ fill_line(escape_rst(printer.colors[id]), 62) }} |
|
||||||
|
+------------------+----------------------------------------------------------------+
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
|
||||||
|
Feature support
|
||||||
|
^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
+-----------------------------------+----------------------------+
|
||||||
|
| Feature | Supported |
|
||||||
|
+===================================+============================+
|
||||||
|
{% for feature in printer.features -%}
|
||||||
|
| {{ fill_line(escape_rst(feature), 33) }} | {{ fill_line(escape_rst(printer.features[feature]|string), 26) }} |
|
||||||
|
+-----------------------------------+----------------------------+
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
|
||||||
|
Text code pages
|
||||||
|
^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
+------------------+----------------------------------------------------------------+
|
||||||
|
| ID | Encoding |
|
||||||
|
+==================+================================================================+
|
||||||
|
{% for id in printer.codePages -%}
|
||||||
|
| {{ fill_line(escape_rst(id), 16) }} | {{ fill_line(':ref:`encoding-label-'+printer.codePages[id]+'`', 62) }} |
|
||||||
|
+------------------+----------------------------------------------------------------+
|
||||||
|
{% endfor %}
|
||||||
|
|
||||||
|
{% endfor %}
|
331
doc/conf.py
Normal file
@@ -0,0 +1,331 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#
|
||||||
|
# python-escpos documentation build configuration file, created by
|
||||||
|
# sphinx-quickstart on Sat Dec 26 14:28:42 2015.
|
||||||
|
#
|
||||||
|
# This file is execfile()d with the current directory set to its
|
||||||
|
# containing dir.
|
||||||
|
#
|
||||||
|
# Note that not all possible configuration values are present in this
|
||||||
|
# autogenerated file.
|
||||||
|
#
|
||||||
|
# All configuration values have a default; values that are commented out
|
||||||
|
# serve to show the default.
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
from importlib.metadata import version as imp_version
|
||||||
|
|
||||||
|
on_rtd = os.getenv("READTHEDOCS") == "True"
|
||||||
|
|
||||||
|
# If extensions (or modules to document with autodoc) are in another directory,
|
||||||
|
# add these directories to sys.path here. If the directory is relative to the
|
||||||
|
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||||
|
sys.path.insert(0, os.path.abspath("../src"))
|
||||||
|
root = os.path.relpath(os.path.join(os.path.dirname(__file__), ".."))
|
||||||
|
|
||||||
|
# -- General configuration ------------------------------------------------
|
||||||
|
|
||||||
|
# If your documentation needs a minimal Sphinx version, state it here.
|
||||||
|
# needs_sphinx = '1.0'
|
||||||
|
|
||||||
|
# Add any Sphinx extension module names here, as strings. They can be
|
||||||
|
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||||
|
# ones.
|
||||||
|
extensions = [
|
||||||
|
"sphinx.ext.autodoc",
|
||||||
|
"sphinx_autodoc_typehints",
|
||||||
|
"sphinx.ext.doctest",
|
||||||
|
"sphinx.ext.todo",
|
||||||
|
"sphinx.ext.coverage",
|
||||||
|
"sphinx.ext.viewcode",
|
||||||
|
"sphinx.ext.todo",
|
||||||
|
"sphinx.ext.graphviz",
|
||||||
|
"sphinx.ext.inheritance_diagram",
|
||||||
|
"sphinx.ext.imgconverter",
|
||||||
|
"sphinxarg.ext",
|
||||||
|
"sphinxcontrib.datatemplates",
|
||||||
|
"sphinxcontrib.spelling",
|
||||||
|
]
|
||||||
|
|
||||||
|
# mock the following modules for autodoc
|
||||||
|
autodoc_mock_imports = ["qrcode"]
|
||||||
|
|
||||||
|
# supress warnings for external images
|
||||||
|
suppress_warnings = [
|
||||||
|
"image.nonlocal_uri",
|
||||||
|
]
|
||||||
|
|
||||||
|
# enable todos
|
||||||
|
todo_include_todos = True
|
||||||
|
|
||||||
|
# Add any paths that contain templates here, relative to this directory.
|
||||||
|
templates_path = ["_templates", "capability_templates"]
|
||||||
|
|
||||||
|
# The suffix of source filenames.
|
||||||
|
source_suffix = ".rst"
|
||||||
|
|
||||||
|
# The encoding of source files.
|
||||||
|
# source_encoding = 'utf-8-sig'
|
||||||
|
|
||||||
|
# The master toctree document.
|
||||||
|
master_doc = "index"
|
||||||
|
|
||||||
|
# General information about the project.
|
||||||
|
project = "python-escpos"
|
||||||
|
copyright = "2023, python-escpos developers"
|
||||||
|
|
||||||
|
# The version info for the project you're documenting, acts as replacement for
|
||||||
|
# |version| and |release|, also used in various other places throughout the
|
||||||
|
# built documents.
|
||||||
|
#
|
||||||
|
release = imp_version("python-escpos")
|
||||||
|
# The short X.Y version.
|
||||||
|
version = ".".join(release.split(".")[:2])
|
||||||
|
|
||||||
|
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||||
|
# for a list of supported languages.
|
||||||
|
# language = None
|
||||||
|
|
||||||
|
# There are two options for replacing |today|: either, you set today to some
|
||||||
|
# non-false value, then it is used:
|
||||||
|
# today = ''
|
||||||
|
# Else, today_fmt is used as the format for a strftime call.
|
||||||
|
# today_fmt = '%B %d, %Y'
|
||||||
|
|
||||||
|
# List of patterns, relative to source directory, that match files and
|
||||||
|
# directories to ignore when looking for source files.
|
||||||
|
exclude_patterns = ["_build"]
|
||||||
|
|
||||||
|
# The reST default role (used for this markup: `text`) to use for all
|
||||||
|
# documents.
|
||||||
|
# default_role = None
|
||||||
|
|
||||||
|
# If true, '()' will be appended to :func: etc. cross-reference text.
|
||||||
|
# add_function_parentheses = True
|
||||||
|
|
||||||
|
# If true, the current module name will be prepended to all description
|
||||||
|
# unit titles (such as .. function::).
|
||||||
|
# add_module_names = True
|
||||||
|
|
||||||
|
# If true, sectionauthor and moduleauthor directives will be shown in the
|
||||||
|
# output. They are ignored by default.
|
||||||
|
# show_authors = False
|
||||||
|
|
||||||
|
# The name of the Pygments (syntax highlighting) style to use.
|
||||||
|
pygments_style = "sphinx"
|
||||||
|
|
||||||
|
# A list of ignored prefixes for module index sorting.
|
||||||
|
# modindex_common_prefix = []
|
||||||
|
|
||||||
|
# If true, keep warnings as "system message" paragraphs in the built documents.
|
||||||
|
# keep_warnings = False
|
||||||
|
|
||||||
|
|
||||||
|
# -- Options for HTML output ----------------------------------------------
|
||||||
|
|
||||||
|
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||||
|
# a list of builtin themes.
|
||||||
|
if on_rtd:
|
||||||
|
html_theme = "sphinx_rtd_theme"
|
||||||
|
print("recognized execution on RTD")
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
import sphinx_rtd_theme
|
||||||
|
|
||||||
|
html_theme = "sphinx_rtd_theme"
|
||||||
|
html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]
|
||||||
|
except ImportError:
|
||||||
|
print("no sphinx_rtd_theme found, switching to nature")
|
||||||
|
html_theme = "default"
|
||||||
|
|
||||||
|
# Theme options are theme-specific and customize the look and feel of a theme
|
||||||
|
# further. For a list of options available for each theme, see the
|
||||||
|
# documentation.
|
||||||
|
# html_theme_options = {}
|
||||||
|
|
||||||
|
# Add any paths that contain custom themes here, relative to this directory.
|
||||||
|
# html_theme_path = []
|
||||||
|
|
||||||
|
# The name for this set of Sphinx documents. If None, it defaults to
|
||||||
|
# "<project> v<release> documentation".
|
||||||
|
# html_title = None
|
||||||
|
|
||||||
|
# A shorter title for the navigation bar. Default is the same as html_title.
|
||||||
|
# html_short_title = None
|
||||||
|
|
||||||
|
# The name of an image file (relative to this directory) to place at the top
|
||||||
|
# of the sidebar.
|
||||||
|
# html_logo = None
|
||||||
|
|
||||||
|
# The name of an image file (within the static path) to use as favicon of the
|
||||||
|
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
|
||||||
|
# pixels large.
|
||||||
|
html_favicon = "pyescpos.ico"
|
||||||
|
|
||||||
|
# Add any paths that contain custom static files (such as style sheets) here,
|
||||||
|
# relative to this directory. They are copied after the builtin static files,
|
||||||
|
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||||
|
html_static_path = ["_static"]
|
||||||
|
|
||||||
|
# Add any extra paths that contain custom files (such as robots.txt or
|
||||||
|
# .htaccess) here, relative to this directory. These files are copied
|
||||||
|
# directly to the root of the documentation.
|
||||||
|
# html_extra_path = []
|
||||||
|
|
||||||
|
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
|
||||||
|
# using the given strftime format.
|
||||||
|
# html_last_updated_fmt = '%b %d, %Y'
|
||||||
|
|
||||||
|
# If true, SmartyPants will be used to convert quotes and dashes to
|
||||||
|
# typographically correct entities.
|
||||||
|
# html_use_smartypants = True
|
||||||
|
|
||||||
|
# Custom sidebar templates, maps document names to template names.
|
||||||
|
# html_sidebars = {}
|
||||||
|
|
||||||
|
# Additional templates that should be rendered to pages, maps page names to
|
||||||
|
# template names.
|
||||||
|
# html_additional_pages = {}
|
||||||
|
|
||||||
|
# If false, no module index is generated.
|
||||||
|
# html_domain_indices = True
|
||||||
|
|
||||||
|
# If false, no index is generated.
|
||||||
|
# html_use_index = True
|
||||||
|
|
||||||
|
# If true, the index is split into individual pages for each letter.
|
||||||
|
# html_split_index = False
|
||||||
|
|
||||||
|
# If true, links to the reST sources are added to the pages.
|
||||||
|
# html_show_sourcelink = True
|
||||||
|
|
||||||
|
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
|
||||||
|
# html_show_sphinx = True
|
||||||
|
|
||||||
|
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
|
||||||
|
# html_show_copyright = True
|
||||||
|
|
||||||
|
# If true, an OpenSearch description file will be output, and all pages will
|
||||||
|
# contain a <link> tag referring to it. The value of this option must be the
|
||||||
|
# base URL from which the finished HTML is served.
|
||||||
|
# html_use_opensearch = ''
|
||||||
|
|
||||||
|
# This is the file name suffix for HTML files (e.g. ".xhtml").
|
||||||
|
# html_file_suffix = None
|
||||||
|
|
||||||
|
# Output file base name for HTML help builder.
|
||||||
|
htmlhelp_basename = "python-escposdoc"
|
||||||
|
|
||||||
|
|
||||||
|
# -- Options for LaTeX output ---------------------------------------------
|
||||||
|
|
||||||
|
latex_elements = {
|
||||||
|
# The paper size ('letterpaper' or 'a4paper').
|
||||||
|
#'papersize': 'letterpaper',
|
||||||
|
# The font size ('10pt', '11pt' or '12pt').
|
||||||
|
#'pointsize': '10pt',
|
||||||
|
# Additional stuff for the LaTeX preamble.
|
||||||
|
#'preamble': '',
|
||||||
|
}
|
||||||
|
|
||||||
|
latex_engine = "xelatex"
|
||||||
|
|
||||||
|
# Grouping the document tree into LaTeX files. List of tuples
|
||||||
|
# (source start file, target name, title,
|
||||||
|
# author, documentclass [howto, manual, or own class]).
|
||||||
|
latex_documents = [
|
||||||
|
(
|
||||||
|
"index",
|
||||||
|
"python-escpos.tex",
|
||||||
|
"python-escpos Documentation",
|
||||||
|
"python-escpos developers",
|
||||||
|
"manual",
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
|
# The name of an image file (relative to this directory) to place at the top of
|
||||||
|
# the title page.
|
||||||
|
# latex_logo = None
|
||||||
|
|
||||||
|
# For "manual" documents, if this is true, then toplevel headings are parts,
|
||||||
|
# not chapters.
|
||||||
|
# latex_use_parts = False
|
||||||
|
|
||||||
|
# If true, show page references after internal links.
|
||||||
|
# latex_show_pagerefs = False
|
||||||
|
|
||||||
|
# If true, show URL addresses after external links.
|
||||||
|
# latex_show_urls = False
|
||||||
|
|
||||||
|
# Documents to append as an appendix to all manuals.
|
||||||
|
# latex_appendices = []
|
||||||
|
|
||||||
|
# If false, no module index is generated.
|
||||||
|
# latex_domain_indices = True
|
||||||
|
|
||||||
|
|
||||||
|
# -- Options for manual page output ---------------------------------------
|
||||||
|
|
||||||
|
# One entry per manual page. List of tuples
|
||||||
|
# (source start file, name, description, authors, manual section).
|
||||||
|
man_pages = [
|
||||||
|
(
|
||||||
|
"index",
|
||||||
|
"python-escpos",
|
||||||
|
"python-escpos Documentation",
|
||||||
|
["python-escpos developers"],
|
||||||
|
1,
|
||||||
|
)
|
||||||
|
]
|
||||||
|
|
||||||
|
# If true, show URL addresses after external links.
|
||||||
|
# man_show_urls = False
|
||||||
|
|
||||||
|
|
||||||
|
# -- Options for Texinfo output -------------------------------------------
|
||||||
|
|
||||||
|
# Grouping the document tree into Texinfo files. List of tuples
|
||||||
|
# (source start file, target name, title, author,
|
||||||
|
# dir menu entry, description, category)
|
||||||
|
texinfo_documents = [
|
||||||
|
(
|
||||||
|
"index",
|
||||||
|
"python-escpos",
|
||||||
|
"python-escpos Documentation",
|
||||||
|
"python-escpos developers",
|
||||||
|
"python-escpos",
|
||||||
|
"One line description of project.",
|
||||||
|
"Miscellaneous",
|
||||||
|
),
|
||||||
|
]
|
||||||
|
|
||||||
|
# Documents to append as an appendix to all manuals.
|
||||||
|
# texinfo_appendices = []
|
||||||
|
|
||||||
|
# If false, no module index is generated.
|
||||||
|
# texinfo_domain_indices = True
|
||||||
|
|
||||||
|
# How to display URL addresses: 'footnote', 'no', or 'inline'.
|
||||||
|
# texinfo_show_urls = 'footnote'
|
||||||
|
|
||||||
|
# If true, do not generate a @detailmenu in the "Top" node's menu.
|
||||||
|
# texinfo_no_detailmenu = False
|
||||||
|
|
||||||
|
# spellchecker
|
||||||
|
spelling_ignore_pypi_package_names = True
|
||||||
|
spelling_ignore_wiki_words = True
|
||||||
|
spelling_ignore_python_builtins = True
|
||||||
|
spelling_ignore_importable_modules = True
|
||||||
|
spelling_ignore_contributor_names = True
|
||||||
|
spelling_word_list_filename = ["spelling_wordlist.txt", "../AUTHORS"]
|
||||||
|
spelling_show_suggestions = True
|
||||||
|
spelling_suggestion_limit = 3
|
||||||
|
spelling_warning = True
|
||||||
|
spelling_exclude_patterns = [
|
||||||
|
"**/capabilities.json",
|
||||||
|
"../../capabilities-data/dist/capabilities.json",
|
||||||
|
"**/available-encodings.rst",
|
||||||
|
"**/available-profiles.rst",
|
||||||
|
"dev/todo.rst",
|
||||||
|
]
|
1
doc/dev/changelog.rst
Normal file
@@ -0,0 +1 @@
|
|||||||
|
.. include:: ../../CHANGELOG.rst
|
1
doc/dev/contributing.rst
Normal file
@@ -0,0 +1 @@
|
|||||||
|
.. include:: ../../CONTRIBUTING.rst
|
11
doc/dev/release-process.rst
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
Release process
|
||||||
|
===============
|
||||||
|
|
||||||
|
:Last Reviewed: 2023-08-10
|
||||||
|
|
||||||
|
* Update authors file
|
||||||
|
* Update changelog
|
||||||
|
* Set annotated tag for release and push to public github
|
||||||
|
* Build wheel
|
||||||
|
* Load wheel to PyPi
|
||||||
|
* Prepare project for next release with an empty changelog entry
|
17
doc/dev/repository.rst
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
.. _developer-manual-repository:
|
||||||
|
|
||||||
|
Repository
|
||||||
|
==========
|
||||||
|
|
||||||
|
:Last Reviewed: 2023-09-05
|
||||||
|
|
||||||
|
This project uses sub-projects and retrieves its versioning
|
||||||
|
information from version control.
|
||||||
|
Therefore it is crucial that you follow these rules when
|
||||||
|
working with the project (e.g. for packaging a
|
||||||
|
development version).
|
||||||
|
|
||||||
|
* Make sure that the git project is complete. A call to git status for example should succeed.
|
||||||
|
* Make sure that you have checked out all available sub-projects.
|
||||||
|
* Proper initialization of submodules can be ensured with ``git submodule update --init --recursive``
|
||||||
|
|
15
doc/dev/todo.rst
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
TODO
|
||||||
|
====
|
||||||
|
|
||||||
|
:Last Reviewed: 2023-08-10
|
||||||
|
|
||||||
|
Open points and issues of the project are tracked in the GitHub issues.
|
||||||
|
Some annotations still remain in the code and should be moved over time
|
||||||
|
into the issue tracker.
|
||||||
|
|
||||||
|
Todos in the codebase
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
.. todolist::
|
||||||
|
|
||||||
|
|
BIN
doc/download/barcode.bin
Normal file
22
doc/generate_authors.sh
Executable file
@@ -0,0 +1,22 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
GENLIST=$(git shortlog -s -n | cut -f2 | sort -f)
|
||||||
|
GENLIST_W_MAIL=$(git shortlog -s -e -n | cut -f2 | sort -f)
|
||||||
|
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 --suppress-common-lines -b --from-file $AUTHORSFILE $TEMPAUTHORSFILE
|
||||||
|
echo "Authors with mail addresses:\n"
|
||||||
|
echo "$GENLIST_W_MAIL"
|
||||||
|
else
|
||||||
|
echo "$GENLIST">$AUTHORSFILE
|
||||||
|
fi
|
||||||
|
|
90
doc/index.rst
Normal file
@@ -0,0 +1,90 @@
|
|||||||
|
.. python-escpos documentation master file, created by
|
||||||
|
sphinx-quickstart on Sat Dec 26 14:28:42 2015.
|
||||||
|
You can adapt this file completely to your liking, but it should at least
|
||||||
|
contain the root `toctree` directive.
|
||||||
|
|
||||||
|
.. include:: ../README.rst
|
||||||
|
|
||||||
|
#######
|
||||||
|
Content
|
||||||
|
#######
|
||||||
|
|
||||||
|
User Documentation
|
||||||
|
==================
|
||||||
|
|
||||||
|
This chapter describes the central points that
|
||||||
|
are relevant to the user of this library.
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 1
|
||||||
|
:caption: User Documentation
|
||||||
|
|
||||||
|
user/installation
|
||||||
|
user/methods
|
||||||
|
user/printers
|
||||||
|
user/raspi
|
||||||
|
user/usage
|
||||||
|
user/cli-user
|
||||||
|
user/barcode
|
||||||
|
|
||||||
|
Printer profiles
|
||||||
|
================
|
||||||
|
|
||||||
|
This chapter gives a listing of the available
|
||||||
|
printer profiles. Details are described in
|
||||||
|
:ref:`capabilities-profile-intro`.
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 1
|
||||||
|
:caption: Printer profiles
|
||||||
|
|
||||||
|
printer_profiles/capabilities
|
||||||
|
printer_profiles/available-profiles
|
||||||
|
printer_profiles/available-encodings
|
||||||
|
|
||||||
|
Developer Documentation
|
||||||
|
=======================
|
||||||
|
|
||||||
|
This chapter summarizes information for
|
||||||
|
developers of this library.
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 1
|
||||||
|
:caption: Developer Documentation
|
||||||
|
|
||||||
|
dev/release-process
|
||||||
|
dev/contributing
|
||||||
|
dev/repository
|
||||||
|
dev/changelog
|
||||||
|
dev/todo
|
||||||
|
|
||||||
|
API Documentation
|
||||||
|
=================
|
||||||
|
|
||||||
|
This chapter contains an auto-generated
|
||||||
|
documentation of the API of this library.
|
||||||
|
|
||||||
|
.. toctree::
|
||||||
|
:maxdepth: 1
|
||||||
|
:caption: API Documentation
|
||||||
|
|
||||||
|
api/escpos
|
||||||
|
api/printer
|
||||||
|
api/constants
|
||||||
|
api/exceptions
|
||||||
|
api/capabilities
|
||||||
|
api/config
|
||||||
|
api/image
|
||||||
|
api/cli
|
||||||
|
api/magicencode
|
||||||
|
api/codepages
|
||||||
|
api/katakana
|
||||||
|
|
||||||
|
##################
|
||||||
|
Indices and tables
|
||||||
|
##################
|
||||||
|
|
||||||
|
* :ref:`genindex`
|
||||||
|
* :ref:`modindex`
|
||||||
|
* :ref:`search`
|
||||||
|
|
242
doc/make.bat
Normal file
@@ -0,0 +1,242 @@
|
|||||||
|
@ECHO OFF
|
||||||
|
|
||||||
|
REM Command file for Sphinx documentation
|
||||||
|
|
||||||
|
if "%SPHINXBUILD%" == "" (
|
||||||
|
set SPHINXBUILD=sphinx-build
|
||||||
|
)
|
||||||
|
set BUILDDIR=_build
|
||||||
|
set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% .
|
||||||
|
set I18NSPHINXOPTS=%SPHINXOPTS% .
|
||||||
|
if NOT "%PAPER%" == "" (
|
||||||
|
set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS%
|
||||||
|
set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS%
|
||||||
|
)
|
||||||
|
|
||||||
|
if "%1" == "" goto help
|
||||||
|
|
||||||
|
if "%1" == "help" (
|
||||||
|
:help
|
||||||
|
echo.Please use `make ^<target^>` where ^<target^> is one of
|
||||||
|
echo. html to make standalone HTML files
|
||||||
|
echo. dirhtml to make HTML files named index.html in directories
|
||||||
|
echo. singlehtml to make a single large HTML file
|
||||||
|
echo. pickle to make pickle files
|
||||||
|
echo. json to make JSON files
|
||||||
|
echo. htmlhelp to make HTML files and a HTML help project
|
||||||
|
echo. qthelp to make HTML files and a qthelp project
|
||||||
|
echo. devhelp to make HTML files and a Devhelp project
|
||||||
|
echo. epub to make an epub
|
||||||
|
echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter
|
||||||
|
echo. text to make text files
|
||||||
|
echo. man to make manual pages
|
||||||
|
echo. texinfo to make Texinfo files
|
||||||
|
echo. gettext to make PO message catalogs
|
||||||
|
echo. changes to make an overview over all changed/added/deprecated items
|
||||||
|
echo. xml to make Docutils-native XML files
|
||||||
|
echo. pseudoxml to make pseudoxml-XML files for display purposes
|
||||||
|
echo. linkcheck to check all external links for integrity
|
||||||
|
echo. doctest to run all doctests embedded in the documentation if enabled
|
||||||
|
goto end
|
||||||
|
)
|
||||||
|
|
||||||
|
if "%1" == "clean" (
|
||||||
|
for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i
|
||||||
|
del /q /s %BUILDDIR%\*
|
||||||
|
goto end
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
%SPHINXBUILD% 2> nul
|
||||||
|
if errorlevel 9009 (
|
||||||
|
echo.
|
||||||
|
echo.The 'sphinx-build' command was not found. Make sure you have Sphinx
|
||||||
|
echo.installed, then set the SPHINXBUILD environment variable to point
|
||||||
|
echo.to the full path of the 'sphinx-build' executable. Alternatively you
|
||||||
|
echo.may add the Sphinx directory to PATH.
|
||||||
|
echo.
|
||||||
|
echo.If you don't have Sphinx installed, grab it from
|
||||||
|
echo.https://sphinx-doc.org/
|
||||||
|
exit /b 1
|
||||||
|
)
|
||||||
|
|
||||||
|
if "%1" == "html" (
|
||||||
|
%SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html
|
||||||
|
if errorlevel 1 exit /b 1
|
||||||
|
echo.
|
||||||
|
echo.Build finished. The HTML pages are in %BUILDDIR%/html.
|
||||||
|
goto end
|
||||||
|
)
|
||||||
|
|
||||||
|
if "%1" == "dirhtml" (
|
||||||
|
%SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml
|
||||||
|
if errorlevel 1 exit /b 1
|
||||||
|
echo.
|
||||||
|
echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml.
|
||||||
|
goto end
|
||||||
|
)
|
||||||
|
|
||||||
|
if "%1" == "singlehtml" (
|
||||||
|
%SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml
|
||||||
|
if errorlevel 1 exit /b 1
|
||||||
|
echo.
|
||||||
|
echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml.
|
||||||
|
goto end
|
||||||
|
)
|
||||||
|
|
||||||
|
if "%1" == "pickle" (
|
||||||
|
%SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle
|
||||||
|
if errorlevel 1 exit /b 1
|
||||||
|
echo.
|
||||||
|
echo.Build finished; now you can process the pickle files.
|
||||||
|
goto end
|
||||||
|
)
|
||||||
|
|
||||||
|
if "%1" == "json" (
|
||||||
|
%SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json
|
||||||
|
if errorlevel 1 exit /b 1
|
||||||
|
echo.
|
||||||
|
echo.Build finished; now you can process the JSON files.
|
||||||
|
goto end
|
||||||
|
)
|
||||||
|
|
||||||
|
if "%1" == "htmlhelp" (
|
||||||
|
%SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp
|
||||||
|
if errorlevel 1 exit /b 1
|
||||||
|
echo.
|
||||||
|
echo.Build finished; now you can run HTML Help Workshop with the ^
|
||||||
|
.hhp project file in %BUILDDIR%/htmlhelp.
|
||||||
|
goto end
|
||||||
|
)
|
||||||
|
|
||||||
|
if "%1" == "qthelp" (
|
||||||
|
%SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp
|
||||||
|
if errorlevel 1 exit /b 1
|
||||||
|
echo.
|
||||||
|
echo.Build finished; now you can run "qcollectiongenerator" with the ^
|
||||||
|
.qhcp project file in %BUILDDIR%/qthelp, like this:
|
||||||
|
echo.^> qcollectiongenerator %BUILDDIR%\qthelp\python-escpos.qhcp
|
||||||
|
echo.To view the help file:
|
||||||
|
echo.^> assistant -collectionFile %BUILDDIR%\qthelp\python-escpos.ghc
|
||||||
|
goto end
|
||||||
|
)
|
||||||
|
|
||||||
|
if "%1" == "devhelp" (
|
||||||
|
%SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp
|
||||||
|
if errorlevel 1 exit /b 1
|
||||||
|
echo.
|
||||||
|
echo.Build finished.
|
||||||
|
goto end
|
||||||
|
)
|
||||||
|
|
||||||
|
if "%1" == "epub" (
|
||||||
|
%SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub
|
||||||
|
if errorlevel 1 exit /b 1
|
||||||
|
echo.
|
||||||
|
echo.Build finished. The epub file is in %BUILDDIR%/epub.
|
||||||
|
goto end
|
||||||
|
)
|
||||||
|
|
||||||
|
if "%1" == "latex" (
|
||||||
|
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
|
||||||
|
if errorlevel 1 exit /b 1
|
||||||
|
echo.
|
||||||
|
echo.Build finished; the LaTeX files are in %BUILDDIR%/latex.
|
||||||
|
goto end
|
||||||
|
)
|
||||||
|
|
||||||
|
if "%1" == "latexpdf" (
|
||||||
|
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
|
||||||
|
cd %BUILDDIR%/latex
|
||||||
|
make all-pdf
|
||||||
|
cd %BUILDDIR%/..
|
||||||
|
echo.
|
||||||
|
echo.Build finished; the PDF files are in %BUILDDIR%/latex.
|
||||||
|
goto end
|
||||||
|
)
|
||||||
|
|
||||||
|
if "%1" == "latexpdfja" (
|
||||||
|
%SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex
|
||||||
|
cd %BUILDDIR%/latex
|
||||||
|
make all-pdf-ja
|
||||||
|
cd %BUILDDIR%/..
|
||||||
|
echo.
|
||||||
|
echo.Build finished; the PDF files are in %BUILDDIR%/latex.
|
||||||
|
goto end
|
||||||
|
)
|
||||||
|
|
||||||
|
if "%1" == "text" (
|
||||||
|
%SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text
|
||||||
|
if errorlevel 1 exit /b 1
|
||||||
|
echo.
|
||||||
|
echo.Build finished. The text files are in %BUILDDIR%/text.
|
||||||
|
goto end
|
||||||
|
)
|
||||||
|
|
||||||
|
if "%1" == "man" (
|
||||||
|
%SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man
|
||||||
|
if errorlevel 1 exit /b 1
|
||||||
|
echo.
|
||||||
|
echo.Build finished. The manual pages are in %BUILDDIR%/man.
|
||||||
|
goto end
|
||||||
|
)
|
||||||
|
|
||||||
|
if "%1" == "texinfo" (
|
||||||
|
%SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo
|
||||||
|
if errorlevel 1 exit /b 1
|
||||||
|
echo.
|
||||||
|
echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo.
|
||||||
|
goto end
|
||||||
|
)
|
||||||
|
|
||||||
|
if "%1" == "gettext" (
|
||||||
|
%SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale
|
||||||
|
if errorlevel 1 exit /b 1
|
||||||
|
echo.
|
||||||
|
echo.Build finished. The message catalogs are in %BUILDDIR%/locale.
|
||||||
|
goto end
|
||||||
|
)
|
||||||
|
|
||||||
|
if "%1" == "changes" (
|
||||||
|
%SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes
|
||||||
|
if errorlevel 1 exit /b 1
|
||||||
|
echo.
|
||||||
|
echo.The overview file is in %BUILDDIR%/changes.
|
||||||
|
goto end
|
||||||
|
)
|
||||||
|
|
||||||
|
if "%1" == "linkcheck" (
|
||||||
|
%SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck
|
||||||
|
if errorlevel 1 exit /b 1
|
||||||
|
echo.
|
||||||
|
echo.Link check complete; look for any errors in the above output ^
|
||||||
|
or in %BUILDDIR%/linkcheck/output.txt.
|
||||||
|
goto end
|
||||||
|
)
|
||||||
|
|
||||||
|
if "%1" == "doctest" (
|
||||||
|
%SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest
|
||||||
|
if errorlevel 1 exit /b 1
|
||||||
|
echo.
|
||||||
|
echo.Testing of doctests in the sources finished, look at the ^
|
||||||
|
results in %BUILDDIR%/doctest/output.txt.
|
||||||
|
goto end
|
||||||
|
)
|
||||||
|
|
||||||
|
if "%1" == "xml" (
|
||||||
|
%SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml
|
||||||
|
if errorlevel 1 exit /b 1
|
||||||
|
echo.
|
||||||
|
echo.Build finished. The XML files are in %BUILDDIR%/xml.
|
||||||
|
goto end
|
||||||
|
)
|
||||||
|
|
||||||
|
if "%1" == "pseudoxml" (
|
||||||
|
%SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml
|
||||||
|
if errorlevel 1 exit /b 1
|
||||||
|
echo.
|
||||||
|
echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml.
|
||||||
|
goto end
|
||||||
|
)
|
||||||
|
|
||||||
|
:end
|
11
doc/printer_profiles/available-encodings.rst
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
Available Encodings
|
||||||
|
-------------------
|
||||||
|
:Last Reviewed: 2023-08-10
|
||||||
|
|
||||||
|
If you find any issues with the described encodings,
|
||||||
|
please open an issue in the
|
||||||
|
`ESC/POS printer database <https://github.com/receipt-print-hq/escpos-printer-db>`_.
|
||||||
|
The data shown here is directly taken from there.
|
||||||
|
|
||||||
|
.. datatemplate:json:: ../../capabilities-data/dist/capabilities.json
|
||||||
|
:template: capabilities-template-encoding.jinja
|
18
doc/printer_profiles/available-profiles.rst
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
.. _available-profiles:
|
||||||
|
|
||||||
|
Available Profiles
|
||||||
|
------------------
|
||||||
|
:Last Reviewed: 2023-08-10
|
||||||
|
|
||||||
|
The following list describes which printer profiles are
|
||||||
|
available in this release.
|
||||||
|
The existence of a profile is a hint, but no guarantee
|
||||||
|
that this printer actually can be controlled by this library.
|
||||||
|
|
||||||
|
If you find any issues with the described capabilities,
|
||||||
|
please open an issue in the
|
||||||
|
`ESC/POS printer database <https://github.com/receipt-print-hq/escpos-printer-db>`_.
|
||||||
|
The data shown here is directly taken from there.
|
||||||
|
|
||||||
|
.. datatemplate:json:: ../../capabilities-data/dist/capabilities.json
|
||||||
|
:template: capabilities-template.jinja
|
26
doc/printer_profiles/capabilities.rst
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
.. _capabilities-profile-intro:
|
||||||
|
|
||||||
|
Capabilities
|
||||||
|
------------
|
||||||
|
:Last Reviewed: 2023-08-10
|
||||||
|
|
||||||
|
Since the used command set often differs between printers,
|
||||||
|
a model for supporting different printers is implemented.
|
||||||
|
This feature is called `capabilities`.
|
||||||
|
|
||||||
|
The `capabilities`-feature allows this library to know
|
||||||
|
which features are supported.
|
||||||
|
If no further information is specified, python-escpos will
|
||||||
|
try to automatically use features based on the supplied information.
|
||||||
|
|
||||||
|
In order to use the `capabilities`-database, the printer instance
|
||||||
|
simply has to be created with the parameter `profile` set to the
|
||||||
|
relevant identifier.
|
||||||
|
The identifier can be found in :ref:`available-profiles`.
|
||||||
|
|
||||||
|
This documentation describes the profiles in the database file that
|
||||||
|
is bundled with this release.
|
||||||
|
If another configuration is to be used, this chapter can be followed
|
||||||
|
for information on how to side-load another `capabilities`-database:
|
||||||
|
:ref:`advanced-usage-change-capabilities-profile`.
|
||||||
|
|
BIN
doc/pyescpos.ico
Normal file
After Width: | Height: | Size: 162 KiB |
16
doc/requirements.txt
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
pyusb
|
||||||
|
Pillow>=2.0
|
||||||
|
qrcode>=4.0
|
||||||
|
pyserial
|
||||||
|
sphinx-rtd-theme==2.0.0
|
||||||
|
setuptools
|
||||||
|
setuptools-scm
|
||||||
|
docutils>=0.12
|
||||||
|
sphinxcontrib-spelling>=7.2.0
|
||||||
|
python-barcode>=0.15.0,<1
|
||||||
|
importlib-metadata
|
||||||
|
importlib_resources
|
||||||
|
sphinxcontrib.datatemplates
|
||||||
|
sphinx-argparse
|
||||||
|
sphinx-autodoc-typehints
|
||||||
|
pycups
|
130
doc/spelling_wordlist.txt
Normal file
@@ -0,0 +1,130 @@
|
|||||||
|
ESC
|
||||||
|
Esc
|
||||||
|
POS
|
||||||
|
Pos
|
||||||
|
Escpos
|
||||||
|
Escpos
|
||||||
|
escpos
|
||||||
|
|
||||||
|
bitImageColumn
|
||||||
|
bitImageRaster
|
||||||
|
ep
|
||||||
|
pc
|
||||||
|
cp
|
||||||
|
|
||||||
|
csoft
|
||||||
|
Frédéric
|
||||||
|
Headcrash
|
||||||
|
Krispy
|
||||||
|
primax
|
||||||
|
Tahri
|
||||||
|
reck
|
||||||
|
mrwunderbar
|
||||||
|
zouppen
|
||||||
|
kedare
|
||||||
|
Foaly
|
||||||
|
brendanhowell
|
||||||
|
der
|
||||||
|
fvdsn
|
||||||
|
Marull
|
||||||
|
Paretas
|
||||||
|
Kakistocrat
|
||||||
|
Billington
|
||||||
|
patkan
|
||||||
|
Romain
|
||||||
|
Bougakov
|
||||||
|
Yaisel
|
||||||
|
Hurtado
|
||||||
|
Wagenbach
|
||||||
|
Poca
|
||||||
|
Akram
|
||||||
|
Vieira
|
||||||
|
Christoph
|
||||||
|
Heuel
|
||||||
|
Thijs
|
||||||
|
Triemstra
|
||||||
|
Linder
|
||||||
|
Romain
|
||||||
|
Pulgarin
|
||||||
|
Romain
|
||||||
|
Cheng
|
||||||
|
Dmytro
|
||||||
|
Katyukha
|
||||||
|
Elsdörfer
|
||||||
|
Asuki
|
||||||
|
Kono
|
||||||
|
López
|
||||||
|
mashedkeyboard
|
||||||
|
Thijs
|
||||||
|
Triemstra
|
||||||
|
Elsdörfer
|
||||||
|
Renato
|
||||||
|
Lorenzi
|
||||||
|
Bookham
|
||||||
|
Goglin
|
||||||
|
Christoph
|
||||||
|
Heuel
|
||||||
|
Qian
|
||||||
|
Lehtonen
|
||||||
|
Kanzler
|
||||||
|
Rotondo
|
||||||
|
Alexandre
|
||||||
|
Detiste
|
||||||
|
|
||||||
|
barcode
|
||||||
|
barcodes
|
||||||
|
baudrate
|
||||||
|
Bashlinux
|
||||||
|
capabilities
|
||||||
|
cashdraw
|
||||||
|
charcode
|
||||||
|
changelog
|
||||||
|
cheque
|
||||||
|
codebase
|
||||||
|
codecov
|
||||||
|
codepages
|
||||||
|
config
|
||||||
|
del
|
||||||
|
dev
|
||||||
|
dialout
|
||||||
|
docstrings
|
||||||
|
ean
|
||||||
|
Ean
|
||||||
|
encodable
|
||||||
|
fff
|
||||||
|
fullimage
|
||||||
|
io
|
||||||
|
json
|
||||||
|
latin
|
||||||
|
libusb
|
||||||
|
lp
|
||||||
|
lsusb
|
||||||
|
natively
|
||||||
|
php
|
||||||
|
pre
|
||||||
|
prefilled
|
||||||
|
printcap
|
||||||
|
programmatically
|
||||||
|
py
|
||||||
|
pypy
|
||||||
|
pyyaml
|
||||||
|
px
|
||||||
|
qrcode
|
||||||
|
Raspbian
|
||||||
|
rebase
|
||||||
|
rebased
|
||||||
|
resetted
|
||||||
|
rst
|
||||||
|
submodule
|
||||||
|
submodules
|
||||||
|
src
|
||||||
|
testcases
|
||||||
|
th
|
||||||
|
Todo
|
||||||
|
traceback
|
||||||
|
udev
|
||||||
|
usb
|
||||||
|
usec
|
||||||
|
virtualenvs
|
||||||
|
whitespaces
|
||||||
|
xml
|
47
doc/user/barcode.rst
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
Printing Barcodes
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
:Last Reviewed: 2023-08-10
|
||||||
|
|
||||||
|
Many printers implement barcode printing natively.
|
||||||
|
These hardware rendered barcodes are fast but the supported
|
||||||
|
formats are limited by the printer itself and different between models.
|
||||||
|
However, almost all printers support printing images, so barcode
|
||||||
|
rendering can be performed externally by software and then sent
|
||||||
|
to the printer as an image.
|
||||||
|
As a drawback, this operation is much slower and the user needs
|
||||||
|
to know and choose the image implementation method supported by
|
||||||
|
the printer's command-set.
|
||||||
|
|
||||||
|
barcode-method
|
||||||
|
~~~~~~~~~~~~~~
|
||||||
|
Since version 3.0, the ``barcode`` method unifies the previous
|
||||||
|
``barcode`` (hardware) and ``soft_barcode`` (software) methods.
|
||||||
|
It is able to choose automatically the best printer implementation
|
||||||
|
for barcode printing based on the capabilities of the printer
|
||||||
|
and the type of barcode desired.
|
||||||
|
To achieve this, it relies on the information contained in the
|
||||||
|
escpos-printer-db profiles.
|
||||||
|
The chosen profile needs to match the capabilities of the printer
|
||||||
|
as closely as possible.
|
||||||
|
|
||||||
|
.. py:currentmodule:: escpos.escpos
|
||||||
|
|
||||||
|
.. automethod:: Escpos.barcode
|
||||||
|
:noindex:
|
||||||
|
|
||||||
|
CODE128
|
||||||
|
~~~~~~~
|
||||||
|
Code128 barcodes need a certain format.
|
||||||
|
For now the user has to make sure that the payload is correct.
|
||||||
|
For alphanumeric CODE128 you have to preface your payload with `{B`.
|
||||||
|
|
||||||
|
.. code-block:: Python
|
||||||
|
|
||||||
|
from escpos.printer import Dummy, Serial
|
||||||
|
p = Serial()
|
||||||
|
# print CODE128 012ABCDabcd
|
||||||
|
p.barcode("{B012ABCDabcd", "CODE128", function_type="B")
|
||||||
|
|
||||||
|
A very good description on CODE128 is also on
|
||||||
|
`Wikipedia <https://en.wikipedia.org/wiki/Code_128>`_.
|
10
doc/user/cli-user.rst
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
CLI
|
||||||
|
===
|
||||||
|
|
||||||
|
:Last Reviewed: 2023-09-25
|
||||||
|
|
||||||
|
Documentation of the command line interface, callable with ``python-escpos``.
|
||||||
|
|
||||||
|
.. argparse::
|
||||||
|
:ref: escpos.cli.generate_parser
|
||||||
|
:prog: python-escpos
|
77
doc/user/installation.rst
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
.. _user_installation:
|
||||||
|
|
||||||
|
Installation
|
||||||
|
============
|
||||||
|
|
||||||
|
:Last Reviewed: 2023-08-10
|
||||||
|
|
||||||
|
Installation with PIP
|
||||||
|
---------------------
|
||||||
|
Installation should be rather straight-forward. python-escpos is on PyPi,
|
||||||
|
so you can simply enter:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
pip install python-escpos[all]
|
||||||
|
|
||||||
|
This should install all necessary dependencies. Apart from that
|
||||||
|
python-escpos is for some versions also available as a Debian package.
|
||||||
|
If you want to always benefit from the newest stable releases you should
|
||||||
|
always install from PyPi.
|
||||||
|
If you use the ``--pre`` parameter for ``pip``, you will get the latest
|
||||||
|
pre-release.
|
||||||
|
|
||||||
|
The following installation options exist:
|
||||||
|
|
||||||
|
* `all`: install all packages available for this platform
|
||||||
|
* `usb`: install packages required for USB printers
|
||||||
|
* `serial`: install packages required for serial printers
|
||||||
|
* `win32`: install packages required for win32 printing (only Windows)
|
||||||
|
* `cups`: install packages required for CUPS printing
|
||||||
|
|
||||||
|
Other installation methods
|
||||||
|
--------------------------
|
||||||
|
Officially, no other installation methods are supplied.
|
||||||
|
|
||||||
|
If you want to install nevertheless from another source,
|
||||||
|
please make sure that you have received the correct package
|
||||||
|
and that the capabilities data is properly integrated.
|
||||||
|
When packaging from source please read the developer
|
||||||
|
information in :ref:`developer-manual-repository`.
|
||||||
|
|
||||||
|
If your packaging method breaks the resource system from setuptools,
|
||||||
|
it might be necessary to supply the path to the capabilities file:
|
||||||
|
:ref:`advanced-usage-change-capabilities-profile`.
|
||||||
|
|
||||||
|
Setup udev for USB-Printers
|
||||||
|
---------------------------
|
||||||
|
1. Get the *Product ID* and *Vendor ID* from the lsusb command
|
||||||
|
``# lsusb Bus 002 Device 001: ID 1a2b:1a2b Device name``.
|
||||||
|
(Or whichever way your system supplies to get the PID and VID.)
|
||||||
|
|
||||||
|
2. Create a udev rule to let users belonging to *dialout* group use the
|
||||||
|
printer. You can create the file
|
||||||
|
``/etc/udev/rules.d/99-escpos.rules`` and add the following:
|
||||||
|
``SUBSYSTEM=="usb", ATTRS{idVendor}=="1a2b", ATTRS{idProduct}=="1a2b", MODE="0664", GROUP="dialout"``
|
||||||
|
Replace *idVendor* and *idProduct* hex numbers with the ones that you
|
||||||
|
got from the previous step. Note that you can either, add yourself to
|
||||||
|
"dialout" group, or use another group you already belongs instead
|
||||||
|
"dialout" and set it in the ``GROUP`` parameter in the above rule.
|
||||||
|
|
||||||
|
3. Restart udev ``# sudo service udev restart`` In some new systems it
|
||||||
|
is done with ``# sudo udevadm control --reload``
|
||||||
|
|
||||||
|
Enabling tab-completion in CLI
|
||||||
|
------------------------------
|
||||||
|
python-escpos has a CLI with tab-completion.
|
||||||
|
This is realized with ``argcomplete``.
|
||||||
|
In order for this to work you have to enable tab-completion, which is described in
|
||||||
|
the `manual of argcomplete <https://argcomplete.readthedocs.io>`__.
|
||||||
|
|
||||||
|
If you only want to enable it for python-escpos, or global activation does not work, try this:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
eval "$(register-python-argcomplete python-escpos)"
|
||||||
|
|
||||||
|
|
17
doc/user/methods.rst
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
Methods
|
||||||
|
=======
|
||||||
|
|
||||||
|
:Last Reviewed: 2023-08-10
|
||||||
|
|
||||||
|
Escpos class
|
||||||
|
------------
|
||||||
|
|
||||||
|
The core part of the API of this library is the Escpos class.
|
||||||
|
You use it by instantiating a :doc:`printer <printers>` which is a child of Escpos.
|
||||||
|
The following methods are available:
|
||||||
|
|
||||||
|
.. autoclass:: escpos.escpos.Escpos
|
||||||
|
:members:
|
||||||
|
:member-order: bysource
|
||||||
|
:noindex:
|
||||||
|
|
123
doc/user/printers.rst
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
Printers
|
||||||
|
========
|
||||||
|
|
||||||
|
:Last Reviewed: 2023-08-23
|
||||||
|
|
||||||
|
As of now there are 8 different types of printer implementations.
|
||||||
|
|
||||||
|
USB
|
||||||
|
---
|
||||||
|
The USB-class uses pyusb and libusb to communicate with USB-based
|
||||||
|
printers.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
This driver is not suited for USB-to-Serial-adapters
|
||||||
|
and similar devices, but only for those implementing native USB.
|
||||||
|
|
||||||
|
.. autoclass:: escpos.printer.Usb
|
||||||
|
:members:
|
||||||
|
:special-members:
|
||||||
|
:member-order: bysource
|
||||||
|
:noindex:
|
||||||
|
|
||||||
|
Serial
|
||||||
|
------
|
||||||
|
This driver uses pyserial in order to communicate with serial devices.
|
||||||
|
If you are using an USB-based adapter to connect to the serial port,
|
||||||
|
then you should also use this driver.
|
||||||
|
The configuration is often based on DIP-switches that you can set on your
|
||||||
|
printer. For the hardware-configuration please refer to your printer's manual.
|
||||||
|
|
||||||
|
.. autoclass:: escpos.printer.Serial
|
||||||
|
:members:
|
||||||
|
:special-members:
|
||||||
|
:member-order: bysource
|
||||||
|
:noindex:
|
||||||
|
|
||||||
|
Network
|
||||||
|
-------
|
||||||
|
|
||||||
|
This driver is based on the socket class.
|
||||||
|
|
||||||
|
.. autoclass:: escpos.printer.Network
|
||||||
|
:members:
|
||||||
|
:special-members:
|
||||||
|
:member-order: bysource
|
||||||
|
:noindex:
|
||||||
|
|
||||||
|
Troubleshooting
|
||||||
|
^^^^^^^^^^^^^^^
|
||||||
|
Problems with a network-attached printer can have numerous causes.
|
||||||
|
Make sure that your device has a proper IP address.
|
||||||
|
Often you can check the IP address by triggering the self-test of the device.
|
||||||
|
As a next step try to send text manually to the device.
|
||||||
|
You could use for example:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
echo "OK\n" | nc IPADDRESS 9100
|
||||||
|
# the port number is often 9100
|
||||||
|
|
||||||
|
As a last resort try to reset the interface of the printer.
|
||||||
|
This should be described in its manual.
|
||||||
|
|
||||||
|
File
|
||||||
|
----
|
||||||
|
This printer "prints" just into a file-handle.
|
||||||
|
Especially on \*nix-systems this comes very handy.
|
||||||
|
|
||||||
|
.. autoclass:: escpos.printer.File
|
||||||
|
:members:
|
||||||
|
:special-members:
|
||||||
|
:member-order: bysource
|
||||||
|
:noindex:
|
||||||
|
|
||||||
|
Dummy
|
||||||
|
-----
|
||||||
|
The Dummy-printer is mainly for testing- and debugging-purposes.
|
||||||
|
It stores all of the "output" as raw ESC/POS in a string and returns that.
|
||||||
|
|
||||||
|
.. autoclass:: escpos.printer.Dummy
|
||||||
|
:members:
|
||||||
|
:member-order: bysource
|
||||||
|
:noindex:
|
||||||
|
|
||||||
|
CUPS
|
||||||
|
----
|
||||||
|
This driver uses `pycups` in order to communicate with a CUPS server.
|
||||||
|
Supports both local and remote CUPS printers and servers.
|
||||||
|
The printer must be properly configured in CUPS administration.
|
||||||
|
The connector generates a print job that is added to the CUPS queue.
|
||||||
|
|
||||||
|
.. autoclass:: escpos.printer.CupsPrinter
|
||||||
|
:members:
|
||||||
|
:member-order: bysource
|
||||||
|
:noindex:
|
||||||
|
|
||||||
|
LP
|
||||||
|
----
|
||||||
|
This driver uses the UNIX command `lp` in order to communicate with a CUPS server.
|
||||||
|
Supports local and remote CUPS printers.
|
||||||
|
The printer must be properly configured in CUPS administration.
|
||||||
|
The connector spawns a new sub-process where the command lp is executed.
|
||||||
|
|
||||||
|
No dependencies required, but somehow the print queue will affect some
|
||||||
|
print job such as barcode.
|
||||||
|
|
||||||
|
.. autoclass:: escpos.printer.LP
|
||||||
|
:members:
|
||||||
|
:special-members:
|
||||||
|
:member-order: bysource
|
||||||
|
:noindex:
|
||||||
|
|
||||||
|
Win32Raw
|
||||||
|
--------
|
||||||
|
This driver uses a native WIN32 interface of Windows in order to print.
|
||||||
|
Please refer to the code for documentation as this driver is currently
|
||||||
|
not included in the documentation build.
|
||||||
|
|
||||||
|
.. autoclass:: escpos.printer.Win32Raw
|
||||||
|
:members:
|
||||||
|
:special-members:
|
||||||
|
:member-order: bysource
|
||||||
|
:noindex:
|
26
doc/user/raspi.rst
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
Raspberry Pi
|
||||||
|
============
|
||||||
|
|
||||||
|
:Last Reviewed: 2023-08-10
|
||||||
|
|
||||||
|
.. warning:: You should **never** directly connect an printer with RS232-interface
|
||||||
|
(serial port) directly to a Raspberry PI or similar interface
|
||||||
|
(e.g. those simple USB-sticks without encasing).
|
||||||
|
Those interfaces are based on 5V- or 3,3V-logic
|
||||||
|
(the latter in the case of Raspberry PI).
|
||||||
|
Classical RS232 uses 12V-logic and would **thus destroy your interface**.
|
||||||
|
Connect both systems with an appropriate *level shifter*.
|
||||||
|
|
||||||
|
Installation
|
||||||
|
------------
|
||||||
|
The installation should be performed as described in :ref:`user_installation`.
|
||||||
|
|
||||||
|
Run
|
||||||
|
---
|
||||||
|
You can run this software as on any other Linux system.
|
||||||
|
|
||||||
|
Attach your printer and test it with the example code in the project's set of examples.
|
||||||
|
You can find that in the
|
||||||
|
`project-repository <https://github.com/python-escpos/python-escpos>`__.
|
||||||
|
|
||||||
|
For more details on this check the :doc:`installation-manual <installation>`.
|
315
doc/user/usage.rst
Normal file
@@ -0,0 +1,315 @@
|
|||||||
|
Usage
|
||||||
|
=====
|
||||||
|
|
||||||
|
:Last Reviewed: 2023-08-10
|
||||||
|
|
||||||
|
Define your printer
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
USB printer
|
||||||
|
^^^^^^^^^^^
|
||||||
|
|
||||||
|
Before creating your Python ESC/POS printer instance, consult the system to obtain
|
||||||
|
the printer parameters. This is done with the 'lsusb' command.
|
||||||
|
|
||||||
|
Run the command and look for the "Vendor ID" and "Product ID" and write
|
||||||
|
down the values. These values are displayed just before the name
|
||||||
|
of the device with the following format:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
xxxx:xxxx
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
# lsusb
|
||||||
|
Bus 002 Device 001: ID 04b8:0202 Epson ...
|
||||||
|
|
||||||
|
Write down the the values in question, then issue the following command
|
||||||
|
so you can get the "Interface" number and "End Point"
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
# lsusb -vvv -d xxxx:xxxx | grep iInterface
|
||||||
|
iInterface 0
|
||||||
|
# lsusb -vvv -d xxxx:xxxx | grep bEndpointAddress | grep OUT
|
||||||
|
bEndpointAddress 0x01 EP 1 OUT
|
||||||
|
|
||||||
|
The first command will yield the "Interface" number that must be handy
|
||||||
|
to have and the second yields the "Output Endpoint" address.
|
||||||
|
|
||||||
|
**USB Printer initialization**
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
p = printer.Usb(0x04b8,0x0202)
|
||||||
|
|
||||||
|
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
|
||||||
|
your instance. So, assuming that we have another printer, CT-S2000,
|
||||||
|
manufactured by Citizen (with "Vendor ID" of 2730 and "Product ID" of 0fff)
|
||||||
|
where in\_ep is on 0x81 and out\_ep=0x02, then the printer definition should
|
||||||
|
look like:
|
||||||
|
|
||||||
|
**Generic USB Printer initialization**
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
p = printer.Usb(0x2730, 0x0fff, 0, 0x81, 0x02)
|
||||||
|
|
||||||
|
Network printer
|
||||||
|
^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
You only need the IP of your printer, either because it is getting its
|
||||||
|
IP by DHCP or you set it manually.
|
||||||
|
|
||||||
|
**Network Printer initialization**
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
p = printer.Network("192.168.1.99")
|
||||||
|
|
||||||
|
Serial printer
|
||||||
|
^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
Most of the default values set by the DIP switches for the serial
|
||||||
|
printers, have been set as default on the serial printer class, so the
|
||||||
|
only thing you need to know is which serial port the printer is connected
|
||||||
|
to.
|
||||||
|
|
||||||
|
**Serial printer initialization**
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
p = printer.Serial("/dev/tty0")
|
||||||
|
|
||||||
|
# on a Windows OS serial devices are typically accessible as COM
|
||||||
|
p = printer.Serial("COM1")
|
||||||
|
|
||||||
|
Other printers
|
||||||
|
^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
Some printers under `/dev` can't be used or initialized with any of the
|
||||||
|
methods described above. Usually, those are printers used by printcap,
|
||||||
|
however, if you know the device name, you could try to initialize by
|
||||||
|
passing the device node name.
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
p = printer.File("/dev/usb/lp1")
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
Define your instance
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
The following example demonstrates how to initialize the Epson TM-TI88IV
|
||||||
|
on a USB interface.
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
from escpos import *
|
||||||
|
""" Seiko Epson Corp. Receipt Printer M129 Definitions (EPSON TM-T88IV) """
|
||||||
|
p = printer.Usb(0x04b8,0x0202)
|
||||||
|
# Print text
|
||||||
|
p.text("Hello World\n")
|
||||||
|
# Print image
|
||||||
|
p.image("logo.gif")
|
||||||
|
# Print QR Code
|
||||||
|
p.qr("You can readme from your smartphone")
|
||||||
|
# Print barcode
|
||||||
|
p.barcode('4006381333931','EAN13',64,2,'','')
|
||||||
|
# Cut paper
|
||||||
|
p.cut()
|
||||||
|
|
||||||
|
Standard python constraints on libraries apply. This means especially
|
||||||
|
that you should not name the script in which you implement these lines
|
||||||
|
should not be named ``escpos`` as this would collide with the name of
|
||||||
|
the library.
|
||||||
|
|
||||||
|
Configuration File
|
||||||
|
------------------
|
||||||
|
|
||||||
|
You can create a configuration file for python-escpos. This will
|
||||||
|
allow you to use the CLI, and skip some setup when using the library
|
||||||
|
programmatically.
|
||||||
|
|
||||||
|
The default configuration file is named ``config.yaml`` and uses the YAML
|
||||||
|
format. For windows it is probably at::
|
||||||
|
|
||||||
|
%appdata%/python-escpos/config.yaml
|
||||||
|
|
||||||
|
And for linux::
|
||||||
|
|
||||||
|
$HOME/.config/python-escpos/config.yaml
|
||||||
|
|
||||||
|
If you are not sure, run::
|
||||||
|
|
||||||
|
from escpos import config
|
||||||
|
c = config.Config()
|
||||||
|
c.load()
|
||||||
|
|
||||||
|
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
|
||||||
|
the ``load()`` method.
|
||||||
|
|
||||||
|
To load the configured printer, run::
|
||||||
|
|
||||||
|
from escpos import config
|
||||||
|
c = config.Config()
|
||||||
|
printer = c.printer()
|
||||||
|
|
||||||
|
|
||||||
|
The printer section
|
||||||
|
^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
||||||
|
The ``printer`` configuration section defines a default printer to create.
|
||||||
|
|
||||||
|
The only required parameter is ``type``. The value of this has to be one of the
|
||||||
|
printers defined in :doc:`/user/printers`.
|
||||||
|
|
||||||
|
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::
|
||||||
|
|
||||||
|
printer:
|
||||||
|
type: File
|
||||||
|
devfile: /dev/someprinter
|
||||||
|
|
||||||
|
And for a network printer::
|
||||||
|
|
||||||
|
printer:
|
||||||
|
type: Network
|
||||||
|
host: 127.0.0.1
|
||||||
|
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
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
Python-escpos is designed to accept unicode.
|
||||||
|
|
||||||
|
For normal usage you can simply pass your text to the printers ``text()``-function. It will automatically guess
|
||||||
|
the right codepage and then send the encoded data to the printer. If this feature does not work, please try to
|
||||||
|
isolate the error and then create an issue on the GitHub project page.
|
||||||
|
|
||||||
|
If you want or need to you can manually set the codepage.
|
||||||
|
For this please use the ``charcode()``-function.
|
||||||
|
You can set any key-value that is in ``CHARCODE``.
|
||||||
|
If something is wrong, an ``CharCodeError`` will be raised.
|
||||||
|
After you have manually set the codepage the printer won't change it anymore.
|
||||||
|
You can revert to normal behavior by setting charcode to ``AUTO``.
|
||||||
|
|
||||||
|
Advanced Usage: Print from binary blob
|
||||||
|
--------------------------------------
|
||||||
|
|
||||||
|
Imagine you have a file with ESC/POS-commands in binary form. This could be useful for testing capabilities of your
|
||||||
|
printer with a known working combination of commands.
|
||||||
|
You can print this data with the following code, using the standard methods of python-escpos. (This is an
|
||||||
|
advantage of the fact that `_raw()` accepts binary strings.)
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
from escpos import printer
|
||||||
|
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
|
||||||
|
data = file.read()
|
||||||
|
file.close()
|
||||||
|
|
||||||
|
p._raw(data)
|
||||||
|
|
||||||
|
That's all, the printer should then print your data. You can also use this technique to let others reproduce an issue
|
||||||
|
that you have found. (Just "print" your commands to a File-printer on your local filesystem.)
|
||||||
|
However, please keep in mind, that often it is easier and better to just supply the code that you are using.
|
||||||
|
|
||||||
|
Here you can download an example, that will print a set of common barcodes:
|
||||||
|
|
||||||
|
* :download:`barcode.bin </download/barcode.bin>` by `@mike42 <https://github.com/mike42>`_
|
||||||
|
|
||||||
|
.. _advanced-usage-change-capabilities-profile:
|
||||||
|
|
||||||
|
Advanced Usage: change capabilities-profile
|
||||||
|
-------------------------------------------
|
||||||
|
|
||||||
|
Packaged together with the escpos-code is a capabilities-file. This file in
|
||||||
|
JSON-format describes the capabilities of different printers. It is developed and hosted in
|
||||||
|
`escpos-printer-db <https://github.com/receipt-print-hq/escpos-printer-db>`_.
|
||||||
|
|
||||||
|
Certain applications like the usage of `cx_freeze <https://cx-freeze.readthedocs.io>`_ might change the
|
||||||
|
packaging structure. This leads to the capabilities-profile not being found.
|
||||||
|
In this case you can use the environment-variable `ESCPOS_CAPABILITIES_FILE`.
|
||||||
|
The following code is an example.
|
||||||
|
|
||||||
|
.. code-block:: shell
|
||||||
|
|
||||||
|
# use packaged capabilities-profile
|
||||||
|
python-escpos cut
|
||||||
|
|
||||||
|
# use capabilities-profile that you have put in /usr/python-escpos
|
||||||
|
export ESCPOS_CAPABILITIES_FILE=/usr/python-escpos/capabilities.json
|
||||||
|
python-escpos cut
|
||||||
|
|
||||||
|
# use packaged file again
|
||||||
|
unset ESCPOS_CAPABILITIES_FILE
|
||||||
|
python-escpos cut
|
||||||
|
|
||||||
|
|
||||||
|
Hint: preprocess printing
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
Printing images directly to the printer is rather slow.
|
||||||
|
One factor that slows down the process is the transmission over e.g. serial port.
|
||||||
|
|
||||||
|
Apart from configuring your printer to use the maximum baudrate (in the case of serial-printers), there is not much
|
||||||
|
that you can do.
|
||||||
|
However you could use the :py:class:`escpos.printer.Dummy`-printer to preprocess your image.
|
||||||
|
This is probably best explained by an example:
|
||||||
|
|
||||||
|
.. code-block:: Python
|
||||||
|
|
||||||
|
from escpos.printer import Serial, Dummy
|
||||||
|
|
||||||
|
p = Serial()
|
||||||
|
d = Dummy()
|
||||||
|
|
||||||
|
# create ESC/POS for the print job, this should go really fast
|
||||||
|
d.text("This is my image:\n")
|
||||||
|
d.image("funny_cat.png")
|
||||||
|
d.cut()
|
||||||
|
|
||||||
|
# send code to printer
|
||||||
|
p._raw(d.output)
|
||||||
|
|
||||||
|
This way you could also store the code in a file and print it later.
|
||||||
|
You could then for example print the code from another process than your main-program and thus reduce the waiting time.
|
||||||
|
(Of course this will not make the printer print faster.)
|
||||||
|
|
||||||
|
Troubleshooting
|
||||||
|
---------------
|
||||||
|
|
||||||
|
This section gathers various hints on troubleshooting.
|
||||||
|
|
||||||
|
Print with STAR TSP100 family
|
||||||
|
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
Printer of the STAR TSP100 family do not have a native ESC/POS mode, which
|
||||||
|
is why you will not be able to directly print with this library to the printer.
|
||||||
|
|
||||||
|
More information on this topic can be found in the online documentation of
|
||||||
|
`Star Micronics <https://www.starmicronics.com/help-center/knowledge-base/configure-tsp100-series-printers-esc-pos-mode/>`_
|
||||||
|
and the `discussion in the python-escpos project <https://github.com/python-escpos/python-escpos/issues/410>`_.
|
||||||
|
|
||||||
|
|
@@ -1 +0,0 @@
|
|||||||
__all__ = ["constants","escpos","exceptions","printer"]
|
|
@@ -1,86 +0,0 @@
|
|||||||
""" ESC/POS Commands (Constants) """
|
|
||||||
|
|
||||||
# Feed control sequences
|
|
||||||
CTL_LF = '\x0a' # Print and line feed
|
|
||||||
CTL_FF = '\x0c' # Form feed
|
|
||||||
CTL_CR = '\x0d' # Carriage return
|
|
||||||
CTL_HT = '\x09' # Horizontal tab
|
|
||||||
CTL_SET_HT = '\x1b\x44' # Set horizontal tab positions
|
|
||||||
CTL_VT = '\x1b\x64\x04' # Vertical tab
|
|
||||||
# Printer hardware
|
|
||||||
HW_INIT = '\x1b\x40' # Clear data in buffer and reset modes
|
|
||||||
HW_SELECT = '\x1b\x3d\x01' # Printer select
|
|
||||||
HW_RESET = '\x1b\x3f\x0a\x00' # Reset printer hardware
|
|
||||||
# Cash Drawer
|
|
||||||
CD_KICK_2 = '\x1b\x70\x00' # Sends a pulse to pin 2 []
|
|
||||||
CD_KICK_5 = '\x1b\x70\x01' # Sends a pulse to pin 5 []
|
|
||||||
# Paper
|
|
||||||
PAPER_FULL_CUT = '\x1d\x56\x00' # Full cut paper
|
|
||||||
PAPER_PART_CUT = '\x1d\x56\x01' # Partial cut paper
|
|
||||||
# Text format
|
|
||||||
TXT_NORMAL = '\x1b\x21\x00' # Normal text
|
|
||||||
TXT_2HEIGHT = '\x1b\x21\x10' # Double height text
|
|
||||||
TXT_2WIDTH = '\x1b\x21\x20' # Double width text
|
|
||||||
TXT_4SQUARE = '\x1b\x21\x30' # Quad area text
|
|
||||||
TXT_UNDERL_OFF = '\x1b\x2d\x00' # Underline font OFF
|
|
||||||
TXT_UNDERL_ON = '\x1b\x2d\x01' # Underline font 1-dot ON
|
|
||||||
TXT_UNDERL2_ON = '\x1b\x2d\x02' # Underline font 2-dot ON
|
|
||||||
TXT_BOLD_OFF = '\x1b\x45\x00' # Bold font OFF
|
|
||||||
TXT_BOLD_ON = '\x1b\x45\x01' # Bold font ON
|
|
||||||
TXT_FONT_A = '\x1b\x4d\x00' # Font type A
|
|
||||||
TXT_FONT_B = '\x1b\x4d\x01' # Font type B
|
|
||||||
TXT_ALIGN_LT = '\x1b\x61\x00' # Left justification
|
|
||||||
TXT_ALIGN_CT = '\x1b\x61\x01' # Centering
|
|
||||||
TXT_ALIGN_RT = '\x1b\x61\x02' # Right justification
|
|
||||||
# Char code table
|
|
||||||
CHARCODE_PC437 = '\x1b\x74\x00' # USA: Standard Europe
|
|
||||||
CHARCODE_JIS = '\x1b\x74\x01' # Japanese Katakana
|
|
||||||
CHARCODE_PC850 = '\x1b\x74\x02' # Multilingual
|
|
||||||
CHARCODE_PC860 = '\x1b\x74\x03' # Portuguese
|
|
||||||
CHARCODE_PC863 = '\x1b\x74\x04' # Canadian-French
|
|
||||||
CHARCODE_PC865 = '\x1b\x74\x05' # Nordic
|
|
||||||
CHARCODE_WEU = '\x1b\x74\x06' # Simplified Kanji, Hirakana
|
|
||||||
CHARCODE_GREEK = '\x1b\x74\x07' # Simplified Kanji
|
|
||||||
CHARCODE_HEBREW = '\x1b\x74\x08' # Simplified Kanji
|
|
||||||
CHARCODE_PC1252 = '\x1b\x74\x11' # Western European Windows Code Set
|
|
||||||
CHARCODE_PC866 = '\x1b\x74\x12' # Cirillic #2
|
|
||||||
CHARCODE_PC852 = '\x1b\x74\x13' # Latin 2
|
|
||||||
CHARCODE_PC858 = '\x1b\x74\x14' # Euro
|
|
||||||
CHARCODE_THAI42 = '\x1b\x74\x15' # Thai character code 42
|
|
||||||
CHARCODE_THAI11 = '\x1b\x74\x16' # Thai character code 11
|
|
||||||
CHARCODE_THAI13 = '\x1b\x74\x17' # Thai character code 13
|
|
||||||
CHARCODE_THAI14 = '\x1b\x74\x18' # Thai character code 14
|
|
||||||
CHARCODE_THAI16 = '\x1b\x74\x19' # Thai character code 16
|
|
||||||
CHARCODE_THAI17 = '\x1b\x74\x1a' # Thai character code 17
|
|
||||||
CHARCODE_THAI18 = '\x1b\x74\x1b' # Thai character code 18
|
|
||||||
# Barcode format
|
|
||||||
BARCODE_TXT_OFF = '\x1d\x48\x00' # HRI barcode chars OFF
|
|
||||||
BARCODE_TXT_ABV = '\x1d\x48\x01' # HRI barcode chars above
|
|
||||||
BARCODE_TXT_BLW = '\x1d\x48\x02' # HRI barcode chars below
|
|
||||||
BARCODE_TXT_BTH = '\x1d\x48\x03' # HRI barcode chars both above and below
|
|
||||||
BARCODE_FONT_A = '\x1d\x66\x00' # Font type A for HRI barcode chars
|
|
||||||
BARCODE_FONT_B = '\x1d\x66\x01' # Font type B for HRI barcode chars
|
|
||||||
BARCODE_HEIGHT = '\x1d\x68\x64' # Barcode Height [1-255]
|
|
||||||
BARCODE_WIDTH = '\x1d\x77\x03' # Barcode Width [2-6]
|
|
||||||
BARCODE_UPC_A = '\x1d\x6b\x00' # Barcode type UPC-A
|
|
||||||
BARCODE_UPC_E = '\x1d\x6b\x01' # Barcode type UPC-E
|
|
||||||
BARCODE_EAN13 = '\x1d\x6b\x02' # Barcode type EAN13
|
|
||||||
BARCODE_EAN8 = '\x1d\x6b\x03' # Barcode type EAN8
|
|
||||||
BARCODE_CODE39 = '\x1d\x6b\x04' # Barcode type CODE39
|
|
||||||
BARCODE_ITF = '\x1d\x6b\x05' # Barcode type ITF
|
|
||||||
BARCODE_NW7 = '\x1d\x6b\x06' # Barcode type NW7
|
|
||||||
# Image format
|
|
||||||
S_RASTER_N = '\x1d\x76\x30\x00' # Set raster image normal size
|
|
||||||
S_RASTER_2W = '\x1d\x76\x30\x01' # Set raster image double width
|
|
||||||
S_RASTER_2H = '\x1d\x76\x30\x02' # Set raster image double height
|
|
||||||
S_RASTER_Q = '\x1d\x76\x30\x03' # Set raster image quadruple
|
|
||||||
# Printing Density
|
|
||||||
PD_N50 = '\x1d\x7c\x00' # Printing Density -50%
|
|
||||||
PD_N37 = '\x1d\x7c\x01' # Printing Density -37.5%
|
|
||||||
PD_N25 = '\x1d\x7c\x02' # Printing Density -25%
|
|
||||||
PD_N12 = '\x1d\x7c\x03' # Printing Density -12.5%
|
|
||||||
PD_0 = '\x1d\x7c\x04' # Printing Density 0%
|
|
||||||
PD_P50 = '\x1d\x7c\x08' # Printing Density +50%
|
|
||||||
PD_P37 = '\x1d\x7c\x07' # Printing Density +37.5%
|
|
||||||
PD_P25 = '\x1d\x7c\x06' # Printing Density +25%
|
|
||||||
PD_P12 = '\x1d\x7c\x05' # Printing Density +12.5%
|
|
360
escpos/escpos.py
@@ -1,360 +0,0 @@
|
|||||||
#!/usr/bin/python
|
|
||||||
"""
|
|
||||||
@author: Manuel F Martinez <manpaz@bashlinux.com>
|
|
||||||
@organization: Bashlinux
|
|
||||||
@copyright: Copyright (c) 2012 Bashlinux
|
|
||||||
@license: GNU GPL v3
|
|
||||||
"""
|
|
||||||
|
|
||||||
try:
|
|
||||||
import Image
|
|
||||||
except ImportError:
|
|
||||||
from PIL import Image
|
|
||||||
|
|
||||||
import qrcode
|
|
||||||
import time
|
|
||||||
|
|
||||||
from constants import *
|
|
||||||
from exceptions import *
|
|
||||||
|
|
||||||
class Escpos:
|
|
||||||
""" ESC/POS Printer object """
|
|
||||||
device = None
|
|
||||||
|
|
||||||
|
|
||||||
def _check_image_size(self, size):
|
|
||||||
""" Check and fix the size of the image to 32 bits """
|
|
||||||
if size % 32 == 0:
|
|
||||||
return (0, 0)
|
|
||||||
else:
|
|
||||||
image_border = 32 - (size % 32)
|
|
||||||
if (image_border % 2) == 0:
|
|
||||||
return (image_border / 2, image_border / 2)
|
|
||||||
else:
|
|
||||||
return (image_border / 2, (image_border / 2) + 1)
|
|
||||||
|
|
||||||
|
|
||||||
def _print_image(self, line, size):
|
|
||||||
""" Print formatted image """
|
|
||||||
i = 0
|
|
||||||
cont = 0
|
|
||||||
buffer = ""
|
|
||||||
|
|
||||||
self._raw(S_RASTER_N)
|
|
||||||
buffer = "%02X%02X%02X%02X" % (((size[0]/size[1])/8), 0, size[1], 0)
|
|
||||||
self._raw(buffer.decode('hex'))
|
|
||||||
buffer = ""
|
|
||||||
|
|
||||||
while i < len(line):
|
|
||||||
hex_string = int(line[i:i+8],2)
|
|
||||||
buffer += "%02X" % hex_string
|
|
||||||
i += 8
|
|
||||||
cont += 1
|
|
||||||
if cont % 4 == 0:
|
|
||||||
self._raw(buffer.decode("hex"))
|
|
||||||
buffer = ""
|
|
||||||
cont = 0
|
|
||||||
|
|
||||||
|
|
||||||
def _convert_image(self, im):
|
|
||||||
""" Parse image and prepare it to a printable format """
|
|
||||||
pixels = []
|
|
||||||
pix_line = ""
|
|
||||||
im_left = ""
|
|
||||||
im_right = ""
|
|
||||||
switch = 0
|
|
||||||
img_size = [ 0, 0 ]
|
|
||||||
|
|
||||||
|
|
||||||
if im.size[0] > 512:
|
|
||||||
print ("WARNING: Image is wider than 512 and could be truncated at print time ")
|
|
||||||
if im.size[1] > 255:
|
|
||||||
raise ImageSizeError()
|
|
||||||
|
|
||||||
im_border = self._check_image_size(im.size[0])
|
|
||||||
for i in range(im_border[0]):
|
|
||||||
im_left += "0"
|
|
||||||
for i in range(im_border[1]):
|
|
||||||
im_right += "0"
|
|
||||||
|
|
||||||
for y in range(im.size[1]):
|
|
||||||
img_size[1] += 1
|
|
||||||
pix_line += im_left
|
|
||||||
img_size[0] += im_border[0]
|
|
||||||
for x in range(im.size[0]):
|
|
||||||
img_size[0] += 1
|
|
||||||
RGB = im.getpixel((x, y))
|
|
||||||
im_color = (RGB[0] + RGB[1] + RGB[2])
|
|
||||||
im_pattern = "1X0"
|
|
||||||
pattern_len = len(im_pattern)
|
|
||||||
switch = (switch - 1 ) * (-1)
|
|
||||||
for x in range(pattern_len):
|
|
||||||
if im_color <= (255 * 3 / pattern_len * (x+1)):
|
|
||||||
if im_pattern[x] == "X":
|
|
||||||
pix_line += "%d" % switch
|
|
||||||
else:
|
|
||||||
pix_line += im_pattern[x]
|
|
||||||
break
|
|
||||||
elif im_color > (255 * 3 / pattern_len * pattern_len) and im_color <= (255 * 3):
|
|
||||||
pix_line += im_pattern[-1]
|
|
||||||
break
|
|
||||||
pix_line += im_right
|
|
||||||
img_size[0] += im_border[1]
|
|
||||||
|
|
||||||
self._print_image(pix_line, img_size)
|
|
||||||
|
|
||||||
|
|
||||||
def image(self,path_img):
|
|
||||||
""" Open image file """
|
|
||||||
im_open = Image.open(path_img)
|
|
||||||
|
|
||||||
# Remove the alpha channel on transparent images
|
|
||||||
if im_open.mode == 'RGBA':
|
|
||||||
im_open.load()
|
|
||||||
im = Image.new("RGB", im_open.size, (255, 255, 255))
|
|
||||||
im.paste(im_open, mask=im_open.split()[3])
|
|
||||||
else:
|
|
||||||
im = im_open.convert("RGB")
|
|
||||||
|
|
||||||
# Convert the RGB image in printable image
|
|
||||||
self._convert_image(im)
|
|
||||||
|
|
||||||
|
|
||||||
def qr(self,text):
|
|
||||||
""" Print QR Code for the provided string """
|
|
||||||
qr_code = qrcode.QRCode(version=4, box_size=4, border=1)
|
|
||||||
qr_code.add_data(text)
|
|
||||||
qr_code.make(fit=True)
|
|
||||||
qr_img = qr_code.make_image()
|
|
||||||
im = qr_img._img.convert("RGB")
|
|
||||||
|
|
||||||
# Convert the RGB image in printable image
|
|
||||||
self._convert_image(im)
|
|
||||||
|
|
||||||
|
|
||||||
def charcode(self,code):
|
|
||||||
""" Set Character Code Table """
|
|
||||||
if code.upper() == "USA":
|
|
||||||
self._raw(CHARCODE_PC437)
|
|
||||||
elif code.upper() == "JIS":
|
|
||||||
self._raw(CHARCODE_JIS)
|
|
||||||
elif code.upper() == "MULTILINGUAL":
|
|
||||||
self._raw(CHARCODE_PC850)
|
|
||||||
elif code.upper() == "PORTUGUESE":
|
|
||||||
self._raw(CHARCODE_PC860)
|
|
||||||
elif code.upper() == "CA_FRENCH":
|
|
||||||
self._raw(CHARCODE_PC863)
|
|
||||||
elif code.upper() == "NORDIC":
|
|
||||||
self._raw(CHARCODE_PC865)
|
|
||||||
elif code.upper() == "WEST_EUROPE":
|
|
||||||
self._raw(CHARCODE_WEU)
|
|
||||||
elif code.upper() == "GREEK":
|
|
||||||
self._raw(CHARCODE_GREEK)
|
|
||||||
elif code.upper() == "HEBREW":
|
|
||||||
self._raw(CHARCODE_HEBREW)
|
|
||||||
elif code.upper() == "LATVIAN":
|
|
||||||
self._raw(CHARCODE_PC755)
|
|
||||||
elif code.upper() == "WPC1252":
|
|
||||||
self._raw(CHARCODE_PC1252)
|
|
||||||
elif code.upper() == "CIRILLIC2":
|
|
||||||
self._raw(CHARCODE_PC866)
|
|
||||||
elif code.upper() == "LATIN2":
|
|
||||||
self._raw(CHARCODE_PC852)
|
|
||||||
elif code.upper() == "EURO":
|
|
||||||
self._raw(CHARCODE_PC858)
|
|
||||||
elif code.upper() == "THAI42":
|
|
||||||
self._raw(CHARCODE_THAI42)
|
|
||||||
elif code.upper() == "THAI11":
|
|
||||||
self._raw(CHARCODE_THAI11)
|
|
||||||
elif code.upper() == "THAI13":
|
|
||||||
self._raw(CHARCODE_THAI13)
|
|
||||||
elif code.upper() == "THAI14":
|
|
||||||
self._raw(CHARCODE_THAI14)
|
|
||||||
elif code.upper() == "THAI16":
|
|
||||||
self._raw(CHARCODE_THAI16)
|
|
||||||
elif code.upper() == "THAI17":
|
|
||||||
self._raw(CHARCODE_THAI17)
|
|
||||||
elif code.upper() == "THAI18":
|
|
||||||
self._raw(CHARCODE_THAI18)
|
|
||||||
else:
|
|
||||||
raise CharCodeError()
|
|
||||||
|
|
||||||
def barcode(self, code, bc, width, height, pos, font):
|
|
||||||
""" Print Barcode """
|
|
||||||
# Align Bar Code()
|
|
||||||
self._raw(TXT_ALIGN_CT)
|
|
||||||
# Height
|
|
||||||
if height >=2 or height <=6:
|
|
||||||
self._raw(BARCODE_HEIGHT)
|
|
||||||
else:
|
|
||||||
raise BarcodeSizeError()
|
|
||||||
# Width
|
|
||||||
if width >= 1 or width <=255:
|
|
||||||
self._raw(BARCODE_WIDTH)
|
|
||||||
else:
|
|
||||||
raise BarcodeSizeError()
|
|
||||||
# Font
|
|
||||||
if font.upper() == "B":
|
|
||||||
self._raw(BARCODE_FONT_B)
|
|
||||||
else: # DEFAULT FONT: A
|
|
||||||
self._raw(BARCODE_FONT_A)
|
|
||||||
# Position
|
|
||||||
if pos.upper() == "OFF":
|
|
||||||
self._raw(BARCODE_TXT_OFF)
|
|
||||||
elif pos.upper() == "BOTH":
|
|
||||||
self._raw(BARCODE_TXT_BTH)
|
|
||||||
elif pos.upper() == "ABOVE":
|
|
||||||
self._raw(BARCODE_TXT_ABV)
|
|
||||||
else: # DEFAULT POSITION: BELOW
|
|
||||||
self._raw(BARCODE_TXT_BLW)
|
|
||||||
# Type
|
|
||||||
if bc.upper() == "UPC-A":
|
|
||||||
self._raw(BARCODE_UPC_A)
|
|
||||||
elif bc.upper() == "UPC-E":
|
|
||||||
self._raw(BARCODE_UPC_E)
|
|
||||||
elif bc.upper() == "EAN13":
|
|
||||||
self._raw(BARCODE_EAN13)
|
|
||||||
elif bc.upper() == "EAN8":
|
|
||||||
self._raw(BARCODE_EAN8)
|
|
||||||
elif bc.upper() == "CODE39":
|
|
||||||
self._raw(BARCODE_CODE39)
|
|
||||||
elif bc.upper() == "ITF":
|
|
||||||
self._raw(BARCODE_ITF)
|
|
||||||
elif bc.upper() == "NW7":
|
|
||||||
self._raw(BARCODE_NW7)
|
|
||||||
else:
|
|
||||||
raise BarcodeTypeError()
|
|
||||||
# Print Code
|
|
||||||
if code:
|
|
||||||
self._raw(code)
|
|
||||||
else:
|
|
||||||
raise exception.BarcodeCodeError()
|
|
||||||
|
|
||||||
|
|
||||||
def text(self, txt):
|
|
||||||
""" Print alpha-numeric text """
|
|
||||||
if txt:
|
|
||||||
self._raw(txt)
|
|
||||||
else:
|
|
||||||
raise TextError()
|
|
||||||
|
|
||||||
|
|
||||||
def set(self, align='left', font='a', type='normal', width=1, height=1, density=9):
|
|
||||||
""" Set text properties """
|
|
||||||
# Width
|
|
||||||
if height == 2 and width == 2:
|
|
||||||
self._raw(TXT_NORMAL)
|
|
||||||
self._raw(TXT_4SQUARE)
|
|
||||||
elif height == 2 and width != 2:
|
|
||||||
self._raw(TXT_NORMAL)
|
|
||||||
self._raw(TXT_2HEIGHT)
|
|
||||||
elif width == 2 and height != 2:
|
|
||||||
self._raw(TXT_NORMAL)
|
|
||||||
self._raw(TXT_2WIDTH)
|
|
||||||
else: # DEFAULT SIZE: NORMAL
|
|
||||||
self._raw(TXT_NORMAL)
|
|
||||||
# Type
|
|
||||||
if type.upper() == "B":
|
|
||||||
self._raw(TXT_BOLD_ON)
|
|
||||||
self._raw(TXT_UNDERL_OFF)
|
|
||||||
elif type.upper() == "U":
|
|
||||||
self._raw(TXT_BOLD_OFF)
|
|
||||||
self._raw(TXT_UNDERL_ON)
|
|
||||||
elif type.upper() == "U2":
|
|
||||||
self._raw(TXT_BOLD_OFF)
|
|
||||||
self._raw(TXT_UNDERL2_ON)
|
|
||||||
elif type.upper() == "BU":
|
|
||||||
self._raw(TXT_BOLD_ON)
|
|
||||||
self._raw(TXT_UNDERL_ON)
|
|
||||||
elif type.upper() == "BU2":
|
|
||||||
self._raw(TXT_BOLD_ON)
|
|
||||||
self._raw(TXT_UNDERL2_ON)
|
|
||||||
elif type.upper == "NORMAL":
|
|
||||||
self._raw(TXT_BOLD_OFF)
|
|
||||||
self._raw(TXT_UNDERL_OFF)
|
|
||||||
# Font
|
|
||||||
if font.upper() == "B":
|
|
||||||
self._raw(TXT_FONT_B)
|
|
||||||
else: # DEFAULT FONT: A
|
|
||||||
self._raw(TXT_FONT_A)
|
|
||||||
# Align
|
|
||||||
if align.upper() == "CENTER":
|
|
||||||
self._raw(TXT_ALIGN_CT)
|
|
||||||
elif align.upper() == "RIGHT":
|
|
||||||
self._raw(TXT_ALIGN_RT)
|
|
||||||
elif align.upper() == "LEFT":
|
|
||||||
self._raw(TXT_ALIGN_LT)
|
|
||||||
# Density
|
|
||||||
if density == 0:
|
|
||||||
self._raw(PD_N50)
|
|
||||||
elif density == 1:
|
|
||||||
self._raw(PD_N37)
|
|
||||||
elif density == 2:
|
|
||||||
self._raw(PD_N25)
|
|
||||||
elif density == 3:
|
|
||||||
self._raw(PD_N12)
|
|
||||||
elif density == 4:
|
|
||||||
self._raw(PD_0)
|
|
||||||
elif density == 5:
|
|
||||||
self._raw(PD_P12)
|
|
||||||
elif density == 6:
|
|
||||||
self._raw(PD_P25)
|
|
||||||
elif density == 7:
|
|
||||||
self._raw(PD_P37)
|
|
||||||
elif density == 8:
|
|
||||||
self._raw(PD_P50)
|
|
||||||
else:# DEFAULT: DOES NOTHING
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
def cut(self, mode=''):
|
|
||||||
""" Cut paper """
|
|
||||||
# Fix the size between last line and cut
|
|
||||||
# TODO: handle this with a line feed
|
|
||||||
self._raw("\n\n\n\n\n\n")
|
|
||||||
if mode.upper() == "PART":
|
|
||||||
self._raw(PAPER_PART_CUT)
|
|
||||||
else: # DEFAULT MODE: FULL CUT
|
|
||||||
self._raw(PAPER_FULL_CUT)
|
|
||||||
|
|
||||||
|
|
||||||
def cashdraw(self, pin):
|
|
||||||
""" Send pulse to kick the cash drawer """
|
|
||||||
if pin == 2:
|
|
||||||
self._raw(CD_KICK_2)
|
|
||||||
elif pin == 5:
|
|
||||||
self._raw(CD_KICK_5)
|
|
||||||
else:
|
|
||||||
raise CashDrawerError()
|
|
||||||
|
|
||||||
|
|
||||||
def hw(self, hw):
|
|
||||||
""" Hardware operations """
|
|
||||||
if hw.upper() == "INIT":
|
|
||||||
self._raw(HW_INIT)
|
|
||||||
elif hw.upper() == "SELECT":
|
|
||||||
self._raw(HW_SELECT)
|
|
||||||
elif hw.upper() == "RESET":
|
|
||||||
self._raw(HW_RESET)
|
|
||||||
else: # DEFAULT: DOES NOTHING
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
def control(self, ctl, pos=4):
|
|
||||||
""" Feed control sequences """
|
|
||||||
# Set tab positions
|
|
||||||
if pos < 1 or pos > 16:
|
|
||||||
raise TabError()
|
|
||||||
else:
|
|
||||||
self._raw("".join([CTL_SET_HT,hex(pos)]))
|
|
||||||
# Set position
|
|
||||||
if ctl.upper() == "LF":
|
|
||||||
self._raw(CTL_LF)
|
|
||||||
elif ctl.upper() == "FF":
|
|
||||||
self._raw(CTL_FF)
|
|
||||||
elif ctl.upper() == "CR":
|
|
||||||
self._raw(CTL_CR)
|
|
||||||
elif ctl.upper() == "HT":
|
|
||||||
self._raw(CTL_HT)
|
|
||||||
elif ctl.upper() == "VT":
|
|
||||||
self._raw(CTL_VT)
|
|
@@ -1,102 +0,0 @@
|
|||||||
""" ESC/POS Exceptions classes """
|
|
||||||
|
|
||||||
import os
|
|
||||||
|
|
||||||
class Error(Exception):
|
|
||||||
""" Base class for ESC/POS errors """
|
|
||||||
def __init__(self, msg, status=None):
|
|
||||||
Exception.__init__(self)
|
|
||||||
self.msg = msg
|
|
||||||
self.resultcode = 1
|
|
||||||
if status is not None:
|
|
||||||
self.resultcode = status
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return self.msg
|
|
||||||
|
|
||||||
# Result/Exit codes
|
|
||||||
# 0 = success
|
|
||||||
# 10 = No Barcode type defined
|
|
||||||
# 20 = Barcode size values are out of range
|
|
||||||
# 30 = Barcode text not supplied
|
|
||||||
# 40 = Image height is too large
|
|
||||||
# 50 = No string supplied to be printed
|
|
||||||
# 60 = Invalid pin to send Cash Drawer pulse
|
|
||||||
# 70 = Invalid number of tab positions
|
|
||||||
# 80 = Invalid char code
|
|
||||||
|
|
||||||
|
|
||||||
class BarcodeTypeError(Error):
|
|
||||||
def __init__(self, msg=""):
|
|
||||||
Error.__init__(self, msg)
|
|
||||||
self.msg = msg
|
|
||||||
self.resultcode = 10
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return "No Barcode type is defined"
|
|
||||||
|
|
||||||
class BarcodeSizeError(Error):
|
|
||||||
def __init__(self, msg=""):
|
|
||||||
Error.__init__(self, msg)
|
|
||||||
self.msg = msg
|
|
||||||
self.resultcode = 20
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return "Barcode size is out of range"
|
|
||||||
|
|
||||||
class BarcodeCodeError(Error):
|
|
||||||
def __init__(self, msg=""):
|
|
||||||
Error.__init__(self, msg)
|
|
||||||
self.msg = msg
|
|
||||||
self.resultcode = 30
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return "Code was not supplied"
|
|
||||||
|
|
||||||
class ImageSizeError(Error):
|
|
||||||
def __init__(self, msg=""):
|
|
||||||
Error.__init__(self, msg)
|
|
||||||
self.msg = msg
|
|
||||||
self.resultcode = 40
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return "Image height is longer than 255px and can't be printed"
|
|
||||||
|
|
||||||
class TextError(Error):
|
|
||||||
def __init__(self, msg=""):
|
|
||||||
Error.__init__(self, msg)
|
|
||||||
self.msg = msg
|
|
||||||
self.resultcode = 50
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return "Text string must be supplied to the text() method"
|
|
||||||
|
|
||||||
|
|
||||||
class CashDrawerError(Error):
|
|
||||||
def __init__(self, msg=""):
|
|
||||||
Error.__init__(self, msg)
|
|
||||||
self.msg = msg
|
|
||||||
self.resultcode = 60
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return "Valid pin must be set to send pulse"
|
|
||||||
|
|
||||||
|
|
||||||
class TabError(Error):
|
|
||||||
def __init__(self, msg=""):
|
|
||||||
Error.__init__(self, msg)
|
|
||||||
self.msg = msg
|
|
||||||
self.resultcode = 70
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return "Valid tab positions must be in the range 0 to 16"
|
|
||||||
|
|
||||||
|
|
||||||
class CharCodeError(Error):
|
|
||||||
def __init__(self, msg=""):
|
|
||||||
Error.__init__(self, msg)
|
|
||||||
self.msg = msg
|
|
||||||
self.resultcode = 70
|
|
||||||
|
|
||||||
def __str__(self):
|
|
||||||
return "Valid char code must be set"
|
|
@@ -1,183 +0,0 @@
|
|||||||
#!/usr/bin/python
|
|
||||||
"""
|
|
||||||
@author: Manuel F Martinez <manpaz@bashlinux.com>
|
|
||||||
@organization: Bashlinux
|
|
||||||
@copyright: Copyright (c) 2012 Bashlinux
|
|
||||||
@license: GNU GPL v3
|
|
||||||
"""
|
|
||||||
|
|
||||||
import usb.core
|
|
||||||
import usb.util
|
|
||||||
import serial
|
|
||||||
import socket
|
|
||||||
|
|
||||||
from escpos import *
|
|
||||||
from constants import *
|
|
||||||
from exceptions import *
|
|
||||||
|
|
||||||
class Usb(Escpos):
|
|
||||||
""" Define USB printer """
|
|
||||||
|
|
||||||
def __init__(self, idVendor, idProduct, interface=0, in_ep=0x82, out_ep=0x01):
|
|
||||||
"""
|
|
||||||
@param idVendor : Vendor ID
|
|
||||||
@param idProduct : Product ID
|
|
||||||
@param interface : USB device interface
|
|
||||||
@param in_ep : Input end point
|
|
||||||
@param out_ep : Output end point
|
|
||||||
"""
|
|
||||||
self.idVendor = idVendor
|
|
||||||
self.idProduct = idProduct
|
|
||||||
self.interface = interface
|
|
||||||
self.in_ep = in_ep
|
|
||||||
self.out_ep = out_ep
|
|
||||||
self.open()
|
|
||||||
|
|
||||||
|
|
||||||
def open(self):
|
|
||||||
""" Search device on USB tree and set is as escpos device """
|
|
||||||
self.device = usb.core.find(idVendor=self.idVendor, idProduct=self.idProduct)
|
|
||||||
if self.device is None:
|
|
||||||
print "Cable isn't plugged in"
|
|
||||||
|
|
||||||
if self.device.is_kernel_driver_active(0):
|
|
||||||
try:
|
|
||||||
self.device.detach_kernel_driver(0)
|
|
||||||
except usb.core.USBError as e:
|
|
||||||
print "Could not detatch kernel driver: %s" % str(e)
|
|
||||||
|
|
||||||
try:
|
|
||||||
self.device.set_configuration()
|
|
||||||
self.device.reset()
|
|
||||||
except usb.core.USBError as e:
|
|
||||||
print "Could not set configuration: %s" % str(e)
|
|
||||||
|
|
||||||
|
|
||||||
def _raw(self, msg):
|
|
||||||
""" Print any command sent in raw format """
|
|
||||||
self.device.write(self.out_ep, msg, self.interface)
|
|
||||||
|
|
||||||
|
|
||||||
def __del__(self):
|
|
||||||
""" Release USB interface """
|
|
||||||
if self.device:
|
|
||||||
usb.util.dispose_resources(self.device)
|
|
||||||
self.device = None
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Serial(Escpos):
|
|
||||||
""" Define Serial printer """
|
|
||||||
|
|
||||||
def __init__(self, devfile="/dev/ttyS0", baudrate=9600, bytesize=8, timeout=1,
|
|
||||||
parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE,
|
|
||||||
xonxoff=False , dsrdtr=True):
|
|
||||||
"""
|
|
||||||
@param devfile : Device file under dev filesystem
|
|
||||||
@param baudrate : Baud rate for serial transmission
|
|
||||||
@param bytesize : Serial buffer size
|
|
||||||
@param timeout : Read/Write timeout
|
|
||||||
|
|
||||||
@param parity : Parity checking
|
|
||||||
@param stopbits : Number of stop bits
|
|
||||||
@param xonxoff : Software flow control
|
|
||||||
@param dsrdtr : Hardware flow control (False to enable RTS/CTS)
|
|
||||||
"""
|
|
||||||
self.devfile = devfile
|
|
||||||
self.baudrate = baudrate
|
|
||||||
self.bytesize = bytesize
|
|
||||||
self.timeout = timeout
|
|
||||||
|
|
||||||
self.parity = parity
|
|
||||||
self.stopbits = stopbits
|
|
||||||
self.xonxoff = xonxoff
|
|
||||||
self.dsrdtr = dsrdtr
|
|
||||||
|
|
||||||
self.open()
|
|
||||||
|
|
||||||
|
|
||||||
def open(self):
|
|
||||||
""" Setup serial port and set is as escpos device """
|
|
||||||
self.device = serial.Serial(port=self.devfile, baudrate=self.baudrate,
|
|
||||||
bytesize=self.bytesize, parity=self.parity,
|
|
||||||
stopbits=self.stopbits, timeout=self.timeout,
|
|
||||||
xonxoff=self.xonxoff, dsrdtr=self.dsrdtr)
|
|
||||||
|
|
||||||
if self.device is not None:
|
|
||||||
print "Serial printer enabled"
|
|
||||||
else:
|
|
||||||
print "Unable to open serial printer on: %s" % self.devfile
|
|
||||||
|
|
||||||
|
|
||||||
def _raw(self, msg):
|
|
||||||
""" Print any command sent in raw format """
|
|
||||||
self.device.write(msg)
|
|
||||||
|
|
||||||
|
|
||||||
def __del__(self):
|
|
||||||
""" Close Serial interface """
|
|
||||||
if self.device is not None:
|
|
||||||
self.device.close()
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Network(Escpos):
|
|
||||||
""" Define Network printer """
|
|
||||||
|
|
||||||
def __init__(self,host,port=9100):
|
|
||||||
"""
|
|
||||||
@param host : Printer's hostname or IP address
|
|
||||||
@param port : Port to write to
|
|
||||||
"""
|
|
||||||
self.host = host
|
|
||||||
self.port = port
|
|
||||||
self.open()
|
|
||||||
|
|
||||||
|
|
||||||
def open(self):
|
|
||||||
""" Open TCP socket and set it as escpos device """
|
|
||||||
self.device = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
|
||||||
self.device.connect((self.host, self.port))
|
|
||||||
|
|
||||||
if self.device is None:
|
|
||||||
print "Could not open socket for %s" % self.host
|
|
||||||
|
|
||||||
|
|
||||||
def _raw(self, msg):
|
|
||||||
""" Print any command sent in raw format """
|
|
||||||
self.device.send(msg)
|
|
||||||
|
|
||||||
|
|
||||||
def __del__(self):
|
|
||||||
""" Close TCP connection """
|
|
||||||
self.device.close()
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class File(Escpos):
|
|
||||||
""" Define Generic file printer """
|
|
||||||
|
|
||||||
def __init__(self, devfile="/dev/usb/lp0"):
|
|
||||||
"""
|
|
||||||
@param devfile : Device file under dev filesystem
|
|
||||||
"""
|
|
||||||
self.devfile = devfile
|
|
||||||
self.open()
|
|
||||||
|
|
||||||
|
|
||||||
def open(self):
|
|
||||||
""" Open system file """
|
|
||||||
self.device = open(self.devfile, "wb")
|
|
||||||
|
|
||||||
if self.device is None:
|
|
||||||
print "Could not open the specified file %s" % self.devfile
|
|
||||||
|
|
||||||
|
|
||||||
def _raw(self, msg):
|
|
||||||
""" Print any command sent in raw format """
|
|
||||||
self.device.write(msg);
|
|
||||||
|
|
||||||
|
|
||||||
def __del__(self):
|
|
||||||
""" Close system file """
|
|
||||||
self.device.close()
|
|
11
examples/barcodes.py
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
"""Example for printing barcodes."""
|
||||||
|
from escpos.printer import Usb
|
||||||
|
|
||||||
|
# Adapt to your needs
|
||||||
|
p = Usb(0x0416, 0x5011, profile="TM-T88II")
|
||||||
|
|
||||||
|
# Print software and then hardware barcode with the same content
|
||||||
|
p.barcode("123456", "CODE39", width=2, force_software=True)
|
||||||
|
p.text("\n")
|
||||||
|
p.text("\n")
|
||||||
|
p.barcode("123456", "CODE39")
|
72
examples/codepage_tables.py
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
"""Prints code page tables."""
|
||||||
|
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from escpos import printer
|
||||||
|
from escpos.constants import (
|
||||||
|
CODEPAGE_CHANGE,
|
||||||
|
CTL_CR,
|
||||||
|
CTL_FF,
|
||||||
|
CTL_HT,
|
||||||
|
CTL_LF,
|
||||||
|
CTL_VT,
|
||||||
|
ESC,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""Init printer and print codepage tables."""
|
||||||
|
dummy = printer.Dummy()
|
||||||
|
|
||||||
|
dummy.hw("init")
|
||||||
|
|
||||||
|
for codepage in sys.argv[1:] or ["USA"]:
|
||||||
|
dummy.set(height=2, width=2)
|
||||||
|
dummy._raw(codepage + "\n\n\n")
|
||||||
|
print_codepage(dummy, codepage)
|
||||||
|
dummy._raw("\n\n")
|
||||||
|
|
||||||
|
dummy.cut()
|
||||||
|
|
||||||
|
print(dummy.output)
|
||||||
|
|
||||||
|
|
||||||
|
def print_codepage(printer, codepage):
|
||||||
|
"""Print a codepage."""
|
||||||
|
if codepage.isdigit():
|
||||||
|
codepage = int(codepage)
|
||||||
|
printer._raw(CODEPAGE_CHANGE + bytes((codepage,)))
|
||||||
|
printer._raw("after")
|
||||||
|
else:
|
||||||
|
printer.charcode(codepage)
|
||||||
|
|
||||||
|
sep = ""
|
||||||
|
|
||||||
|
# Table header
|
||||||
|
printer.set(font="b")
|
||||||
|
printer._raw(f" {sep.join(map(lambda s: hex(s)[2:], range(0, 16)))}\n")
|
||||||
|
printer.set()
|
||||||
|
|
||||||
|
# The table
|
||||||
|
for x in range(0, 16):
|
||||||
|
# First column
|
||||||
|
printer.set(font="b")
|
||||||
|
printer._raw(f"{hex(x)[2:]} ")
|
||||||
|
printer.set()
|
||||||
|
|
||||||
|
for y in range(0, 16):
|
||||||
|
byte = bytes(
|
||||||
|
(x * 16 + y),
|
||||||
|
)
|
||||||
|
|
||||||
|
if byte in (ESC, CTL_LF, CTL_FF, CTL_CR, CTL_HT, CTL_VT):
|
||||||
|
byte = " "
|
||||||
|
|
||||||
|
printer._raw(byte)
|
||||||
|
printer._raw(sep)
|
||||||
|
printer._raw("\n")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
28
examples/docker-flask/Dockerfile
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
# Use the official Python image as the base image
|
||||||
|
FROM python:3.9-slim
|
||||||
|
|
||||||
|
# Set the working directory
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
# Copy the requirements file
|
||||||
|
COPY requirements.txt .
|
||||||
|
|
||||||
|
#Install the libcups library
|
||||||
|
RUN apt-get update -y && apt-get install libcups2-dev -y
|
||||||
|
# Install the Python packages
|
||||||
|
RUN pip install --no-cache-dir -r requirements.txt
|
||||||
|
RUN pip install python-escpos --pre
|
||||||
|
|
||||||
|
# Install Git
|
||||||
|
RUN apt-get update && \
|
||||||
|
apt-get install -y git && \
|
||||||
|
rm -rf /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
# Copy the Flask app
|
||||||
|
COPY app.py .
|
||||||
|
|
||||||
|
# Expose the port the Flask app will run on
|
||||||
|
EXPOSE 8080
|
||||||
|
|
||||||
|
# Run the Flask app
|
||||||
|
CMD ["python", "app.py"]
|
6
examples/docker-flask/README.md
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
Simple example on how to use it inside a web service
|
||||||
|
|
||||||
|
```
|
||||||
|
docker build . -t escpos-web
|
||||||
|
docker run --network=host -p 9999:9999 escpos
|
||||||
|
```
|
22
examples/docker-flask/app.py
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
"""Example for a flask application."""
|
||||||
|
from flask import Flask
|
||||||
|
|
||||||
|
from escpos.printer import CupsPrinter
|
||||||
|
|
||||||
|
# Initialize Flask app
|
||||||
|
app = Flask(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
@app.route("/", methods=["GET"])
|
||||||
|
def do_print():
|
||||||
|
"""Print."""
|
||||||
|
# p = Usb(0x04b8, 0x0e28, 0)
|
||||||
|
p = CupsPrinter(host="localhost", port=631, printer_name="TM-T20III")
|
||||||
|
p.text("Hello World\n")
|
||||||
|
p.cut()
|
||||||
|
p.close()
|
||||||
|
return "OK"
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
app.run(debug=False, host="0.0.0.0", port=9999)
|
20
examples/docker-flask/requirements.txt
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
appdirs==1.4.4
|
||||||
|
argcomplete==3.0.8
|
||||||
|
blinker==1.6.2
|
||||||
|
click==8.1.3
|
||||||
|
Flask==2.3.2
|
||||||
|
itsdangerous==2.1.2
|
||||||
|
Jinja2==3.1.2
|
||||||
|
MarkupSafe==2.1.2
|
||||||
|
Pillow==10.0.1
|
||||||
|
pycups==2.0.1
|
||||||
|
pypng==0.20220715.0
|
||||||
|
pyserial==3.5
|
||||||
|
python-barcode==0.14.0
|
||||||
|
python-escpos==3.0a9
|
||||||
|
pyusb==1.2.1
|
||||||
|
PyYAML==6.0
|
||||||
|
qrcode==7.4.2
|
||||||
|
six==1.16.0
|
||||||
|
typing_extensions==4.5.0
|
||||||
|
Werkzeug==3.0.1
|
BIN
examples/graphics/climacons/clear-day.png
Normal file
After Width: | Height: | Size: 5.0 KiB |
BIN
examples/graphics/climacons/clear-night.png
Normal file
After Width: | Height: | Size: 21 KiB |
BIN
examples/graphics/climacons/cloudy.png
Normal file
After Width: | Height: | Size: 22 KiB |
BIN
examples/graphics/climacons/fog.png
Normal file
After Width: | Height: | Size: 20 KiB |
BIN
examples/graphics/climacons/partly-cloudy-day.png
Normal file
After Width: | Height: | Size: 5.9 KiB |
BIN
examples/graphics/climacons/partly-cloudy-night.png
Normal file
After Width: | Height: | Size: 5.0 KiB |
BIN
examples/graphics/climacons/rain.png
Normal file
After Width: | Height: | Size: 4.7 KiB |
10
examples/graphics/climacons/readme.md
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
# Climacons by Adam Whitcroft
|
||||||
|
|
||||||
|
75 climatically categorised pictographs for web and UI design by [@adamwhitcroft](https://www.twitter.com/#!/adamwhitcroft).
|
||||||
|
|
||||||
|
Visit the [Climacons](https://adamwhitcroft.com/climacons/) website for more information.
|
||||||
|
|
||||||
|
Visit [Adam Whitcroft on GitHub](https://github.com/AdamWhitcroft)
|
||||||
|
|
||||||
|
## License
|
||||||
|
You are free to use any of the Climacons Icons (the "icons") in any personal or commercial work without obligation of payment (monetary or otherwise) or attribution, however a credit for the work would be appreciated. **Do not** redistribute or sell and **do not** claim creative credit. Intellectual property rights are not transferred with the download of the icons.
|
BIN
examples/graphics/climacons/sleet.png
Normal file
After Width: | Height: | Size: 5.0 KiB |
BIN
examples/graphics/climacons/snow.png
Normal file
After Width: | Height: | Size: 4.9 KiB |
BIN
examples/graphics/climacons/wind.png
Normal file
After Width: | Height: | Size: 3.1 KiB |
21
examples/qr_code.py
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
"""Print example QR codes."""
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from escpos.printer import Usb
|
||||||
|
|
||||||
|
|
||||||
|
def usage():
|
||||||
|
"""Print information on 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, center=True)
|
9
examples/software_barcode.py
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
"""Example file for software barcodes."""
|
||||||
|
from escpos.printer import Usb
|
||||||
|
|
||||||
|
# Adapt to your needs
|
||||||
|
p = Usb(0x0416, 0x5011, profile="POS-5890")
|
||||||
|
|
||||||
|
# Some software barcodes
|
||||||
|
p.barcode("Hello", "code128", width=2, force_software="bitImageRaster")
|
||||||
|
p.barcode("1234", "code39", width=2, force_software=True)
|
131
examples/weather.py
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
"""Weather forecast example.
|
||||||
|
|
||||||
|
Adapted script from Adafruit
|
||||||
|
Weather forecast for Raspberry Pi w/Adafruit Mini Thermal Printer.
|
||||||
|
Retrieves data from DarkSky.net's API, prints current conditions and
|
||||||
|
forecasts for next two days.
|
||||||
|
Weather example using nice bitmaps.
|
||||||
|
Written by Adafruit Industries. MIT license.
|
||||||
|
Adapted and enhanced for escpos library by MrWunderbar666
|
||||||
|
|
||||||
|
Icons taken from https://adamwhitcroft.com/climacons/
|
||||||
|
Check out his github: https://github.com/AdamWhitcroft/climacons
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
import calendar
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import time
|
||||||
|
from datetime import datetime
|
||||||
|
from urllib.request import urlopen
|
||||||
|
|
||||||
|
from escpos.printer import Usb
|
||||||
|
|
||||||
|
"""Set up the main pathing."""
|
||||||
|
this_dir, this_filename = os.path.split(__file__)
|
||||||
|
GRAPHICS_PATH = os.path.join(this_dir, "graphics/climacons/")
|
||||||
|
|
||||||
|
# Adapt to your needs
|
||||||
|
printer = Usb(0x0416, 0x5011, profile="POS-5890")
|
||||||
|
|
||||||
|
# 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 :)
|
||||||
|
API_KEY = "YOUR API KEY"
|
||||||
|
|
||||||
|
LAT = "22.345490" # Your Location
|
||||||
|
LONG = "114.189945" # Your Location
|
||||||
|
|
||||||
|
|
||||||
|
def forecast_icon(idx):
|
||||||
|
"""Get right icon for forecast."""
|
||||||
|
icon = data["daily"]["data"][idx]["icon"]
|
||||||
|
image = GRAPHICS_PATH + icon + ".png"
|
||||||
|
return image
|
||||||
|
|
||||||
|
|
||||||
|
def forecast(idx):
|
||||||
|
"""Dump one forecast line to the printer."""
|
||||||
|
date = datetime.fromtimestamp(int(data["daily"]["data"][idx]["time"]))
|
||||||
|
day = calendar.day_name[date.weekday()]
|
||||||
|
lo = data["daily"]["data"][idx]["temperatureMin"]
|
||||||
|
hi = data["daily"]["data"][idx]["temperatureMax"]
|
||||||
|
cond = data["daily"]["data"][idx]["summary"]
|
||||||
|
print(date)
|
||||||
|
print(day)
|
||||||
|
print(lo)
|
||||||
|
print(hi)
|
||||||
|
print(cond)
|
||||||
|
time.sleep(1)
|
||||||
|
printer.set(font="a", height=2, align="left", bold=False, double_height=False)
|
||||||
|
printer.text(day + " \n ")
|
||||||
|
time.sleep(5) # Sleep to prevent printer buffer overflow
|
||||||
|
printer.text("\n")
|
||||||
|
printer.image(forecast_icon(idx))
|
||||||
|
printer.text("low " + str(lo))
|
||||||
|
printer.text(deg)
|
||||||
|
printer.text("\n")
|
||||||
|
printer.text(" high " + str(hi))
|
||||||
|
printer.text(deg)
|
||||||
|
printer.text("\n")
|
||||||
|
# take care of pesky unicode dash
|
||||||
|
printer.text(cond.replace("\u2013", "-").encode("utf-8"))
|
||||||
|
printer.text("\n \n")
|
||||||
|
|
||||||
|
|
||||||
|
def icon():
|
||||||
|
"""Get icon."""
|
||||||
|
icon = data["currently"]["icon"]
|
||||||
|
image = GRAPHICS_PATH + icon + ".png"
|
||||||
|
return image
|
||||||
|
|
||||||
|
|
||||||
|
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'
|
||||||
|
url = (
|
||||||
|
"https://api.darksky.net/forecast/"
|
||||||
|
+ API_KEY
|
||||||
|
+ "/"
|
||||||
|
+ LAT
|
||||||
|
+ ","
|
||||||
|
+ LONG
|
||||||
|
+ "?exclude=[alerts,minutely,hourly,flags]&units=si"
|
||||||
|
) # change last bit to 'us' for Fahrenheit
|
||||||
|
response = urlopen(url)
|
||||||
|
data = json.loads(response.read())
|
||||||
|
|
||||||
|
printer.print_and_feed(n=1)
|
||||||
|
printer.control("LF")
|
||||||
|
printer.set(font="a", height=2, align="center", bold=True, double_height=True)
|
||||||
|
printer.text("Weather Forecast")
|
||||||
|
printer.text("\n")
|
||||||
|
printer.set(align="center")
|
||||||
|
|
||||||
|
|
||||||
|
# Print current conditions
|
||||||
|
printer.set(font="a", height=2, align="center", bold=True, double_height=False)
|
||||||
|
printer.text("Current conditions: \n")
|
||||||
|
printer.image(icon())
|
||||||
|
printer.text("\n")
|
||||||
|
|
||||||
|
printer.set(font="a", height=2, align="left", bold=False, double_height=False)
|
||||||
|
temp = data["currently"]["temperature"]
|
||||||
|
cond = data["currently"]["summary"]
|
||||||
|
printer.text(temp)
|
||||||
|
printer.text(" ")
|
||||||
|
printer.text(deg)
|
||||||
|
printer.text(" ")
|
||||||
|
printer.text("\n")
|
||||||
|
printer.text("Sky: " + cond)
|
||||||
|
printer.text("\n")
|
||||||
|
printer.text("\n")
|
||||||
|
|
||||||
|
# Print forecast
|
||||||
|
printer.set(font="a", height=2, align="center", bold=True, double_height=False)
|
||||||
|
printer.text("Forecast: \n")
|
||||||
|
forecast(0)
|
||||||
|
forecast(1)
|
||||||
|
printer.cut()
|
||||||
|
printer.control("LF")
|
27
pyproject.toml
Normal file
@@ -0,0 +1,27 @@
|
|||||||
|
[tool.black]
|
||||||
|
extend-exclude = 'capabilities-data'
|
||||||
|
|
||||||
|
[tool.isort]
|
||||||
|
profile = "black"
|
||||||
|
|
||||||
|
[tool.pytest.ini_options]
|
||||||
|
minversion = "6.0"
|
||||||
|
addopts = "--doctest-modules --cov escpos --cov-report=xml"
|
||||||
|
testpaths = [
|
||||||
|
"test",
|
||||||
|
"src",
|
||||||
|
"src/escpos",
|
||||||
|
"escpos",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[tool.mypy.overrides]]
|
||||||
|
module = ["pytest",
|
||||||
|
"jaconv",
|
||||||
|
"scripttest",
|
||||||
|
"barcode.*",
|
||||||
|
"qrcode",
|
||||||
|
"usb.*",
|
||||||
|
"cups",
|
||||||
|
"win32print"
|
||||||
|
]
|
||||||
|
ignore_missing_imports = true
|
1
requirements.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
-e .
|
80
setup.cfg
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
[metadata]
|
||||||
|
name = python-escpos
|
||||||
|
url = https://github.com/python-escpos/python-escpos
|
||||||
|
description = Python library to manipulate ESC/POS Printers
|
||||||
|
long_description = file: README.rst
|
||||||
|
long_description_content_type = text/x-rst
|
||||||
|
license = MIT
|
||||||
|
license_file = LICENSE
|
||||||
|
author = python-escpos developers
|
||||||
|
author_email = dev@pkanzler.de
|
||||||
|
maintainer = Patrick Kanzler
|
||||||
|
maintainer_email = dev@pkanzler.de
|
||||||
|
keywords = ESC/POS, thermoprinter, voucher printer, printing, receipt
|
||||||
|
classifiers =
|
||||||
|
Development Status :: 4 - Beta
|
||||||
|
Environment :: Console
|
||||||
|
Intended Audience :: Developers
|
||||||
|
License :: OSI Approved :: MIT License
|
||||||
|
Operating System :: OS Independent
|
||||||
|
Programming Language :: Python
|
||||||
|
Programming Language :: Python :: 3
|
||||||
|
Programming Language :: Python :: 3.8
|
||||||
|
Programming Language :: Python :: 3.9
|
||||||
|
Programming Language :: Python :: 3.10
|
||||||
|
Programming Language :: Python :: 3.11
|
||||||
|
Programming Language :: Python :: 3.12
|
||||||
|
Programming Language :: Python :: Implementation :: CPython
|
||||||
|
Topic :: Software Development :: Libraries :: Python Modules
|
||||||
|
Topic :: Office/Business :: Financial :: Point-Of-Sale
|
||||||
|
project_urls =
|
||||||
|
Bug Tracker = https://github.com/python-escpos/python-escpos/issues
|
||||||
|
Documentation = https://python-escpos.readthedocs.io/en/latest/
|
||||||
|
Release Notes = https://github.com/python-escpos/python-escpos/releases
|
||||||
|
|
||||||
|
[options]
|
||||||
|
python_requires = >=3.8
|
||||||
|
zip_safe = false
|
||||||
|
include_package_data = true
|
||||||
|
install_requires =
|
||||||
|
Pillow>=2.0
|
||||||
|
qrcode>=4.0
|
||||||
|
python-barcode>=0.15.0,<1
|
||||||
|
setuptools
|
||||||
|
six
|
||||||
|
appdirs
|
||||||
|
PyYAML
|
||||||
|
argcomplete
|
||||||
|
importlib_resources
|
||||||
|
setup_requires = setuptools_scm
|
||||||
|
tests_require =
|
||||||
|
jaconv
|
||||||
|
tox>=4.11
|
||||||
|
pytest>=7.4
|
||||||
|
pytest-cov
|
||||||
|
pytest-mock
|
||||||
|
scripttest
|
||||||
|
mock
|
||||||
|
hypothesis>=6.83
|
||||||
|
flake8
|
||||||
|
sphinxcontrib-spelling>=8.0.0
|
||||||
|
|
||||||
|
[options.extras_require]
|
||||||
|
usb =
|
||||||
|
pyusb>=1.0.0
|
||||||
|
serial =
|
||||||
|
pyserial
|
||||||
|
cups =
|
||||||
|
pycups; platform_system!='Windows'
|
||||||
|
win32 =
|
||||||
|
pywin32; platform_system=='Windows'
|
||||||
|
all =
|
||||||
|
pyusb>=1.0.0
|
||||||
|
pyserial
|
||||||
|
pycups; platform_system!='Windows'
|
||||||
|
pywin32; platform_system=='Windows'
|
||||||
|
|
||||||
|
[flake8]
|
||||||
|
exclude = .git,.tox,.github,.eggs,__pycache__,doc/conf.py,build,dist,capabilities-data,test,src/escpos/constants.py
|
||||||
|
max-line-length = 120
|
||||||
|
extend-ignore = E203, W503
|
66
setup.py
@@ -1,29 +1,45 @@
|
|||||||
#!/usr/bin/python
|
#!/usr/bin/env python
|
||||||
|
"""Setup script for python package."""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from setuptools import find_packages, setup
|
||||||
|
|
||||||
|
base_dir = os.path.dirname(__file__)
|
||||||
|
src_dir = os.path.join(base_dir, "src")
|
||||||
|
|
||||||
|
# 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.
|
||||||
|
sys.path.insert(0, src_dir)
|
||||||
|
|
||||||
|
|
||||||
|
def read(fname):
|
||||||
|
"""Read file from same path as setup.py."""
|
||||||
|
return open(os.path.join(os.path.dirname(__file__), fname)).read()
|
||||||
|
|
||||||
|
|
||||||
|
setuptools_scm_template = """\
|
||||||
|
#!/usr/bin/python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
\"\"\"Version identifier.
|
||||||
|
|
||||||
|
file generated by setuptools_scm
|
||||||
|
don't change, don't track in version control
|
||||||
|
\"\"\"
|
||||||
|
|
||||||
|
version = '{version}'
|
||||||
|
"""
|
||||||
|
|
||||||
from distutils.core import setup
|
|
||||||
|
|
||||||
setup(
|
setup(
|
||||||
name='escpos',
|
use_scm_version={
|
||||||
version='1.0.7',
|
"write_to": "src/escpos/version.py",
|
||||||
url='https://github.com/manpaz/python-escpos',
|
"write_to_template": setuptools_scm_template,
|
||||||
download_url='https://github.com/manpaz/python-escpos.git',
|
},
|
||||||
description='Python library to manipulate ESC/POS Printers',
|
platforms="any",
|
||||||
license='GNU GPL v3',
|
package_dir={"": "src"},
|
||||||
long_description=open('README').read(),
|
packages=find_packages(where="src", exclude=["tests", "tests.*"]),
|
||||||
author='Manuel F Martinez',
|
package_data={"escpos": ["capabilities.json"]},
|
||||||
author_email='manpaz@bashlinux.com',
|
entry_points={"console_scripts": ["python-escpos = escpos.cli:main"]},
|
||||||
platforms=['linux'],
|
|
||||||
packages=[
|
|
||||||
'escpos',
|
|
||||||
],
|
|
||||||
package_data={'': ['COPYING']},
|
|
||||||
classifiers=[
|
|
||||||
'Development Status :: 1 - Alpha',
|
|
||||||
'License :: OSI Approved :: GNU GPL v3',
|
|
||||||
'Operating System :: GNU/Linux',
|
|
||||||
'Intended Audience :: Developers',
|
|
||||||
'Programming Language :: Python',
|
|
||||||
'Topic :: System :: Pheripherals',
|
|
||||||
'Topic :: Software Development :: Libraries :: Python Modules',
|
|
||||||
],
|
|
||||||
)
|
)
|
||||||
|
13
src/escpos/__init__.py
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""python-escpos enables you to manipulate escpos-printers."""
|
||||||
|
|
||||||
|
__all__ = ["constants", "escpos", "exceptions", "printer", "__version__"]
|
||||||
|
|
||||||
|
try:
|
||||||
|
from .version import version as __version__ # noqa
|
||||||
|
except ImportError: # pragma: no cover
|
||||||
|
raise ImportError(
|
||||||
|
"Failed to find (autogenerated) version.py. "
|
||||||
|
"This might be because you are installing from GitHub's tarballs, "
|
||||||
|
"use the PyPI ones."
|
||||||
|
)
|
1
src/escpos/capabilities.json
Symbolic link
@@ -0,0 +1 @@
|
|||||||
|
../../capabilities-data/dist/capabilities.json
|
196
src/escpos/capabilities.py
Normal file
@@ -0,0 +1,196 @@
|
|||||||
|
"""Handler for capabilities data."""
|
||||||
|
import atexit
|
||||||
|
import logging
|
||||||
|
import pickle
|
||||||
|
import platform
|
||||||
|
import re
|
||||||
|
import time
|
||||||
|
from contextlib import ExitStack
|
||||||
|
from os import environ, path
|
||||||
|
from tempfile import mkdtemp
|
||||||
|
from typing import Any, Dict, Optional, Type
|
||||||
|
|
||||||
|
import importlib_resources
|
||||||
|
import yaml
|
||||||
|
|
||||||
|
logging.basicConfig()
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
pickle_dir = environ.get("ESCPOS_CAPABILITIES_PICKLE_DIR", mkdtemp())
|
||||||
|
pickle_path = path.join(pickle_dir, f"{platform.python_version()}.capabilities.pickle")
|
||||||
|
# get a temporary file from importlib_resources if no file is specified in env
|
||||||
|
file_manager = ExitStack()
|
||||||
|
atexit.register(file_manager.close)
|
||||||
|
ref = importlib_resources.files(__name__) / "capabilities.json"
|
||||||
|
capabilities_path = environ.get(
|
||||||
|
"ESCPOS_CAPABILITIES_FILE",
|
||||||
|
file_manager.enter_context(importlib_resources.as_file(ref)),
|
||||||
|
)
|
||||||
|
|
||||||
|
# Load external printer database
|
||||||
|
t0 = time.time()
|
||||||
|
logger.debug("Using capabilities from file: %s", capabilities_path)
|
||||||
|
if path.exists(pickle_path):
|
||||||
|
if path.getmtime(capabilities_path) > path.getmtime(pickle_path):
|
||||||
|
logger.debug("Found a more recent capabilities file")
|
||||||
|
full_load = True
|
||||||
|
else:
|
||||||
|
full_load = False
|
||||||
|
logger.debug("Loading capabilities from pickle in %s", pickle_path)
|
||||||
|
with open(pickle_path, "rb") as cf:
|
||||||
|
CAPABILITIES = pickle.load(cf)
|
||||||
|
else:
|
||||||
|
logger.debug("Capabilities pickle file not found: %s", pickle_path)
|
||||||
|
full_load = True
|
||||||
|
|
||||||
|
if full_load:
|
||||||
|
logger.debug("Loading and pickling capabilities")
|
||||||
|
with open(capabilities_path) as cp, open(pickle_path, "wb") as pp:
|
||||||
|
CAPABILITIES = yaml.safe_load(cp)
|
||||||
|
if not CAPABILITIES:
|
||||||
|
# yaml could not be loaded
|
||||||
|
print(
|
||||||
|
f"Capabilities yaml from {capabilities_path} could not be loaded.\n"
|
||||||
|
"This python package seems to be broken. If it has been installed "
|
||||||
|
"from official sources, please report an issue on GitHub.\n"
|
||||||
|
"Currently loaded capabilities:\n"
|
||||||
|
f"{CAPABILITIES}"
|
||||||
|
)
|
||||||
|
CAPABILITIES = {
|
||||||
|
"profiles": {
|
||||||
|
"default": {
|
||||||
|
"name": "BrokenDefault",
|
||||||
|
"notes": "The integrated capabilities file could not be found and has been replaced.",
|
||||||
|
"codePages": {"0": "Broken"},
|
||||||
|
"features": {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"encodings": {
|
||||||
|
"Broken": {
|
||||||
|
"name": "Broken",
|
||||||
|
"notes": "The configuration is broken.",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
print(
|
||||||
|
"Created a minimal backup profile, "
|
||||||
|
"many functionalities of the library will not work:\n"
|
||||||
|
f"{CAPABILITIES}"
|
||||||
|
)
|
||||||
|
pickle.dump(CAPABILITIES, pp, protocol=2)
|
||||||
|
|
||||||
|
logger.debug("Finished loading capabilities took %.2fs", time.time() - t0)
|
||||||
|
|
||||||
|
|
||||||
|
class NotSupported(Exception):
|
||||||
|
"""Raised if a requested feature is not supported by the printer profile."""
|
||||||
|
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
BARCODE_B = "barcodeB"
|
||||||
|
|
||||||
|
|
||||||
|
class BaseProfile:
|
||||||
|
"""This represents a printer profile.
|
||||||
|
|
||||||
|
A printer profile knows about the number of columns, supported
|
||||||
|
features, colors and more.
|
||||||
|
"""
|
||||||
|
|
||||||
|
profile_data: Dict[str, Any] = {}
|
||||||
|
|
||||||
|
def __getattr__(self, name):
|
||||||
|
"""Get a data element from the profile."""
|
||||||
|
return self.profile_data[name]
|
||||||
|
|
||||||
|
def get_font(self, font) -> int:
|
||||||
|
"""Return the escpos index for `font`.
|
||||||
|
|
||||||
|
Makes sure that the requested `font` is valid.
|
||||||
|
"""
|
||||||
|
font = {"a": 0, "b": 1}.get(font, font)
|
||||||
|
if not str(font) in self.fonts:
|
||||||
|
raise NotSupported(f'"{font}" is not a valid font in the current profile')
|
||||||
|
return font
|
||||||
|
|
||||||
|
def get_columns(self, font) -> int:
|
||||||
|
"""Return the number of columns for the given font."""
|
||||||
|
font = self.get_font(font)
|
||||||
|
columns = self.fonts[str(font)]["columns"]
|
||||||
|
assert type(columns) is int
|
||||||
|
return columns
|
||||||
|
|
||||||
|
def supports(self, feature) -> bool:
|
||||||
|
"""Return true/false for the given feature."""
|
||||||
|
return self.features.get(feature)
|
||||||
|
|
||||||
|
def get_code_pages(self) -> Dict[str, int]:
|
||||||
|
"""Return the support code pages as a ``{name: index}`` dict."""
|
||||||
|
return {v: k for k, v in self.codePages.items()}
|
||||||
|
|
||||||
|
|
||||||
|
def get_profile(name: Optional[str] = None, **kwargs):
|
||||||
|
"""Get a profile by name.
|
||||||
|
|
||||||
|
If no name is given, return the default profile.
|
||||||
|
"""
|
||||||
|
if isinstance(name, Profile):
|
||||||
|
return name
|
||||||
|
|
||||||
|
clazz = get_profile_class(name or "default")
|
||||||
|
return clazz(**kwargs)
|
||||||
|
|
||||||
|
|
||||||
|
CLASS_CACHE = {}
|
||||||
|
|
||||||
|
|
||||||
|
def get_profile_class(name: str) -> Type[BaseProfile]:
|
||||||
|
"""Load a profile class.
|
||||||
|
|
||||||
|
For the given profile name, load the data from the external
|
||||||
|
database, then generate dynamically a class.
|
||||||
|
"""
|
||||||
|
if name not in CLASS_CACHE:
|
||||||
|
profiles: Dict[str, Any] = CAPABILITIES["profiles"]
|
||||||
|
profile_data = profiles[name]
|
||||||
|
profile_name = clean(name)
|
||||||
|
class_name = f"{profile_name[0].upper()}{profile_name[1:]}Profile"
|
||||||
|
new_class = type(class_name, (BaseProfile,), {"profile_data": profile_data})
|
||||||
|
CLASS_CACHE[name] = new_class
|
||||||
|
|
||||||
|
return CLASS_CACHE[name]
|
||||||
|
|
||||||
|
|
||||||
|
def clean(s: str) -> str:
|
||||||
|
"""Clean profile name."""
|
||||||
|
# Remove invalid characters
|
||||||
|
s = re.sub("[^0-9a-zA-Z_]", "", s)
|
||||||
|
# Remove leading characters until we find a letter or underscore
|
||||||
|
s = re.sub("^[^a-zA-Z_]+", "", s)
|
||||||
|
return str(s)
|
||||||
|
|
||||||
|
|
||||||
|
# mute the mypy type issue with this dynamic base class function for now (: Any)
|
||||||
|
ProfileBaseClass: Any = get_profile_class("default")
|
||||||
|
|
||||||
|
|
||||||
|
class Profile(ProfileBaseClass):
|
||||||
|
"""Profile class for user usage.
|
||||||
|
|
||||||
|
For users, who want to provide their own profile.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, columns: Optional[int] = None, features=None) -> None:
|
||||||
|
"""Initialize profile."""
|
||||||
|
super(Profile, self).__init__()
|
||||||
|
|
||||||
|
self.columns = columns
|
||||||
|
self.features = features or {}
|
||||||
|
|
||||||
|
def get_columns(self, font) -> int:
|
||||||
|
"""Get column count of printer."""
|
||||||
|
if self.columns is not None:
|
||||||
|
return self.columns
|
||||||
|
|
||||||
|
return super(Profile, self).get_columns(font)
|