tinyprint 0.2.4__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,91 @@
1
+ """Printer profile management for the tinyprint application.
2
+
3
+ This module provides functionality to manage and configure printer profiles
4
+ for different ESC/POS compatible printers. It handles printer-specific settings
5
+ and configurations to ensure optimal printing results across different printer
6
+ models.
7
+
8
+ The module includes functionality to:
9
+ - Apply custom configurations to printer profiles
10
+ - Handle printer model-specific settings
11
+ - Configure connection-specific parameters
12
+ - Set default values for various printing parameters
13
+ """
14
+
15
+ from escpos.printer.usb import Usb as UsbPrinter # type: ignore
16
+
17
+
18
+ def patch_printer_profile(printer):
19
+ """Apply custom configuration to a printer's profile.
20
+
21
+ This function extends the printer's profile with additional settings and
22
+ configurations that are not included in the default ESC/POS profile. It
23
+ handles model-specific configurations and sets appropriate defaults for
24
+ various printing parameters.
25
+ """
26
+ profile = printer.profile
27
+
28
+ # Default values in case printer is unknown
29
+ profile.img_kwargs = {}
30
+ profile.img_cut_index = 3
31
+ profile.img_scale_factor = 1
32
+ profile.img_x_scale_factor = 1
33
+ profile.img_y_scale_factor = 1
34
+ profile.sleep_time = 0
35
+
36
+ # How many characters fit on one line with normal font size.
37
+ # 42 is also default for TM-T88III.
38
+ profile.default_char_count = 42
39
+ # How many characters fit on one line with heading font size.
40
+ # 21 is also default for TM-T88III.
41
+ profile.big_char_count = 21
42
+
43
+ # Special treatment for specific printer models.
44
+ match profile.profile_data["name"]:
45
+ case "TM-T88III":
46
+ profile.img_kwargs = dict(
47
+ impl="bitImageColumn",
48
+ high_density_vertical=True,
49
+ high_density_horizontal=True,
50
+ center=False,
51
+ )
52
+ profile.default_char_count = 42
53
+ profile.big_char_count = 21
54
+ profile.img_cut_index = 4
55
+ case "TM-U220B":
56
+ profile.img_kwargs = dict(
57
+ impl="bitImageColumn",
58
+ high_density_vertical=False,
59
+ high_density_horizontal=False,
60
+ center=False,
61
+ fragment_height=32,
62
+ )
63
+ # NOTE Numbers need less space than letters in case of this
64
+ # printer (there is space for 40 numbers). Let's use the
65
+ # smaller number to make sure everything always fits in one
66
+ # line.
67
+ profile.default_char_count = 33
68
+ profile.big_char_count = 16
69
+ profile.img_cut_index = 9
70
+ # Profile is wrong, it's 200 dots, not 400
71
+ # https://files.support.epson.com/pdf/pos/bulk/tm-u220_trg_en_std_reve.pdf
72
+ # https://github.com/receipt-print-hq/escpos-printer-db/pull/87/commits/242299097
73
+ profile.profile_data["media"]["width"]["pixels"] = 200
74
+
75
+ case _:
76
+ pass
77
+
78
+ # Special treatment for specific connections to printer.
79
+ match printer:
80
+ case UsbPrinter():
81
+ # Usb printer immediately returns, but is usually slower
82
+ # than Python - improve synchronicity & sleep after each
83
+ # print command. Otherwise we get a lot of timeouts &
84
+ # printed gibberish. The time here seems to depend on the
85
+ # printed material. If it's more dense & blackish / colorful,
86
+ # then we need a higher value to not run into any trouble.
87
+ # More spare material seems to be less problematic. Also
88
+ # the problem becomes bigger if we print multiple pages.
89
+ profile.sleep_time = 0.3
90
+ case _:
91
+ pass
tinyprint/xescpos.py ADDED
@@ -0,0 +1,166 @@
1
+ """Patching escpos library to cut between images without whitespace between
2
+
3
+ See comment at Job.print for more details.
4
+ """
5
+
6
+ from dataclasses import dataclass
7
+ import logging
8
+ import time
9
+ from typing import Optional
10
+
11
+ import six # type: ignore
12
+
13
+ from escpos.image import EscposImage # type: ignore
14
+ from escpos.escpos import Escpos # type: ignore
15
+ from escpos.constants import ESC, GS # type: ignore
16
+ from escpos.exceptions import ImageWidthError # type: ignore
17
+ from escpos.printer.usb import Usb as UsbPrinter # type: ignore
18
+
19
+
20
+ @dataclass
21
+ class Cmd:
22
+ index: int
23
+ cmd: bytes
24
+
25
+
26
+ if 1:
27
+
28
+ def _image(
29
+ self,
30
+ img_source,
31
+ high_density_vertical: bool = True,
32
+ high_density_horizontal: bool = True,
33
+ impl: str = "bitImageRaster",
34
+ fragment_height: int = 960,
35
+ center: bool = False,
36
+ cmd_index_offset: int = 0,
37
+ ) -> Optional[int]:
38
+ """Print an image.
39
+
40
+ You can select whether the printer should print in high density or not. The default value is high density.
41
+ When printing in low density, the image will be stretched.
42
+
43
+ Esc/Pos supplies several commands for printing. This function supports three of them. Please try to vary the
44
+ implementations if you have any problems. For example the printer `IT80-002` will have trouble aligning
45
+ images that are not printed in Column-mode.
46
+
47
+ The available printing implementations are:
48
+
49
+ * `bitImageRaster`: prints with the `GS v 0`-command
50
+ * `graphics`: prints with the `GS ( L`-command
51
+ * `bitImageColumn`: prints with the `ESC *`-command
52
+
53
+ When trying to center an image make sure you have initialized the printer with a valid profile, that
54
+ contains a media width pixel field. Otherwise the centering will have no effect.
55
+
56
+ :param img_source: PIL image or filename to load: `jpg`, `gif`, `png` or `bmp`
57
+ :param high_density_vertical: print in high density in vertical direction *default:* True
58
+ :param high_density_horizontal: print in high density in horizontal direction *default:* True
59
+ :param impl: choose image printing mode between `bitImageRaster`, `graphics` or `bitImageColumn`
60
+ :param fragment_height: Images larger than this will be split into multiple fragments *default:* 960
61
+ :param center: Center image horizontally *default:* False
62
+
63
+ """
64
+ im = EscposImage(img_source)
65
+
66
+ try:
67
+ if self.profile.profile_data["media"]["width"]["pixels"] == "Unknown":
68
+ logging.debug(
69
+ "The media.width.pixel field of the printer profile is not set. "
70
+ + "The center flag will have no effect."
71
+ )
72
+
73
+ max_width = int(self.profile.profile_data["media"]["width"]["pixels"])
74
+
75
+ if im.width > max_width:
76
+ raise ImageWidthError(f"{im.width} > {max_width}")
77
+
78
+ if center:
79
+ im.center(max_width)
80
+ except KeyError:
81
+ # If the printer's pixel width is not known, print anyways...
82
+ pass
83
+ except ValueError:
84
+ # If the max_width cannot be converted to an int, print anyways...
85
+ pass
86
+
87
+ if im.height > fragment_height:
88
+ fragments = im.split(fragment_height)
89
+ cmd_index_offset = 0
90
+ for fragment in fragments:
91
+ cmd_index_offset = self.image(
92
+ fragment,
93
+ high_density_vertical=high_density_vertical,
94
+ high_density_horizontal=high_density_horizontal,
95
+ impl=impl,
96
+ fragment_height=fragment_height,
97
+ cmd_index_offset=cmd_index_offset,
98
+ )
99
+ # XXX dummy printer doesn't have '_sleep_in_fragment' method
100
+ # self._sleep_in_fragment()
101
+ return None
102
+
103
+ if impl == "bitImageRaster":
104
+ # GS v 0, raster format bit image
105
+ density_byte = (0 if high_density_horizontal else 1) + (
106
+ 0 if high_density_vertical else 2
107
+ )
108
+ header = (
109
+ GS
110
+ + b"v0"
111
+ + bytes((density_byte,))
112
+ + self._int_low_high(im.width_bytes, 2)
113
+ + self._int_low_high(im.height, 2)
114
+ )
115
+ self._raw(header + im.to_raster_format())
116
+
117
+ if impl == "graphics":
118
+ # GS ( L raster format graphics
119
+ img_header = self._int_low_high(im.width, 2) + self._int_low_high(
120
+ im.height, 2
121
+ )
122
+ tone = b"0"
123
+ colors = b"1"
124
+ ym = b"\x01" if high_density_vertical else b"\x02"
125
+ xm = b"\x01" if high_density_horizontal else b"\x02"
126
+ header = tone + xm + ym + colors + img_header
127
+ raster_data = im.to_raster_format()
128
+ self._image_send_graphics_data(b"0", b"p", header + raster_data)
129
+ self._image_send_graphics_data(b"0", b"2", b"")
130
+
131
+ if impl == "bitImageColumn":
132
+ # ESC *, column format bit image
133
+ density_byte = (1 if high_density_horizontal else 0) + (
134
+ 32 if high_density_vertical else 0
135
+ )
136
+ header = (
137
+ ESC
138
+ + b"*"
139
+ + six.int2byte(density_byte)
140
+ + self._int_low_high(im.width, 2)
141
+ )
142
+ self._raw(Cmd(cmd_index_offset, ESC + b"3" + six.int2byte(16)))
143
+ for i, blob in enumerate(im.to_column_format(high_density_vertical)):
144
+ cmd_index = i + 1 + cmd_index_offset
145
+ self._raw(Cmd(cmd_index, header + blob + b"\n"))
146
+ self._raw(ESC + b"2")
147
+ return cmd_index_offset + i + 1
148
+
149
+ return None
150
+
151
+ Escpos.image = _image
152
+
153
+
154
+ if 1:
155
+
156
+ # Usb printer: reduce likelihood for timeout gibberish
157
+
158
+ _Usb_raw_original = UsbPrinter._raw
159
+
160
+ def _Usb_raw(self, *args, **kwargs) -> None:
161
+ _Usb_raw_original(self, *args, **kwargs)
162
+ # NOTE Patch to reduce likelihood for timeout gibberish
163
+ while self._read():
164
+ time.sleep(0.01)
165
+
166
+ UsbPrinter._raw = _Usb_raw
@@ -0,0 +1,53 @@
1
+ Metadata-Version: 2.4
2
+ Name: tinyprint
3
+ Version: 0.2.4
4
+ Summary: ui & cli to print zines with esc/pos printer
5
+ Author-email: Levin Eric Zimmermann <levin.eric.zimmermann@posteo.com>
6
+ License: GPL
7
+ Requires-Python: >=3.10
8
+ Description-Content-Type: text/markdown
9
+ License-File: LICENSE
10
+ Requires-Dist: python-escpos[serial,usb]>=3.1
11
+ Requires-Dist: dataclasses-json>=0.6.0
12
+ Requires-Dist: marko>=2.1.2
13
+ Requires-Dist: pdf2image>=1.17.0
14
+ Provides-Extra: dev
15
+ Requires-Dist: coverage; extra == "dev"
16
+ Requires-Dist: pytest; extra == "dev"
17
+ Requires-Dist: syrupy; extra == "dev"
18
+ Requires-Dist: mypy; extra == "dev"
19
+ Requires-Dist: types-six; extra == "dev"
20
+ Requires-Dist: types-pillow; extra == "dev"
21
+ Dynamic: license-file
22
+
23
+ # tinyprint
24
+
25
+ Software for printing tiny zines with ESC/POS printer.
26
+
27
+ ![gui screenshot](screenshot.jpg)
28
+
29
+ ## Installation
30
+
31
+ ### MacOS
32
+
33
+ Open a console and type:
34
+
35
+ ```bash
36
+ /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)
37
+ brew install python
38
+ brew install python-tk
39
+ brew install pipx
40
+ pipx install tinyprint
41
+ ```
42
+
43
+ ## Linux
44
+
45
+ Install python, and then just use pip:
46
+
47
+ ```bash
48
+ pip3 install tinyprint
49
+ ```
50
+
51
+ ## Windows
52
+
53
+ I don't know, but if someone manages, please let us know.
@@ -0,0 +1,22 @@
1
+ tinyprint/__init__.py,sha256=CsfZ8XmcGxZWncloB7ThieYJ7JrlUVpaur4lPo__LQY,143
2
+ tinyprint/__main__.py,sha256=tMge3GTK-YL3eA2K35I9MDptKg5UIgp_xLrfHZoynow,421
3
+ tinyprint/config.py,sha256=PPd4PYnYKsX0_cSW1aihyYjC0dnPVzKSzBICZWCDhe8,58
4
+ tinyprint/gui.py,sha256=uVaDzteZamqs0HjG7R2e-jgju4u_AhS6bRq5GoKMffA,8603
5
+ tinyprint/gui_misc.py,sha256=YUnuNUDT9lubv9_OacadJNvXIpLq1Zh7WXwARxuqqy0,4624
6
+ tinyprint/job.py,sha256=uXxzkU-nFifEN5EP8M0VKf9N0mkLWJpqzb_xnRt73Bw,4970
7
+ tinyprint/jobconfig.py,sha256=h_bLTb9gQPTNtHM_Q-nb4KXpwxYPz8hejCJUsh2Hoeg,1683
8
+ tinyprint/patches.py,sha256=tlk2FNlbMU24OMHm24BmEGVgNvZzRQdKbL8BYeIjoxQ,551
9
+ tinyprint/preprocessor.py,sha256=CI0IgL3M1vdLAt_HAvitft_gp0Dy1PNqUjzYxe3M908,10009
10
+ tinyprint/xescpos.py,sha256=QCrocWFDq4pElgw6_1HOdNE0JHb-aQv_UOjIxzxXyxo,6173
11
+ tinyprint/patches/__init__.py,sha256=Mp1lgkpNc6PqSOj9K36_eRJpV3OWvsZePTjN_7S5o9M,63
12
+ tinyprint/patches/escpos.py,sha256=b9HcGgmQ-ZjNieE3cN-ENyTUth1vcOURoOfkc0pHEK0,6490
13
+ tinyprint/patches/mako.py,sha256=NTL5ZXuHRZivwDtnnUJFgewbbM8aT08hzQLvWKFfoLU,545
14
+ tinyprint/printer/__init__.py,sha256=DjfK6xdR56ZLM4vVZKad2ZUHRx1_Jw8DGsRZ2LiDObE,44
15
+ tinyprint/printer/manager.py,sha256=Am1h77wtB3BPZ6Kh-6vollN_kUgacAzeCAEeAtS_yXo,4711
16
+ tinyprint/printer/profile.py,sha256=7k-T8BjH-n13Z_Dca_I-UZjPiOe1Li31juETLQcofUw,3671
17
+ tinyprint-0.2.4.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
18
+ tinyprint-0.2.4.dist-info/METADATA,sha256=iR56rCdNbs2voYx9rcwgcFIkpM_bUuW3HtsTVtieh2M,1209
19
+ tinyprint-0.2.4.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
20
+ tinyprint-0.2.4.dist-info/entry_points.txt,sha256=HIRCgyspB4RGducBJkc106a99iXPCHNWTXbbZG51ut4,54
21
+ tinyprint-0.2.4.dist-info/top_level.txt,sha256=wZggB6MuNZLbIYB99OeMuQXDT8Za-OIIEk7xY9ylaoU,10
22
+ tinyprint-0.2.4.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (80.10.2)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ tinyprint = tinyprint.__main__:main