papyrium 0.2.0__tar.gz

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.
Files changed (85) hide show
  1. papyrium-0.2.0/LICENSE +21 -0
  2. papyrium-0.2.0/PKG-INFO +375 -0
  3. papyrium-0.2.0/README-pypi.md +343 -0
  4. papyrium-0.2.0/README.md +343 -0
  5. papyrium-0.2.0/pyproject.toml +185 -0
  6. papyrium-0.2.0/setup.cfg +4 -0
  7. papyrium-0.2.0/src/papyrium/advertiser/mdns/__init__.py +172 -0
  8. papyrium-0.2.0/src/papyrium/cli/__init__.py +462 -0
  9. papyrium-0.2.0/src/papyrium/cli/__main__.py +3 -0
  10. papyrium-0.2.0/src/papyrium/cli/help.py +71 -0
  11. papyrium-0.2.0/src/papyrium/cli/plugins.py +90 -0
  12. papyrium-0.2.0/src/papyrium/core/__init__.py +1 -0
  13. papyrium-0.2.0/src/papyrium/core/advertising.py +135 -0
  14. papyrium-0.2.0/src/papyrium/core/channel.py +68 -0
  15. papyrium-0.2.0/src/papyrium/core/conformance.py +335 -0
  16. papyrium-0.2.0/src/papyrium/core/dotfont.py +318 -0
  17. papyrium-0.2.0/src/papyrium/core/instance.py +66 -0
  18. papyrium-0.2.0/src/papyrium/core/jobs.py +251 -0
  19. papyrium-0.2.0/src/papyrium/core/language.py +52 -0
  20. papyrium-0.2.0/src/papyrium/core/model.py +104 -0
  21. papyrium-0.2.0/src/papyrium/core/options.py +65 -0
  22. papyrium-0.2.0/src/papyrium/core/output.py +49 -0
  23. papyrium-0.2.0/src/papyrium/core/page.py +124 -0
  24. papyrium-0.2.0/src/papyrium/core/rendering.py +115 -0
  25. papyrium-0.2.0/src/papyrium/core/spooler.py +105 -0
  26. papyrium-0.2.0/src/papyrium/core/stationery.py +165 -0
  27. papyrium-0.2.0/src/papyrium/core/testing.py +197 -0
  28. papyrium-0.2.0/src/papyrium/core/transport.py +103 -0
  29. papyrium-0.2.0/src/papyrium/exception/__init__.py +285 -0
  30. papyrium-0.2.0/src/papyrium/extension/__init__.py +293 -0
  31. papyrium-0.2.0/src/papyrium/extension/_text.py +58 -0
  32. papyrium-0.2.0/src/papyrium/font/draft_9/__init__.py +16 -0
  33. papyrium-0.2.0/src/papyrium/font/draft_9/glyphs.txt +1414 -0
  34. papyrium-0.2.0/src/papyrium/font/lc10/__init__.py +124 -0
  35. papyrium-0.2.0/src/papyrium/font/lc10/block-graphics.txt +709 -0
  36. papyrium-0.2.0/src/papyrium/font/lc10/draft-elite.txt +2319 -0
  37. papyrium-0.2.0/src/papyrium/font/lc10/nlq-courier-elite.txt +4212 -0
  38. papyrium-0.2.0/src/papyrium/font/lc10/nlq-courier.txt +4212 -0
  39. papyrium-0.2.0/src/papyrium/font/lc10/nlq-orator-elite.txt +4212 -0
  40. papyrium-0.2.0/src/papyrium/font/lc10/nlq-orator-small-capitals-elite.txt +4212 -0
  41. papyrium-0.2.0/src/papyrium/font/lc10/nlq-orator-small-capitals.txt +4212 -0
  42. papyrium-0.2.0/src/papyrium/font/lc10/nlq-orator.txt +4212 -0
  43. papyrium-0.2.0/src/papyrium/font/lc10/nlq-sanserif-elite.txt +4212 -0
  44. papyrium-0.2.0/src/papyrium/font/lc10/nlq-sanserif.txt +4212 -0
  45. papyrium-0.2.0/src/papyrium/font/lx800/__init__.py +32 -0
  46. papyrium-0.2.0/src/papyrium/font/lx800/draft.txt +1463 -0
  47. papyrium-0.2.0/src/papyrium/font/lx800/nlq-roman.txt +3568 -0
  48. papyrium-0.2.0/src/papyrium/font/m1109/__init__.py +29 -0
  49. papyrium-0.2.0/src/papyrium/font/m1109/draft.txt +1411 -0
  50. papyrium-0.2.0/src/papyrium/font/m1109/nlq.txt +1906 -0
  51. papyrium-0.2.0/src/papyrium/language/escp/__init__.py +30 -0
  52. papyrium-0.2.0/src/papyrium/language/escp/charsets.py +182 -0
  53. papyrium-0.2.0/src/papyrium/language/escp/demo_parts.py +32 -0
  54. papyrium-0.2.0/src/papyrium/language/escp/generator.py +192 -0
  55. papyrium-0.2.0/src/papyrium/language/escp/interpreter.py +1611 -0
  56. papyrium-0.2.0/src/papyrium/language/escp/mechanism.py +161 -0
  57. papyrium-0.2.0/src/papyrium/language/escp/options.py +105 -0
  58. papyrium-0.2.0/src/papyrium/language/escp/writing.py +43 -0
  59. papyrium-0.2.0/src/papyrium/language/proprinter/__init__.py +32 -0
  60. papyrium-0.2.0/src/papyrium/language/proprinter/interpreter.py +519 -0
  61. papyrium-0.2.0/src/papyrium/language/proprinter/mechanism.py +52 -0
  62. papyrium-0.2.0/src/papyrium/language/proprinter/nlq.py +55 -0
  63. papyrium-0.2.0/src/papyrium/language/proprinter/widths.py +36 -0
  64. papyrium-0.2.0/src/papyrium/model/brother_m1109/__init__.py +104 -0
  65. papyrium-0.2.0/src/papyrium/model/brother_m1109/demo.py +49 -0
  66. papyrium-0.2.0/src/papyrium/model/epson_fx80/__init__.py +96 -0
  67. papyrium-0.2.0/src/papyrium/model/epson_fx80/demo.py +46 -0
  68. papyrium-0.2.0/src/papyrium/model/epson_lx800/__init__.py +114 -0
  69. papyrium-0.2.0/src/papyrium/model/epson_lx800/demo.py +58 -0
  70. papyrium-0.2.0/src/papyrium/model/ibm_proprinter_ii/__init__.py +105 -0
  71. papyrium-0.2.0/src/papyrium/model/ibm_proprinter_ii/demo.py +91 -0
  72. papyrium-0.2.0/src/papyrium/model/star_lc10/__init__.py +166 -0
  73. papyrium-0.2.0/src/papyrium/model/star_lc10/demo.py +191 -0
  74. papyrium-0.2.0/src/papyrium/model/star_lc10/generator.py +77 -0
  75. papyrium-0.2.0/src/papyrium/model/star_lc10/interpreter.py +460 -0
  76. papyrium-0.2.0/src/papyrium/output/pdf/__init__.py +303 -0
  77. papyrium-0.2.0/src/papyrium/output/png/__init__.py +152 -0
  78. papyrium-0.2.0/src/papyrium/output/png/golden.py +46 -0
  79. papyrium-0.2.0/src/papyrium/transport/raw_tcp/__init__.py +121 -0
  80. papyrium-0.2.0/src/papyrium.egg-info/PKG-INFO +375 -0
  81. papyrium-0.2.0/src/papyrium.egg-info/SOURCES.txt +83 -0
  82. papyrium-0.2.0/src/papyrium.egg-info/dependency_links.txt +1 -0
  83. papyrium-0.2.0/src/papyrium.egg-info/entry_points.txt +42 -0
  84. papyrium-0.2.0/src/papyrium.egg-info/requires.txt +7 -0
  85. papyrium-0.2.0/src/papyrium.egg-info/top_level.txt +1 -0
papyrium-0.2.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Robert Smallshire
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,375 @@
1
+ Metadata-Version: 2.4
2
+ Name: papyrium
3
+ Version: 0.2.0
4
+ Summary: A virtual vintage printer: the bytes a computer sends its printer, printed as a 1980s dot-matrix printer would print them.
5
+ Author-email: Robert Smallshire <robert@smallshire.org.uk>
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/rob-smallshire/papyrium
8
+ Project-URL: Repository, https://github.com/rob-smallshire/papyrium
9
+ Project-URL: Issues, https://github.com/rob-smallshire/papyrium/issues
10
+ Classifier: Development Status :: 3 - Alpha
11
+ Classifier: Environment :: Console
12
+ Classifier: Intended Audience :: End Users/Desktop
13
+ Classifier: Operating System :: OS Independent
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3 :: Only
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Programming Language :: Python :: 3.14
19
+ Classifier: Topic :: Printing
20
+ Classifier: Topic :: System :: Emulators
21
+ Requires-Python: >=3.12
22
+ Description-Content-Type: text/markdown
23
+ License-File: LICENSE
24
+ Requires-Dist: asyoulikeit>=1.5.1
25
+ Requires-Dist: click>=8.1.7
26
+ Requires-Dist: exit-codes>=1.3
27
+ Requires-Dist: ifaddr>=0.2
28
+ Requires-Dist: pillow>=10.0
29
+ Requires-Dist: stevedore>=5.0
30
+ Requires-Dist: zeroconf>=0.151
31
+ Dynamic: license-file
32
+
33
+ <!-- Generated by scripts/render_readme.py from a template; edit the template, not this file. -->
34
+ # Papyrium
35
+
36
+ [![CI](https://github.com/rob-smallshire/papyrium/actions/workflows/ci.yml/badge.svg)](https://github.com/rob-smallshire/papyrium/actions/workflows/ci.yml)
37
+ [![License: MIT](https://img.shields.io/badge/license-MIT-blue)](https://github.com/rob-smallshire/papyrium/blob/master/LICENSE)
38
+
39
+ Papyrium is a virtual vintage printer. It runs as a headless service,
40
+ receives the bytes a computer sends to its printer, interprets them as a
41
+ chosen period printer would, lays the result out on emulated paper, and
42
+ writes the pages as PNG images and PDF documents, dot for dot.
43
+
44
+ <p>
45
+ <img src="https://raw.githubusercontent.com/rob-smallshire/papyrium/master/docs/images/ledger.png" alt="A condensed ledger report printed by the Epson FX-80 on green-bar listing paper" width="100%">
46
+ </p>
47
+ <p>
48
+ <img src="https://raw.githubusercontent.com/rob-smallshire/papyrium/master/docs/images/letter.png" alt="A letter printed by the Brother M-1109 in near letter quality" width="100%">
49
+ </p>
50
+
51
+ The printers are 9-pin dot-matrix printers of the 1980s, the Epson FX-80
52
+ and LX-800, the Brother M-1109 and the Star LC-10, speaking Epson's ESC/P, and
53
+ the IBM Proprinter II, speaking IBM's Proprinter language. The first client is
54
+ Beebium, the BBC Micro emulator, but Papyrium knows nothing about the
55
+ computer on the other end: any emulator, or real hardware behind a
56
+ network adapter, can drive it.
57
+
58
+ ## Printers
59
+
60
+ Each printer model has a demonstration page, printed here by Papyrium
61
+ itself; `papyrium demo MODEL` prints one.
62
+
63
+ <table>
64
+ <tr>
65
+ <td width="17%" valign="top"><a href="https://github.com/rob-smallshire/papyrium/blob/master/src/papyrium/model/brother_m1109/"><img src="https://raw.githubusercontent.com/rob-smallshire/papyrium/master/docs/images/demo-top-brother-m1109.png" alt="The top of the brother-m1109 demonstration page" width="100%"></a><br><code>brother-m1109</code></td>
66
+ <td width="17%" valign="top"><a href="https://github.com/rob-smallshire/papyrium/blob/master/src/papyrium/model/epson_fx80/"><img src="https://raw.githubusercontent.com/rob-smallshire/papyrium/master/docs/images/demo-top-epson-fx80.png" alt="The top of the epson-fx80 demonstration page" width="100%"></a><br><code>epson-fx80</code></td>
67
+ <td width="17%" valign="top"><a href="https://github.com/rob-smallshire/papyrium/blob/master/src/papyrium/model/epson_lx800/"><img src="https://raw.githubusercontent.com/rob-smallshire/papyrium/master/docs/images/demo-top-epson-lx800.png" alt="The top of the epson-lx800 demonstration page" width="100%"></a><br><code>epson-lx800</code></td>
68
+ <td width="17%" valign="top"><a href="https://github.com/rob-smallshire/papyrium/blob/master/src/papyrium/model/ibm_proprinter_ii/"><img src="https://raw.githubusercontent.com/rob-smallshire/papyrium/master/docs/images/demo-top-ibm-proprinter-ii.png" alt="The top of the ibm-proprinter-ii demonstration page" width="100%"></a><br><code>ibm-proprinter-ii</code></td>
69
+ <td width="17%" valign="top"><a href="https://github.com/rob-smallshire/papyrium/blob/master/src/papyrium/model/star_lc10/"><img src="https://raw.githubusercontent.com/rob-smallshire/papyrium/master/docs/images/demo-top-star-lc10.png" alt="The top of the star-lc10 demonstration page" width="100%"></a><br><code>star-lc10</code></td>
70
+ <td width="17%" valign="top"><a href="https://github.com/rob-smallshire/papyrium/blob/master/src/papyrium/model/star_lc10/"><img src="https://raw.githubusercontent.com/rob-smallshire/papyrium/master/docs/images/demo-top-star-lc10-colour.png" alt="The top of the star-lc10-colour demonstration page" width="100%"></a><br><code>star-lc10-colour</code></td>
71
+ </tr>
72
+ </table>
73
+
74
+ ## Quick start
75
+
76
+ With [uv](https://docs.astral.sh/uv/), run it straight from PyPI:
77
+
78
+ ```sh
79
+ uvx papyrium serve
80
+ ```
81
+
82
+ or install the `papyrium` command for good with `uv tool install papyrium`
83
+ (or `pipx install papyrium`, or `pip install papyrium`). The one
84
+ `papyrium` distribution brings the command and every printer model, font,
85
+ transport and output.
86
+
87
+ From a checkout:
88
+
89
+ ```sh
90
+ git clone https://github.com/rob-smallshire/papyrium.git
91
+ cd papyrium
92
+ uv sync
93
+ uv run papyrium serve
94
+ ```
95
+
96
+ This listens on `localhost:9100` (raw TCP, the JetDirect convention) as an
97
+ Epson FX-80, and writes each job into `papyrium-jobs/job-NNNN/`:
98
+
99
+ | File | Contents |
100
+ |---|---|
101
+ | `capture.prn` | Every byte received, exactly as sent |
102
+ | `job.json` | When the job started and ended, why it ended, and the printer setup |
103
+ | `page-0001.png`, ... | Each page, written as the paper is ejected |
104
+ | `job.pdf` | The whole job, written when the job ends |
105
+
106
+ Print something to it:
107
+
108
+ ```sh
109
+ printf 'HELLO FROM PAPYRIUM\r\n\x0c' | nc localhost 9100
110
+ ```
111
+
112
+ A job ends after five seconds without bytes (`--idle-timeout`), or when
113
+ the service stops. A disconnect never ends a job: an emulator may hold one
114
+ connection open for its whole life.
115
+
116
+ ## Printers, paper and fonts
117
+
118
+ ```
119
+ $ papyrium list-models
120
+ Models
121
+ ┏━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
122
+ ┃ Name ┃ Description ┃
123
+ ┡━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
124
+ │ brother-m1109 │ Brother M-1109: an 80-column, 9-pin dot-matrix printer │
125
+ │ │ in its Mode I. │
126
+ │ epson-fx80 │ Epson FX-80: an 80-column, 9-pin dot-matrix printer │
127
+ │ │ speaking ESC/P. │
128
+ │ epson-lx800 │ Epson LX-800: an 80-column, 9-pin dot-matrix printer │
129
+ │ │ speaking ESC/P. │
130
+ │ ibm-proprinter-ii │ IBM Proprinter II: an 80-column, 9-wire dot-matrix │
131
+ │ │ printer speaking │
132
+ │ star-lc10 │ Star LC-10: an 80-column, 9-pin dot-matrix printer │
133
+ │ │ speaking ESC/P or, │
134
+ │ star-lc10-colour │ Star LC-10 Colour: the LC-10 with a four-colour ribbon. │
135
+ └───────────────────┴──────────────────────────────────────────────────────────┘
136
+
137
+ $ papyrium list-fonts
138
+ Fonts
139
+ ┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
140
+ ┃ Name ┃ Description ┃
141
+ ┡━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
142
+ │ draft-9 │ An original 9-pin draft font in the │
143
+ │ │ style of 1980s dot-matrix printers. │
144
+ │ lc10-block-graphics │ The Star LC-10's IBM block graphics, │
145
+ │ │ extracted from its firmware ROM. │
146
+ │ lc10-draft │ The Star LC-10's pica draft font, │
147
+ │ │ made as the printer makes it. │
148
+ │ lc10-draft-elite │ The Star LC-10's elite draft font, │
149
+ │ │ extracted from its firmware ROM. │
150
+ │ lc10-nlq-courier │ The Star LC-10's NLQ Courier in pica, │
151
+ │ │ extracted from its firmware ROM. │
152
+ │ lc10-nlq-courier-elite │ The Star LC-10's NLQ Courier in │
153
+ │ │ elite, extracted from its firmware │
154
+ │ │ ROM. │
155
+ │ lc10-nlq-orator │ The Star LC-10's NLQ Orator with │
156
+ │ │ lower case in pica, from its firmware │
157
+ │ │ ROM. │
158
+ │ lc10-nlq-orator-elite │ The Star LC-10's NLQ Orator with │
159
+ │ │ lower case in elite, from its │
160
+ │ │ firmware ROM. │
161
+ │ lc10-nlq-orator-small-capitals │ The Star LC-10's NLQ Orator with │
162
+ │ │ small capitals in pica, from its │
163
+ │ │ firmware ROM. │
164
+ │ lc10-nlq-orator-small-capitals-elite │ The Star LC-10's NLQ Orator with │
165
+ │ │ small capitals in elite, from its │
166
+ │ │ firmware ROM. │
167
+ │ lc10-nlq-sanserif │ The Star LC-10's NLQ Sanserif in │
168
+ │ │ pica, extracted from its firmware │
169
+ │ │ ROM. │
170
+ │ lc10-nlq-sanserif-elite │ The Star LC-10's NLQ Sanserif in │
171
+ │ │ elite, extracted from its firmware │
172
+ │ │ ROM. │
173
+ │ lx800-draft │ The Epson LX-800's draft font, │
174
+ │ │ extracted from its firmware ROM. │
175
+ │ lx800-nlq-roman │ The Epson LX-800's NLQ Roman font, │
176
+ │ │ extracted from its firmware ROM. │
177
+ │ m1109-draft │ The Brother M-1109's draft font, │
178
+ │ │ reconstructed from printed output. │
179
+ │ m1109-nlq │ The Brother M-1109's NLQ font, │
180
+ │ │ reconstructed from printed output. │
181
+ └──────────────────────────────────────┴───────────────────────────────────────┘
182
+ ```
183
+
184
+ Choose a printer with `--model` and set its options with `-M KEY=VALUE`;
185
+ `papyrium describe-model NAME` describes a model and its options, which
186
+ set its DIP switches and its paper. For example, an M-1109 printing near
187
+ letter quality from power on, on blue-bar listing paper:
188
+
189
+ ```sh
190
+ uv run papyrium serve --model brother-m1109 -M near-letter-quality=yes -M stationery=blue-bar
191
+ ```
192
+
193
+ The paper can be a plain `sheet`, continuous `fanfold` with its tear-off
194
+ strips and feed holes, or listing paper: `green-bar`, `blue-bar` or
195
+ `music-ruled`. A font stands in for each printer's character ROM:
196
+ `draft-9`, the FX-80's, is an original design; the M-1109's are
197
+ reconstructed from its printed output; and the LX-800's and LC-10's are
198
+ extracted from their firmware, the LC-10 making some of its typefaces from
199
+ others as the printer does. The Proprinter II borrows the LC-10's until
200
+ its own are to hand. Any font can be replaced by a dot font file, with
201
+ `-M font=PATH`.
202
+
203
+ ## Printing from a BBC Micro in Beebium
204
+
205
+ ```sh
206
+ uv run papyrium serve
207
+ /path/to/beebium/build/src/server/beebium-model-b --tcp-printer host=localhost:port=9100
208
+ ```
209
+
210
+ On the BBC:
211
+
212
+ ```
213
+ *FX6,0
214
+ *FX5,1
215
+ VDU 2
216
+ PRINT "HELLO"
217
+ VDU 1,12
218
+ VDU 3
219
+ ```
220
+
221
+ `*FX5,1` selects the parallel printer. The BBC normally suppresses line
222
+ feeds to the printer and sends CR alone; `*FX6,0` lets them through. If you
223
+ would rather leave the BBC at its defaults, switch on the printer's auto
224
+ line feed DIP switch instead:
225
+
226
+ ```sh
227
+ uv run papyrium serve -M auto-line-feed=yes
228
+ ```
229
+
230
+ Escape sequences go to the printer with `VDU 1`, so `VDU 1,27,1,69` turns
231
+ on emphasized printing (`ESC E`).
232
+
233
+ ## Finding Papyrium on the network
234
+
235
+ `--advertise` announces the printer on the local network with multicast
236
+ DNS, as Bonjour and Avahi announce network printers, so that a sender,
237
+ such as a bridge from a real computer's printer port, can find it without
238
+ being given an address:
239
+
240
+ ```sh
241
+ uv run papyrium serve --model brother-m1109 --advertise --name "Desk M-1109"
242
+ ```
243
+
244
+ It appears as a raw TCP printer, a `_pdl-datastream._tcp` service. Its TXT
245
+ record names it a Papyrium printer (`note=Papyrium virtual printer`, and
246
+ `ty=Brother M-1109 (Papyrium)`), so a client can tell it from a real
247
+ printer, and carries the printer's `uuid`, which stays the same across
248
+ restarts and renames. The UUID is kept in `printer.json` in the output
249
+ directory; `--name` defaults to the model's name with "(Papyrium)".
250
+
251
+ Advertising makes the printer listen on every interface unless a host is
252
+ given with `-T host=`. Anyone on the network can then send it jobs, as with
253
+ any network printer. A printer only this machine can reach is not
254
+ advertised, and says so. A desktop that adds the printer from its printer
255
+ dialog must print to it in ESC/P, not PostScript or PCL.
256
+
257
+ ## Commands
258
+
259
+ | Command | Purpose |
260
+ |---|---|
261
+ | `papyrium serve` | Run a printer until interrupted |
262
+ | `papyrium render JOB_OR_CAPTURE` | Print a captured job again, from a job directory or a `.prn` file |
263
+ | `papyrium demo MODEL` | Print a printer model's demonstration page, showing what it can do |
264
+ | `papyrium list-jobs` | List captured jobs |
265
+ | `papyrium list-models`, `describe-model NAME` | The printer models installed, and their options |
266
+ | `papyrium list-transports`, `list-languages`, `list-fonts`, `list-outputs`, `list-advertisers` | The other plug-ins installed |
267
+
268
+ Options are passed as `KEY=VALUE`: `-T` for the transport (`-T port=9101`),
269
+ `-M` for the printer model (`-M character-set=uk`), and
270
+ `-O OUTPUT.KEY=VALUE` for an output (`-O png.dpi=300`). Choose outputs with
271
+ `-o png -o pdf`. Reports such as `list-jobs` print as a table, or as TSV or
272
+ JSON with `--as tsv` or `--as json`.
273
+
274
+ Replaying a capture with the same printer setup always gives identical
275
+ pages; `render` on a job directory uses the setup recorded in its
276
+ `job.json`. `serve --capture-only` captures jobs without printing
277
+ them, and needs no printer model installed: each job records the model and
278
+ options asked for, so it can be printed later on a machine that has it.
279
+
280
+ ## How it is built
281
+
282
+ Papyrium is a framework of independent, pluggable axes. Each is an
283
+ entry-point extension point, so a separately distributed package can add
284
+ to it, its modules joining the `papyrium` namespace beside these:
285
+
286
+ | Axis | Plug-in | Description | Module |
287
+ |---|---|---|---|
288
+ | Transports deliver bytes | `raw-tcp` | Raw TCP printing, by default on port 9100 | [`papyrium.transport.raw_tcp`](https://github.com/rob-smallshire/papyrium/blob/master/src/papyrium/transport/raw_tcp/) |
289
+ | Languages interpret them | `escp` | Epson ESC/P, as spoken by 9-pin dot-matrix printers such as the FX-80 | [`papyrium.language.escp`](https://github.com/rob-smallshire/papyrium/blob/master/src/papyrium/language/escp/) |
290
+ | | `proprinter` | The IBM Proprinter's language, as the 9-wire Proprinter II speaks it | [`papyrium.language.proprinter`](https://github.com/rob-smallshire/papyrium/blob/master/src/papyrium/language/proprinter/) |
291
+ | Printer models are what the user chooses | `brother-m1109` | Brother M-1109: an 80-column, 9-pin dot-matrix printer in its Mode I | [`papyrium.model.brother_m1109`](https://github.com/rob-smallshire/papyrium/blob/master/src/papyrium/model/brother_m1109/) |
292
+ | | `epson-fx80` | Epson FX-80: an 80-column, 9-pin dot-matrix printer speaking ESC/P | [`papyrium.model.epson_fx80`](https://github.com/rob-smallshire/papyrium/blob/master/src/papyrium/model/epson_fx80/) |
293
+ | | `epson-lx800` | Epson LX-800: an 80-column, 9-pin dot-matrix printer speaking ESC/P | [`papyrium.model.epson_lx800`](https://github.com/rob-smallshire/papyrium/blob/master/src/papyrium/model/epson_lx800/) |
294
+ | | `ibm-proprinter-ii` | IBM Proprinter II: an 80-column, 9-wire dot-matrix printer speaking | [`papyrium.model.ibm_proprinter_ii`](https://github.com/rob-smallshire/papyrium/blob/master/src/papyrium/model/ibm_proprinter_ii/) |
295
+ | | `star-lc10` | Star LC-10: an 80-column, 9-pin dot-matrix printer speaking ESC/P or, | [`papyrium.model.star_lc10`](https://github.com/rob-smallshire/papyrium/blob/master/src/papyrium/model/star_lc10/) |
296
+ | | `star-lc10-colour` | Star LC-10 Colour: the LC-10 with a four-colour ribbon | [`papyrium.model.star_lc10`](https://github.com/rob-smallshire/papyrium/blob/master/src/papyrium/model/star_lc10/) |
297
+ | Fonts stand in for character ROMs | `draft-9` | An original 9-pin draft font in the style of 1980s dot-matrix printers | [`papyrium.font.draft_9`](https://github.com/rob-smallshire/papyrium/blob/master/src/papyrium/font/draft_9/) |
298
+ | | `lc10-block-graphics` | The Star LC-10's IBM block graphics, extracted from its firmware ROM | [`papyrium.font.lc10`](https://github.com/rob-smallshire/papyrium/blob/master/src/papyrium/font/lc10/) |
299
+ | | `lc10-draft` | The Star LC-10's pica draft font, made as the printer makes it | [`papyrium.font.lc10`](https://github.com/rob-smallshire/papyrium/blob/master/src/papyrium/font/lc10/) |
300
+ | | `lc10-draft-elite` | The Star LC-10's elite draft font, extracted from its firmware ROM | [`papyrium.font.lc10`](https://github.com/rob-smallshire/papyrium/blob/master/src/papyrium/font/lc10/) |
301
+ | | `lc10-nlq-courier` | The Star LC-10's NLQ Courier in pica, extracted from its firmware ROM | [`papyrium.font.lc10`](https://github.com/rob-smallshire/papyrium/blob/master/src/papyrium/font/lc10/) |
302
+ | | `lc10-nlq-courier-elite` | The Star LC-10's NLQ Courier in elite, extracted from its firmware ROM | [`papyrium.font.lc10`](https://github.com/rob-smallshire/papyrium/blob/master/src/papyrium/font/lc10/) |
303
+ | | `lc10-nlq-orator` | The Star LC-10's NLQ Orator with lower case in pica, from its firmware ROM | [`papyrium.font.lc10`](https://github.com/rob-smallshire/papyrium/blob/master/src/papyrium/font/lc10/) |
304
+ | | `lc10-nlq-orator-elite` | The Star LC-10's NLQ Orator with lower case in elite, from its firmware ROM | [`papyrium.font.lc10`](https://github.com/rob-smallshire/papyrium/blob/master/src/papyrium/font/lc10/) |
305
+ | | `lc10-nlq-orator-small-capitals` | The Star LC-10's NLQ Orator with small capitals in pica, from its firmware ROM | [`papyrium.font.lc10`](https://github.com/rob-smallshire/papyrium/blob/master/src/papyrium/font/lc10/) |
306
+ | | `lc10-nlq-orator-small-capitals-elite` | The Star LC-10's NLQ Orator with small capitals in elite, from its firmware ROM | [`papyrium.font.lc10`](https://github.com/rob-smallshire/papyrium/blob/master/src/papyrium/font/lc10/) |
307
+ | | `lc10-nlq-sanserif` | The Star LC-10's NLQ Sanserif in pica, extracted from its firmware ROM | [`papyrium.font.lc10`](https://github.com/rob-smallshire/papyrium/blob/master/src/papyrium/font/lc10/) |
308
+ | | `lc10-nlq-sanserif-elite` | The Star LC-10's NLQ Sanserif in elite, extracted from its firmware ROM | [`papyrium.font.lc10`](https://github.com/rob-smallshire/papyrium/blob/master/src/papyrium/font/lc10/) |
309
+ | | `lx800-draft` | The Epson LX-800's draft font, extracted from its firmware ROM | [`papyrium.font.lx800`](https://github.com/rob-smallshire/papyrium/blob/master/src/papyrium/font/lx800/) |
310
+ | | `lx800-nlq-roman` | The Epson LX-800's NLQ Roman font, extracted from its firmware ROM | [`papyrium.font.lx800`](https://github.com/rob-smallshire/papyrium/blob/master/src/papyrium/font/lx800/) |
311
+ | | `m1109-draft` | The Brother M-1109's draft font, reconstructed from printed output | [`papyrium.font.m1109`](https://github.com/rob-smallshire/papyrium/blob/master/src/papyrium/font/m1109/) |
312
+ | | `m1109-nlq` | The Brother M-1109's NLQ font, reconstructed from printed output | [`papyrium.font.m1109`](https://github.com/rob-smallshire/papyrium/blob/master/src/papyrium/font/m1109/) |
313
+ | Outputs write pages | `pdf` | One PDF per job, one page per printed page, every dot a vector dot | [`papyrium.output.pdf`](https://github.com/rob-smallshire/papyrium/blob/master/src/papyrium/output/pdf/) |
314
+ | | `png` | PNG images, one per page, with each struck dot drawn as a dot | [`papyrium.output.png`](https://github.com/rob-smallshire/papyrium/blob/master/src/papyrium/output/png/) |
315
+ | Advertisers announce printers | `mdns` | Announces printers with multicast DNS, as Bonjour and Avahi do | [`papyrium.advertiser.mdns`](https://github.com/rob-smallshire/papyrium/blob/master/src/papyrium/advertiser/mdns/) |
316
+
317
+ The modules live under `src/papyrium/`, an implicit namespace package,
318
+ and their tests under `tests/`, in the same arrangement:
319
+
320
+ | Module | Contents |
321
+ |---|---|
322
+ | [`papyrium.exception`](https://github.com/rob-smallshire/papyrium/blob/master/src/papyrium/exception/) | Categorised exceptions and CLI error-reporting boundary for Papyrium |
323
+ | [`papyrium.extension`](https://github.com/rob-smallshire/papyrium/blob/master/src/papyrium/extension/) | Generic entry-point plug-in machinery shared by every Papyrium extension axis |
324
+ | [`papyrium.core`](https://github.com/rob-smallshire/papyrium/blob/master/src/papyrium/core/) | Papyrium's core: the page model, printer models, jobs, spooling and the plug-in axes |
325
+ | [`papyrium.transport.raw_tcp`](https://github.com/rob-smallshire/papyrium/blob/master/src/papyrium/transport/raw_tcp/) | Raw TCP transport: the JetDirect-style port 9100 byte stream |
326
+ | [`papyrium.language.escp`](https://github.com/rob-smallshire/papyrium/blob/master/src/papyrium/language/escp/) | The Epson ESC/P printer language for 9-pin dot-matrix printers |
327
+ | [`papyrium.language.proprinter`](https://github.com/rob-smallshire/papyrium/blob/master/src/papyrium/language/proprinter/) | The IBM Proprinter's printer language, for its 9-wire printers |
328
+ | [`papyrium.model.brother_m1109`](https://github.com/rob-smallshire/papyrium/blob/master/src/papyrium/model/brother_m1109/) | The Brother M-1109 9-pin dot-matrix printer |
329
+ | [`papyrium.model.epson_fx80`](https://github.com/rob-smallshire/papyrium/blob/master/src/papyrium/model/epson_fx80/) | The Epson FX-80 9-pin dot-matrix printer |
330
+ | [`papyrium.model.epson_lx800`](https://github.com/rob-smallshire/papyrium/blob/master/src/papyrium/model/epson_lx800/) | The Epson LX-800 9-pin dot-matrix printer |
331
+ | [`papyrium.model.ibm_proprinter_ii`](https://github.com/rob-smallshire/papyrium/blob/master/src/papyrium/model/ibm_proprinter_ii/) | The IBM Proprinter II 9-wire dot-matrix printer |
332
+ | [`papyrium.model.star_lc10`](https://github.com/rob-smallshire/papyrium/blob/master/src/papyrium/model/star_lc10/) | The Star LC-10 and LC-10 Colour 9-pin dot-matrix printers |
333
+ | [`papyrium.font.draft_9`](https://github.com/rob-smallshire/papyrium/blob/master/src/papyrium/font/draft_9/) | draft-9: a 9-pin dot-matrix font designed for Papyrium |
334
+ | [`papyrium.font.lc10`](https://github.com/rob-smallshire/papyrium/blob/master/src/papyrium/font/lc10/) | The Star LC-10's draft and near letter quality fonts, from its firmware |
335
+ | [`papyrium.font.lx800`](https://github.com/rob-smallshire/papyrium/blob/master/src/papyrium/font/lx800/) | The Epson LX-800's draft and near letter quality Roman fonts, from its firmware |
336
+ | [`papyrium.font.m1109`](https://github.com/rob-smallshire/papyrium/blob/master/src/papyrium/font/m1109/) | The Brother M-1109's draft and NLQ fonts, reconstructed from its printed output |
337
+ | [`papyrium.output.pdf`](https://github.com/rob-smallshire/papyrium/blob/master/src/papyrium/output/pdf/) | PDF output: each job as one document, each dot as a vector dot |
338
+ | [`papyrium.output.png`](https://github.com/rob-smallshire/papyrium/blob/master/src/papyrium/output/png/) | PNG output: one greyscale raster image per page |
339
+ | [`papyrium.advertiser.mdns`](https://github.com/rob-smallshire/papyrium/blob/master/src/papyrium/advertiser/mdns/) | Announcing Papyrium printers on the local network with multicast DNS |
340
+ | [`papyrium.cli`](https://github.com/rob-smallshire/papyrium/blob/master/src/papyrium/cli/) | The ``papyrium`` command: run a virtual vintage printer and inspect its jobs |
341
+
342
+ `docs/specification.md` is the design as handed over from Beebium.
343
+ `docs/epson-fx80.md`, `docs/epson-lx800.md`, `docs/brother-m1109.md` and
344
+ `docs/star-lc-10.md` record the behaviour Papyrium follows, from the
345
+ manufacturers' manuals, and `CLAUDE.md` records the working practices.
346
+
347
+ ## Development
348
+
349
+ ```sh
350
+ uv sync
351
+ uv run pytest
352
+ uv run pre-commit install
353
+ ```
354
+
355
+ The golden tests replay the captures in each printer model's tests'
356
+ `golden/` directory and compare every page with a pinned image. The end-to-end
357
+ tests that drive a real Beebium BBC Micro are in `integration/beebium/`;
358
+ their module docstring gives the command to run them. `oracles/` compares
359
+ Papyrium with independent interpreters run as separate programs:
360
+ `uv run pytest oracles/escapy`.
361
+
362
+ This README and the printer models' READMEs are generated by
363
+ `scripts/render_readme.py` from the templates in
364
+ `scripts/readme-templates/` and beside the modules
365
+ (`src/papyrium/**/README.md.j2`), running the examples in
366
+ `scripts/readme-examples/` against Papyrium's own code. The
367
+ pre-commit hook regenerates them, so edit the templates, not the READMEs.
368
+
369
+ ## Licence
370
+
371
+ Papyrium is released under the MIT licence; see [`LICENSE`](https://github.com/rob-smallshire/papyrium/blob/master/LICENSE).
372
+
373
+ Epson, Brother and the other printer and computer names in this project
374
+ are trademarks of their owners, used only to identify the printers that
375
+ Papyrium emulates. Papyrium is not affiliated with or endorsed by them.