ctrl-kd 2.0.0__tar.gz → 4.0.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 (32) hide show
  1. {ctrl_kd-2.0.0/src/ctrl_kd.egg-info → ctrl_kd-4.0.0}/PKG-INFO +39 -10
  2. {ctrl_kd-2.0.0 → ctrl_kd-4.0.0}/README.md +38 -9
  3. {ctrl_kd-2.0.0 → ctrl_kd-4.0.0}/pyproject.toml +7 -1
  4. {ctrl_kd-2.0.0 → ctrl_kd-4.0.0/src/ctrl_kd.egg-info}/PKG-INFO +39 -10
  5. {ctrl_kd-2.0.0 → ctrl_kd-4.0.0}/src/ctrl_kd.egg-info/SOURCES.txt +11 -1
  6. {ctrl_kd-2.0.0 → ctrl_kd-4.0.0}/src/ctrlkd/__init__.py +4 -2
  7. ctrl_kd-4.0.0/src/ctrlkd/afm.py +337 -0
  8. ctrl_kd-4.0.0/src/ctrlkd/cli.py +253 -0
  9. ctrl_kd-4.0.0/src/ctrlkd/core.py +3414 -0
  10. ctrl_kd-4.0.0/src/ctrlkd/emit.py +1085 -0
  11. ctrl_kd-4.0.0/src/ctrlkd/fontmap.py +290 -0
  12. ctrl_kd-4.0.0/src/ctrlkd/info.py +59 -0
  13. ctrl_kd-4.0.0/src/ctrlkd/layout.py +341 -0
  14. ctrl_kd-4.0.0/src/ctrlkd/pdf.py +1938 -0
  15. ctrl_kd-4.0.0/src/ctrlkd/symbolmap.py +125 -0
  16. ctrl_kd-4.0.0/src/ctrlkd/typestyles.py +256 -0
  17. ctrl_kd-4.0.0/src/ctrlkd/writer.py +267 -0
  18. ctrl_kd-4.0.0/src/ctrlkd/wschange.py +215 -0
  19. ctrl_kd-4.0.0/tests/test_ctrlkd.py +3915 -0
  20. ctrl_kd-4.0.0/tests/test_writer.py +322 -0
  21. ctrl_kd-4.0.0/tests/test_wschange.py +194 -0
  22. ctrl_kd-2.0.0/src/ctrlkd/cli.py +0 -124
  23. ctrl_kd-2.0.0/src/ctrlkd/core.py +0 -929
  24. ctrl_kd-2.0.0/src/ctrlkd/emit.py +0 -577
  25. ctrl_kd-2.0.0/src/ctrlkd/pdf.py +0 -580
  26. ctrl_kd-2.0.0/tests/test_ctrlkd.py +0 -1335
  27. {ctrl_kd-2.0.0 → ctrl_kd-4.0.0}/LICENSE +0 -0
  28. {ctrl_kd-2.0.0 → ctrl_kd-4.0.0}/setup.cfg +0 -0
  29. {ctrl_kd-2.0.0 → ctrl_kd-4.0.0}/src/ctrl_kd.egg-info/dependency_links.txt +0 -0
  30. {ctrl_kd-2.0.0 → ctrl_kd-4.0.0}/src/ctrl_kd.egg-info/entry_points.txt +0 -0
  31. {ctrl_kd-2.0.0 → ctrl_kd-4.0.0}/src/ctrl_kd.egg-info/top_level.txt +0 -0
  32. {ctrl_kd-2.0.0 → ctrl_kd-4.0.0}/src/ctrlkd/convert.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ctrl-kd
3
- Version: 2.0.0
3
+ Version: 4.0.0
4
4
  Summary: Convert WordStar 4-7 documents and print-to-disk files to text, Markdown, HTML, RTF, or PDF. ^KD: save and done.
5
5
  Author: Jon Michaels
6
6
  License: MIT
@@ -19,18 +19,33 @@ Dynamic: license-file
19
19
 
20
20
  # ctrl-kd
21
21
 
22
+ ```
23
+ __ __ __ __
24
+ _____/ /______/ / / /______/ /
25
+ / ___/ __/ ___/ /_____/ //_/ __ /
26
+ / /__/ /_/ / / /_____/ ,< / /_/ /
27
+ \___/\__/_/ /_/ /_/|_|\__,_/
28
+ ```
29
+
22
30
  Convert WordStar-era files to modern formats. **^KD: save and done.**
23
31
 
24
32
  `ctrl-kd` reads WordStar 4 documents, WordStar 5–7 documents, and WordStar
25
33
  **print-to-disk files** (the printer byte stream, captured to a file — a distinct
26
- format most converters mangle), and writes plain text, Markdown, HTML, RTF, or PDF (typewriter-set on the
27
- built-in Courier fonts — no dependencies, the page as it would have printed).
34
+ format most converters mangle), and writes plain text, Markdown, HTML, RTF, or PDF (set on a
35
+ viewer's built-in base-14 fonts — no dependencies, nothing embedded, the page as it would have
36
+ printed: printed mode follows the document's own font blocks *and its own layout
37
+ arithmetic* — the `.lh` in force on each line, and each span placed at the
38
+ per-character advance the file's font blocks declare — while modern mode is the
39
+ same document reflowed for today: its fonts carried, footnotes at the page
40
+ bottom, fontless text in a comfortable reading serif).
28
41
 
29
42
  ```console
30
- $ ctrl-kd ESSAY.WS # -> ESSAY.md
43
+ $ ctrl-kd ESSAY.WS # -> ESSAY.rtf: modern reflow, the
44
+ # document's own fonts carried
45
+ $ ctrl-kd --mode printed LETTER.WS # -> LETTER.pdf: the 1990 facsimile
46
+ $ ctrl-kd ESSAY.WS -t md # modern markdown instead
31
47
  $ ctrl-kd ESSAY.WS -t html -t rtf # multiple formats
32
- $ ctrl-kd ESSAY.WS -t pdf --mode printed # a facsimile of the 1990 printout
33
- $ ctrl-kd --mode printed LETTER.WS # line-for-line, as it printed in 1990
48
+ $ ctrl-kd --page-settings sawyer X.WS # a known machine's page defaults
34
49
  $ ctrl-kd --diagnose MYSTERY.FIL # what IS this file?
35
50
  $ ctrl-kd --comments MEMO.WS # include the author's hidden comments
36
51
  $ ctrl-kd --no-notes PAPER.WS # body text only, no notes
@@ -84,16 +99,30 @@ against surviving period printouts of the same documents. Its rules are empirica
84
99
  breaks — a soft return is where the line broke on paper, so printed output
85
100
  keeps it (and reflowed Modern output still joins it). `--diagnose` says
86
101
  whether each figure came from the file or from the default.
102
+ `.lh` is **stateful**: it applies from where it appears, so a document that
103
+ changes leading around its headings gets each line's own lead (page capacity
104
+ still uses the document default — see `pdf._printed_cap`). Horizontally,
105
+ printed mode places every span at the per-character advance (HMI, 1/1800in)
106
+ the document's own font blocks declare, scaling a proportional face onto
107
+ that grid with the Adobe Core 14 glyph metrics (`ctrlkd.afm`) — still no
108
+ dependencies, still nothing embedded.
87
109
  In `printed` mode footnotes are laid out the way WordStar laid them out: at
88
110
  the foot of the page that references them, behind a twenty-dash separator,
89
111
  split across pages with `...Continued...` when they do not fit.
90
112
 
91
113
  ## Modes
92
114
 
93
- * `--mode modern` (default): reflowed paragraphs, semantic markup, deliberate
94
- line breaks kept.
95
- * `--mode printed`: every line as laid out, fixed-width, `.pa`/form-feed page
96
- breaks honored how it came off the printer.
115
+ * `--mode modern` (default; bare runs produce RTF): the document brought to a
116
+ modern audience — reflowed, its own fonts and styles carried, footnotes at
117
+ the page bottom, gaps the file never specified filled with today's
118
+ conventions (a comfortable serif at reading size, one-inch margins).
119
+ * `--mode printed` (bare runs produce PDF): every line as laid out, on the
120
+ era's own page — how it came off the printer. Gaps are filled with 1990's
121
+ conventions instead; `--page-settings` supplies a particular machine's.
122
+
123
+ Version coverage, known limitations (WordStar 6's bare `.pl`, WordStar 3
124
+ status), and how behaviour gets verified: **[FAQ.md](FAQ.md)**, with the
125
+ technical account in **[ERAS.md](ERAS.md)**.
97
126
 
98
127
  ## Install
99
128
 
@@ -1,17 +1,32 @@
1
1
  # ctrl-kd
2
2
 
3
+ ```
4
+ __ __ __ __
5
+ _____/ /______/ / / /______/ /
6
+ / ___/ __/ ___/ /_____/ //_/ __ /
7
+ / /__/ /_/ / / /_____/ ,< / /_/ /
8
+ \___/\__/_/ /_/ /_/|_|\__,_/
9
+ ```
10
+
3
11
  Convert WordStar-era files to modern formats. **^KD: save and done.**
4
12
 
5
13
  `ctrl-kd` reads WordStar 4 documents, WordStar 5–7 documents, and WordStar
6
14
  **print-to-disk files** (the printer byte stream, captured to a file — a distinct
7
- format most converters mangle), and writes plain text, Markdown, HTML, RTF, or PDF (typewriter-set on the
8
- built-in Courier fonts — no dependencies, the page as it would have printed).
15
+ format most converters mangle), and writes plain text, Markdown, HTML, RTF, or PDF (set on a
16
+ viewer's built-in base-14 fonts — no dependencies, nothing embedded, the page as it would have
17
+ printed: printed mode follows the document's own font blocks *and its own layout
18
+ arithmetic* — the `.lh` in force on each line, and each span placed at the
19
+ per-character advance the file's font blocks declare — while modern mode is the
20
+ same document reflowed for today: its fonts carried, footnotes at the page
21
+ bottom, fontless text in a comfortable reading serif).
9
22
 
10
23
  ```console
11
- $ ctrl-kd ESSAY.WS # -> ESSAY.md
24
+ $ ctrl-kd ESSAY.WS # -> ESSAY.rtf: modern reflow, the
25
+ # document's own fonts carried
26
+ $ ctrl-kd --mode printed LETTER.WS # -> LETTER.pdf: the 1990 facsimile
27
+ $ ctrl-kd ESSAY.WS -t md # modern markdown instead
12
28
  $ ctrl-kd ESSAY.WS -t html -t rtf # multiple formats
13
- $ ctrl-kd ESSAY.WS -t pdf --mode printed # a facsimile of the 1990 printout
14
- $ ctrl-kd --mode printed LETTER.WS # line-for-line, as it printed in 1990
29
+ $ ctrl-kd --page-settings sawyer X.WS # a known machine's page defaults
15
30
  $ ctrl-kd --diagnose MYSTERY.FIL # what IS this file?
16
31
  $ ctrl-kd --comments MEMO.WS # include the author's hidden comments
17
32
  $ ctrl-kd --no-notes PAPER.WS # body text only, no notes
@@ -65,16 +80,30 @@ against surviving period printouts of the same documents. Its rules are empirica
65
80
  breaks — a soft return is where the line broke on paper, so printed output
66
81
  keeps it (and reflowed Modern output still joins it). `--diagnose` says
67
82
  whether each figure came from the file or from the default.
83
+ `.lh` is **stateful**: it applies from where it appears, so a document that
84
+ changes leading around its headings gets each line's own lead (page capacity
85
+ still uses the document default — see `pdf._printed_cap`). Horizontally,
86
+ printed mode places every span at the per-character advance (HMI, 1/1800in)
87
+ the document's own font blocks declare, scaling a proportional face onto
88
+ that grid with the Adobe Core 14 glyph metrics (`ctrlkd.afm`) — still no
89
+ dependencies, still nothing embedded.
68
90
  In `printed` mode footnotes are laid out the way WordStar laid them out: at
69
91
  the foot of the page that references them, behind a twenty-dash separator,
70
92
  split across pages with `...Continued...` when they do not fit.
71
93
 
72
94
  ## Modes
73
95
 
74
- * `--mode modern` (default): reflowed paragraphs, semantic markup, deliberate
75
- line breaks kept.
76
- * `--mode printed`: every line as laid out, fixed-width, `.pa`/form-feed page
77
- breaks honored how it came off the printer.
96
+ * `--mode modern` (default; bare runs produce RTF): the document brought to a
97
+ modern audience — reflowed, its own fonts and styles carried, footnotes at
98
+ the page bottom, gaps the file never specified filled with today's
99
+ conventions (a comfortable serif at reading size, one-inch margins).
100
+ * `--mode printed` (bare runs produce PDF): every line as laid out, on the
101
+ era's own page — how it came off the printer. Gaps are filled with 1990's
102
+ conventions instead; `--page-settings` supplies a particular machine's.
103
+
104
+ Version coverage, known limitations (WordStar 6's bare `.pl`, WordStar 3
105
+ status), and how behaviour gets verified: **[FAQ.md](FAQ.md)**, with the
106
+ technical account in **[ERAS.md](ERAS.md)**.
78
107
 
79
108
  ## Install
80
109
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "ctrl-kd"
7
- version = "2.0.0"
7
+ dynamic = ["version"]
8
8
  description = "Convert WordStar 4-7 documents and print-to-disk files to text, Markdown, HTML, RTF, or PDF. ^KD: save and done."
9
9
  readme = "README.md"
10
10
  license = {text = "MIT"}
@@ -28,3 +28,9 @@ ctrl-kd = "ctrlkd.cli:main"
28
28
 
29
29
  [tool.setuptools.packages.find]
30
30
  where = ["src"]
31
+
32
+ [tool.setuptools.dynamic]
33
+ # single source of truth: src/ctrlkd/__init__.py __version__ -- the 4.0.0
34
+ # release shipped with pyproject still saying 3.0.0 because the version
35
+ # lived in two places and the bump hit one (2026-08-06); never again
36
+ version = {attr = "ctrlkd.__version__"}
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ctrl-kd
3
- Version: 2.0.0
3
+ Version: 4.0.0
4
4
  Summary: Convert WordStar 4-7 documents and print-to-disk files to text, Markdown, HTML, RTF, or PDF. ^KD: save and done.
5
5
  Author: Jon Michaels
6
6
  License: MIT
@@ -19,18 +19,33 @@ Dynamic: license-file
19
19
 
20
20
  # ctrl-kd
21
21
 
22
+ ```
23
+ __ __ __ __
24
+ _____/ /______/ / / /______/ /
25
+ / ___/ __/ ___/ /_____/ //_/ __ /
26
+ / /__/ /_/ / / /_____/ ,< / /_/ /
27
+ \___/\__/_/ /_/ /_/|_|\__,_/
28
+ ```
29
+
22
30
  Convert WordStar-era files to modern formats. **^KD: save and done.**
23
31
 
24
32
  `ctrl-kd` reads WordStar 4 documents, WordStar 5–7 documents, and WordStar
25
33
  **print-to-disk files** (the printer byte stream, captured to a file — a distinct
26
- format most converters mangle), and writes plain text, Markdown, HTML, RTF, or PDF (typewriter-set on the
27
- built-in Courier fonts — no dependencies, the page as it would have printed).
34
+ format most converters mangle), and writes plain text, Markdown, HTML, RTF, or PDF (set on a
35
+ viewer's built-in base-14 fonts — no dependencies, nothing embedded, the page as it would have
36
+ printed: printed mode follows the document's own font blocks *and its own layout
37
+ arithmetic* — the `.lh` in force on each line, and each span placed at the
38
+ per-character advance the file's font blocks declare — while modern mode is the
39
+ same document reflowed for today: its fonts carried, footnotes at the page
40
+ bottom, fontless text in a comfortable reading serif).
28
41
 
29
42
  ```console
30
- $ ctrl-kd ESSAY.WS # -> ESSAY.md
43
+ $ ctrl-kd ESSAY.WS # -> ESSAY.rtf: modern reflow, the
44
+ # document's own fonts carried
45
+ $ ctrl-kd --mode printed LETTER.WS # -> LETTER.pdf: the 1990 facsimile
46
+ $ ctrl-kd ESSAY.WS -t md # modern markdown instead
31
47
  $ ctrl-kd ESSAY.WS -t html -t rtf # multiple formats
32
- $ ctrl-kd ESSAY.WS -t pdf --mode printed # a facsimile of the 1990 printout
33
- $ ctrl-kd --mode printed LETTER.WS # line-for-line, as it printed in 1990
48
+ $ ctrl-kd --page-settings sawyer X.WS # a known machine's page defaults
34
49
  $ ctrl-kd --diagnose MYSTERY.FIL # what IS this file?
35
50
  $ ctrl-kd --comments MEMO.WS # include the author's hidden comments
36
51
  $ ctrl-kd --no-notes PAPER.WS # body text only, no notes
@@ -84,16 +99,30 @@ against surviving period printouts of the same documents. Its rules are empirica
84
99
  breaks — a soft return is where the line broke on paper, so printed output
85
100
  keeps it (and reflowed Modern output still joins it). `--diagnose` says
86
101
  whether each figure came from the file or from the default.
102
+ `.lh` is **stateful**: it applies from where it appears, so a document that
103
+ changes leading around its headings gets each line's own lead (page capacity
104
+ still uses the document default — see `pdf._printed_cap`). Horizontally,
105
+ printed mode places every span at the per-character advance (HMI, 1/1800in)
106
+ the document's own font blocks declare, scaling a proportional face onto
107
+ that grid with the Adobe Core 14 glyph metrics (`ctrlkd.afm`) — still no
108
+ dependencies, still nothing embedded.
87
109
  In `printed` mode footnotes are laid out the way WordStar laid them out: at
88
110
  the foot of the page that references them, behind a twenty-dash separator,
89
111
  split across pages with `...Continued...` when they do not fit.
90
112
 
91
113
  ## Modes
92
114
 
93
- * `--mode modern` (default): reflowed paragraphs, semantic markup, deliberate
94
- line breaks kept.
95
- * `--mode printed`: every line as laid out, fixed-width, `.pa`/form-feed page
96
- breaks honored how it came off the printer.
115
+ * `--mode modern` (default; bare runs produce RTF): the document brought to a
116
+ modern audience — reflowed, its own fonts and styles carried, footnotes at
117
+ the page bottom, gaps the file never specified filled with today's
118
+ conventions (a comfortable serif at reading size, one-inch margins).
119
+ * `--mode printed` (bare runs produce PDF): every line as laid out, on the
120
+ era's own page — how it came off the printer. Gaps are filled with 1990's
121
+ conventions instead; `--page-settings` supplies a particular machine's.
122
+
123
+ Version coverage, known limitations (WordStar 6's bare `.pl`, WordStar 3
124
+ status), and how behaviour gets verified: **[FAQ.md](FAQ.md)**, with the
125
+ technical account in **[ERAS.md](ERAS.md)**.
97
126
 
98
127
  ## Install
99
128
 
@@ -7,9 +7,19 @@ src/ctrl_kd.egg-info/dependency_links.txt
7
7
  src/ctrl_kd.egg-info/entry_points.txt
8
8
  src/ctrl_kd.egg-info/top_level.txt
9
9
  src/ctrlkd/__init__.py
10
+ src/ctrlkd/afm.py
10
11
  src/ctrlkd/cli.py
11
12
  src/ctrlkd/convert.py
12
13
  src/ctrlkd/core.py
13
14
  src/ctrlkd/emit.py
15
+ src/ctrlkd/fontmap.py
16
+ src/ctrlkd/info.py
17
+ src/ctrlkd/layout.py
14
18
  src/ctrlkd/pdf.py
15
- tests/test_ctrlkd.py
19
+ src/ctrlkd/symbolmap.py
20
+ src/ctrlkd/typestyles.py
21
+ src/ctrlkd/writer.py
22
+ src/ctrlkd/wschange.py
23
+ tests/test_ctrlkd.py
24
+ tests/test_writer.py
25
+ tests/test_wschange.py
@@ -1,9 +1,11 @@
1
1
  """ctrl-kd — convert WordStar-era files to modern formats. ^KD: save and done."""
2
2
  from .core import (detect, parse, parse_ws, parse_printstream, merged_lines,
3
- Document, Block, Line, Span)
3
+ Document, Block, Line, Span, ParseError)
4
4
  from .emit import (emit_text, emit_markdown, emit_html, emit_rtf,
5
5
  emitter, get_emitter, formats, load_plugins)
6
+ from .layout import modern_flow, emit_layout # registers the 'layout' format
6
7
  from .pdf import emit_pdf # registers the 'pdf' format
7
8
  from .convert import convert, select_notes, DEFAULT_NOTE_KINDS, ALL_NOTE_KINDS
9
+ from .info import document_info
8
10
 
9
- __version__ = '2.0.0'
11
+ __version__ = '4.0.0'
@@ -0,0 +1,337 @@
1
+ """ctrl-kd — glyph widths for the PDF base-14, as data.
2
+
3
+ WHY THIS EXISTS
4
+ ---------------
5
+ Printed mode positions every span at WordStar's own x (pdf.py's HMI
6
+ arithmetic: each font block declares a per-character advance in 1/1800in,
7
+ and that number IS the grid the document was laid out on). Courier lands on
8
+ that grid by construction. A PROPORTIONAL face does not: Times at 12pt sets
9
+ "Chapter One" in whatever width Times happens to want, which is not the width
10
+ WordStar reserved, so the following span would start in the wrong place --
11
+ or, on a 72pt banner, run clean off the paper.
12
+
13
+ The fix needs one number this emitter never had: how wide a string actually
14
+ is in the face it is set in. That is what these tables are.
15
+
16
+ SOURCE
17
+ ------
18
+ Adobe's Core 14 AFM metrics -- the font metrics Adobe publishes for the 14
19
+ fonts every PDF viewer must provide, freely redistributable and the reason
20
+ this project can typeset in them without embedding anything. Widths are
21
+ INTEGER units of 1/1000 em, exactly as the AFM files state them; nothing here
22
+ is measured, estimated or scaled. They are numbers, transcribed as data.
23
+
24
+ (Transcribed via the URW base-35 AFMs, which are metric-compatible clones of
25
+ the same faces by construction -- Helvetica A=667 space=278, Times A=722
26
+ space=250, Courier 600 throughout, matching Adobe's published tables.)
27
+
28
+ ENCODING
29
+ --------
30
+ One 256-entry tuple per face, indexed by BYTE VALUE, because that is what
31
+ pdf.py writes: it encodes text as Latin-1 (`_esc`). For the text faces the
32
+ table is built over Latin-1 glyph names, which over 0xA0-0xFF are exactly
33
+ WinAnsiEncoding's. For Symbol and ZapfDingbats it is built over the font's
34
+ OWN encoding -- the codes pdf.py deliberately writes back via
35
+ symbolmap.untransliterate, so a Symbol 'a' really is alpha and really is
36
+ 631/1000 wide.
37
+
38
+ (Since 2026-08-05 the text font objects declare /Encoding /WinAnsiEncoding
39
+ and pdf._esc writes cp1252, so bytes, glyphs and these widths agree over the
40
+ whole range -- including the 0x80-0x9F typographic row, overlaid onto the
41
+ Latin-1-named base tables below. The decision this paragraph used to defer
42
+ was made, and the digest pins re-taken with it.)
43
+
44
+ A code with no glyph in a face gets 0. Callers must treat a zero-width string
45
+ as "no metric available" rather than dividing by it (pdf.py does).
46
+ """
47
+
48
+ _HELVETICA = (
49
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
50
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
51
+ 278, 278, 355, 556, 556, 889, 667, 191, 333, 333, 389, 584, 278, 333, 278, 278,
52
+ 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 278, 278, 584, 584, 584, 556,
53
+ 1015, 667, 667, 722, 722, 667, 611, 778, 722, 278, 500, 667, 556, 833, 722, 778,
54
+ 667, 778, 722, 667, 611, 722, 667, 944, 667, 667, 611, 278, 278, 278, 469, 556,
55
+ 333, 556, 556, 500, 556, 556, 278, 556, 556, 222, 222, 500, 222, 833, 556, 556,
56
+ 556, 556, 333, 500, 278, 556, 500, 722, 500, 500, 500, 334, 260, 334, 584, 0,
57
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
58
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
59
+ 278, 333, 556, 556, 556, 556, 260, 556, 333, 737, 370, 556, 584, 333, 737, 333,
60
+ 400, 584, 333, 333, 333, 556, 537, 278, 333, 333, 365, 556, 834, 834, 834, 611,
61
+ 667, 667, 667, 667, 667, 667, 1000, 722, 667, 667, 667, 667, 278, 278, 278, 278,
62
+ 722, 722, 778, 778, 778, 778, 778, 584, 778, 722, 722, 722, 722, 667, 667, 611,
63
+ 556, 556, 556, 556, 556, 556, 889, 500, 556, 556, 556, 556, 278, 278, 278, 278,
64
+ 556, 556, 556, 556, 556, 556, 556, 584, 611, 556, 556, 556, 556, 500, 556, 500,
65
+ )
66
+
67
+ _HELVETICA_BOLD = (
68
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
69
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
70
+ 278, 333, 474, 556, 556, 889, 722, 238, 333, 333, 389, 584, 278, 333, 278, 278,
71
+ 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 333, 333, 584, 584, 584, 611,
72
+ 975, 722, 722, 722, 722, 667, 611, 778, 722, 278, 556, 722, 611, 833, 722, 778,
73
+ 667, 778, 722, 667, 611, 722, 667, 944, 667, 667, 611, 333, 278, 333, 584, 556,
74
+ 333, 556, 611, 556, 611, 556, 333, 611, 611, 278, 278, 556, 278, 889, 611, 611,
75
+ 611, 611, 389, 556, 333, 611, 556, 778, 556, 556, 500, 389, 280, 389, 584, 0,
76
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
77
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
78
+ 278, 333, 556, 556, 556, 556, 280, 556, 333, 737, 370, 556, 584, 333, 737, 333,
79
+ 400, 584, 333, 333, 333, 611, 556, 278, 333, 333, 365, 556, 834, 834, 834, 611,
80
+ 722, 722, 722, 722, 722, 722, 1000, 722, 667, 667, 667, 667, 278, 278, 278, 278,
81
+ 722, 722, 778, 778, 778, 778, 778, 584, 778, 722, 722, 722, 722, 667, 667, 611,
82
+ 556, 556, 556, 556, 556, 556, 889, 556, 556, 556, 556, 556, 278, 278, 278, 278,
83
+ 611, 611, 611, 611, 611, 611, 611, 584, 611, 611, 611, 611, 611, 556, 611, 556,
84
+ )
85
+
86
+ _HELVETICA_OBLIQUE = (
87
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
88
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
89
+ 278, 278, 355, 556, 556, 889, 667, 191, 333, 333, 389, 584, 278, 333, 278, 278,
90
+ 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 278, 278, 584, 584, 584, 556,
91
+ 1015, 667, 667, 722, 722, 667, 611, 778, 722, 278, 500, 667, 556, 833, 722, 778,
92
+ 667, 778, 722, 667, 611, 722, 667, 944, 667, 667, 611, 278, 278, 278, 469, 556,
93
+ 333, 556, 556, 500, 556, 556, 278, 556, 556, 222, 222, 500, 222, 833, 556, 556,
94
+ 556, 556, 333, 500, 278, 556, 500, 722, 500, 500, 500, 334, 260, 334, 584, 0,
95
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
96
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
97
+ 278, 333, 556, 556, 556, 556, 260, 556, 333, 737, 370, 556, 584, 333, 737, 333,
98
+ 400, 584, 333, 333, 333, 556, 537, 278, 333, 333, 365, 556, 834, 834, 834, 611,
99
+ 667, 667, 667, 667, 667, 667, 1000, 722, 667, 667, 667, 667, 278, 278, 278, 278,
100
+ 722, 722, 778, 778, 778, 778, 778, 584, 778, 722, 722, 722, 722, 667, 667, 611,
101
+ 556, 556, 556, 556, 556, 556, 889, 500, 556, 556, 556, 556, 278, 278, 278, 278,
102
+ 556, 556, 556, 556, 556, 556, 556, 584, 611, 556, 556, 556, 556, 500, 556, 500,
103
+ )
104
+
105
+ _HELVETICA_BOLDOBLIQUE = (
106
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
107
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
108
+ 278, 333, 474, 556, 556, 889, 722, 238, 333, 333, 389, 584, 278, 333, 278, 278,
109
+ 556, 556, 556, 556, 556, 556, 556, 556, 556, 556, 333, 333, 584, 584, 584, 611,
110
+ 975, 722, 722, 722, 722, 667, 611, 778, 722, 278, 556, 722, 611, 833, 722, 778,
111
+ 667, 778, 722, 667, 611, 722, 667, 944, 667, 667, 611, 333, 278, 333, 584, 556,
112
+ 333, 556, 611, 556, 611, 556, 333, 611, 611, 278, 278, 556, 278, 889, 611, 611,
113
+ 611, 611, 389, 556, 333, 611, 556, 778, 556, 556, 500, 389, 280, 389, 584, 0,
114
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
115
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
116
+ 278, 333, 556, 556, 556, 556, 280, 556, 333, 737, 370, 556, 584, 333, 737, 333,
117
+ 400, 584, 333, 333, 333, 611, 556, 278, 333, 333, 365, 556, 834, 834, 834, 611,
118
+ 722, 722, 722, 722, 722, 722, 1000, 722, 667, 667, 667, 667, 278, 278, 278, 278,
119
+ 722, 722, 778, 778, 778, 778, 778, 584, 778, 722, 722, 722, 722, 667, 667, 611,
120
+ 556, 556, 556, 556, 556, 556, 889, 556, 556, 556, 556, 556, 278, 278, 278, 278,
121
+ 611, 611, 611, 611, 611, 611, 611, 584, 611, 611, 611, 611, 611, 556, 611, 556,
122
+ )
123
+
124
+ _TIMES_ROMAN = (
125
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
126
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
127
+ 250, 333, 408, 500, 500, 833, 778, 180, 333, 333, 500, 564, 250, 333, 250, 278,
128
+ 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 278, 278, 564, 564, 564, 444,
129
+ 921, 722, 667, 667, 722, 611, 556, 722, 722, 333, 389, 722, 611, 889, 722, 722,
130
+ 556, 722, 667, 556, 611, 722, 722, 944, 722, 722, 611, 333, 278, 333, 469, 500,
131
+ 333, 444, 500, 444, 500, 444, 333, 500, 500, 278, 278, 500, 278, 778, 500, 500,
132
+ 500, 500, 333, 389, 278, 500, 500, 722, 500, 500, 444, 480, 200, 480, 541, 0,
133
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
134
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
135
+ 250, 333, 500, 500, 500, 500, 200, 500, 333, 760, 276, 500, 564, 333, 760, 333,
136
+ 400, 564, 300, 300, 333, 500, 453, 250, 333, 300, 310, 500, 750, 750, 750, 444,
137
+ 722, 722, 722, 722, 722, 722, 889, 667, 611, 611, 611, 611, 333, 333, 333, 333,
138
+ 722, 722, 722, 722, 722, 722, 722, 564, 722, 722, 722, 722, 722, 722, 556, 500,
139
+ 444, 444, 444, 444, 444, 444, 667, 444, 444, 444, 444, 444, 278, 278, 278, 278,
140
+ 500, 500, 500, 500, 500, 500, 500, 564, 500, 500, 500, 500, 500, 500, 500, 500,
141
+ )
142
+
143
+ _TIMES_BOLD = (
144
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
145
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
146
+ 250, 333, 555, 500, 500, 1000, 833, 278, 333, 333, 500, 570, 250, 333, 250, 278,
147
+ 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 333, 333, 570, 570, 570, 500,
148
+ 930, 722, 667, 722, 722, 667, 611, 778, 778, 389, 500, 778, 667, 944, 722, 778,
149
+ 611, 778, 722, 556, 667, 722, 722, 1000, 722, 722, 667, 333, 278, 333, 581, 500,
150
+ 333, 500, 556, 444, 556, 444, 333, 500, 556, 278, 333, 556, 278, 833, 556, 500,
151
+ 556, 556, 444, 389, 333, 556, 500, 722, 500, 500, 444, 394, 220, 394, 520, 0,
152
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
153
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
154
+ 250, 333, 500, 500, 500, 500, 220, 500, 333, 747, 300, 500, 570, 333, 747, 333,
155
+ 400, 570, 300, 300, 333, 556, 540, 250, 333, 300, 330, 500, 750, 750, 750, 500,
156
+ 722, 722, 722, 722, 722, 722, 1000, 722, 667, 667, 667, 667, 389, 389, 389, 389,
157
+ 722, 722, 778, 778, 778, 778, 778, 570, 778, 722, 722, 722, 722, 722, 611, 556,
158
+ 500, 500, 500, 500, 500, 500, 722, 444, 444, 444, 444, 444, 278, 278, 278, 278,
159
+ 500, 556, 500, 500, 500, 500, 500, 570, 500, 556, 556, 556, 556, 500, 556, 500,
160
+ )
161
+
162
+ _TIMES_ITALIC = (
163
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
164
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
165
+ 250, 333, 420, 500, 500, 833, 778, 214, 333, 333, 500, 675, 250, 333, 250, 278,
166
+ 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 333, 333, 675, 675, 675, 500,
167
+ 920, 611, 611, 667, 722, 611, 611, 722, 722, 333, 444, 667, 556, 833, 667, 722,
168
+ 611, 722, 611, 500, 556, 722, 611, 833, 611, 556, 556, 389, 278, 389, 422, 500,
169
+ 333, 500, 500, 444, 500, 444, 278, 500, 500, 278, 278, 444, 278, 722, 500, 500,
170
+ 500, 500, 389, 389, 278, 500, 444, 667, 444, 444, 389, 400, 275, 400, 541, 0,
171
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
172
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
173
+ 250, 389, 500, 500, 500, 500, 275, 500, 333, 760, 276, 500, 675, 333, 760, 333,
174
+ 400, 675, 300, 300, 333, 500, 523, 250, 333, 300, 310, 500, 750, 750, 750, 500,
175
+ 611, 611, 611, 611, 611, 611, 889, 667, 611, 611, 611, 611, 333, 333, 333, 333,
176
+ 722, 667, 722, 722, 722, 722, 722, 675, 722, 722, 722, 722, 722, 556, 611, 500,
177
+ 500, 500, 500, 500, 500, 500, 667, 444, 444, 444, 444, 444, 278, 278, 278, 278,
178
+ 500, 500, 500, 500, 500, 500, 500, 675, 500, 500, 500, 500, 500, 444, 500, 444,
179
+ )
180
+
181
+ _TIMES_BOLDITALIC = (
182
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
183
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
184
+ 250, 389, 555, 500, 500, 833, 778, 278, 333, 333, 500, 570, 250, 333, 250, 278,
185
+ 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 333, 333, 570, 570, 570, 500,
186
+ 832, 667, 667, 667, 722, 667, 667, 722, 778, 389, 500, 667, 611, 889, 722, 722,
187
+ 611, 722, 667, 556, 611, 722, 667, 889, 667, 611, 611, 333, 278, 333, 570, 500,
188
+ 333, 500, 500, 444, 500, 444, 333, 500, 556, 278, 278, 500, 278, 778, 556, 500,
189
+ 500, 500, 389, 389, 278, 556, 444, 667, 500, 444, 389, 348, 220, 348, 570, 0,
190
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
191
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
192
+ 250, 389, 500, 500, 500, 500, 220, 500, 333, 747, 266, 500, 606, 333, 747, 333,
193
+ 400, 570, 300, 300, 333, 576, 500, 250, 333, 300, 300, 500, 750, 750, 750, 500,
194
+ 667, 667, 667, 667, 667, 667, 944, 667, 667, 667, 667, 667, 389, 389, 389, 389,
195
+ 722, 722, 722, 722, 722, 722, 722, 570, 722, 722, 722, 722, 722, 611, 611, 500,
196
+ 500, 500, 500, 500, 500, 500, 722, 444, 444, 444, 444, 444, 278, 278, 278, 278,
197
+ 500, 556, 500, 500, 500, 500, 500, 570, 500, 556, 556, 556, 556, 444, 500, 444,
198
+ )
199
+
200
+ _SYMBOL = (
201
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
202
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
203
+ 250, 333, 713, 500, 549, 833, 778, 631, 333, 333, 500, 549, 250, 549, 250, 278,
204
+ 500, 500, 500, 500, 500, 500, 500, 500, 500, 500, 278, 278, 549, 549, 549, 444,
205
+ 549, 722, 667, 722, 612, 611, 763, 603, 722, 333, 631, 722, 686, 889, 722, 722,
206
+ 768, 741, 556, 592, 611, 690, 631, 768, 645, 795, 611, 333, 863, 333, 658, 500,
207
+ 500, 631, 549, 549, 494, 631, 521, 411, 603, 329, 603, 549, 549, 576, 521, 549,
208
+ 549, 521, 549, 603, 631, 576, 713, 686, 493, 686, 494, 480, 200, 480, 549, 0,
209
+ 790, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
210
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
211
+ 750, 620, 247, 549, 167, 713, 500, 753, 753, 753, 753, 1042, 987, 603, 987, 603,
212
+ 400, 549, 411, 549, 549, 713, 494, 460, 549, 549, 549, 549, 1000, 603, 1000, 658,
213
+ 823, 686, 795, 987, 768, 768, 823, 768, 768, 713, 713, 713, 713, 713, 713, 713,
214
+ 768, 713, 790, 790, 890, 823, 549, 250, 713, 603, 603, 1042, 987, 603, 987, 603,
215
+ 494, 329, 790, 790, 786, 713, 384, 384, 384, 384, 384, 384, 494, 494, 494, 494,
216
+ 0, 329, 274, 686, 686, 686, 384, 384, 384, 384, 384, 384, 494, 494, 494, 0,
217
+ )
218
+
219
+ _ZAPFDINGBATS = (
220
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
221
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
222
+ 278, 974, 961, 974, 980, 719, 789, 790, 791, 690, 960, 939, 549, 855, 911, 933,
223
+ 911, 945, 974, 755, 846, 762, 761, 571, 677, 763, 760, 759, 754, 494, 552, 537,
224
+ 577, 692, 786, 788, 788, 790, 793, 794, 816, 823, 789, 841, 823, 833, 816, 831,
225
+ 923, 744, 723, 749, 790, 792, 695, 776, 768, 792, 759, 707, 708, 682, 701, 826,
226
+ 815, 789, 789, 707, 687, 696, 689, 786, 787, 713, 791, 785, 791, 873, 761, 762,
227
+ 762, 759, 759, 892, 892, 788, 784, 438, 138, 277, 415, 392, 392, 668, 668, 0,
228
+ 390, 390, 317, 317, 276, 276, 509, 509, 410, 410, 234, 234, 334, 334, 0, 0,
229
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
230
+ 0, 732, 544, 544, 910, 667, 760, 760, 776, 595, 694, 626, 788, 788, 788, 788,
231
+ 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788,
232
+ 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788, 788,
233
+ 788, 788, 788, 788, 894, 838, 1016, 458, 748, 924, 748, 918, 927, 928, 928, 834,
234
+ 873, 828, 924, 924, 917, 930, 931, 463, 883, 836, 836, 867, 867, 696, 696, 874,
235
+ 0, 874, 760, 946, 771, 865, 771, 888, 967, 888, 831, 873, 927, 970, 918, 0,
236
+ )
237
+
238
+ # Courier is monospaced at 600/1000 em in all four weights -- the AFM files
239
+ # say 600 for every glyph, including the ones the other faces do not have, so
240
+ # a table would be 1024 copies of one number. This is that number.
241
+ COURIER_WIDTH = 600
242
+
243
+ _COURIER = (COURIER_WIDTH,) * 256
244
+
245
+ # basefont name (the PDF /BaseFont, i.e. pdf.BASE14's own values) -> widths
246
+ # WinAnsiEncoding's 0x80-0x9F row -- the typographic range cp1252 adds over
247
+ # Latin-1 (curly quotes, en/em dashes, ellipsis, bullet, dagger, trademark,
248
+ # ligatures). The Latin-1-named base tables above carry 0 there; since
249
+ # pdf._esc writes cp1252 and the font objects declare /WinAnsiEncoding,
250
+ # these slots are real glyphs with real Adobe AFM widths. Slots WinAnsi
251
+ # leaves undefined (0x80 euro on the era's faces, 0x8D, 0x8F, 0x90, 0x9D)
252
+ # stay 0. Applied as an overlay so the hand-transcribed literals above stay
253
+ # exactly as the AFM files list them.
254
+ _WINANSI_HI = {
255
+ # sb₁ flo db₂ ell dag ddg cir pm Scn gsl OE ql qr dl dr bul en em til tm scn gsr oe Zcn zcn Ydi
256
+ 'Helvetica': {0x82: 222, 0x83: 556, 0x84: 333, 0x85: 1000,
257
+ 0x86: 556, 0x87: 556, 0x88: 333, 0x89: 1000, 0x8A: 667, 0x8B: 333,
258
+ 0x8C: 1000, 0x8E: 611, 0x91: 222, 0x92: 222, 0x93: 333, 0x94: 333,
259
+ 0x95: 350, 0x96: 556, 0x97: 1000, 0x98: 333, 0x99: 1000, 0x9A: 500,
260
+ 0x9B: 333, 0x9C: 944, 0x9E: 500, 0x9F: 667},
261
+ 'Helvetica-Bold': {0x82: 278, 0x83: 556, 0x84: 500, 0x85: 1000,
262
+ 0x86: 556, 0x87: 556, 0x88: 333, 0x89: 1000, 0x8A: 667, 0x8B: 333,
263
+ 0x8C: 1000, 0x8E: 611, 0x91: 278, 0x92: 278, 0x93: 500, 0x94: 500,
264
+ 0x95: 350, 0x96: 556, 0x97: 1000, 0x98: 333, 0x99: 1000, 0x9A: 556,
265
+ 0x9B: 333, 0x9C: 944, 0x9E: 500, 0x9F: 667},
266
+ 'Times-Roman': {0x82: 333, 0x83: 500, 0x84: 444, 0x85: 1000,
267
+ 0x86: 500, 0x87: 500, 0x88: 333, 0x89: 1000, 0x8A: 556, 0x8B: 333,
268
+ 0x8C: 889, 0x8E: 611, 0x91: 333, 0x92: 333, 0x93: 444, 0x94: 444,
269
+ 0x95: 350, 0x96: 500, 0x97: 1000, 0x98: 333, 0x99: 980, 0x9A: 389,
270
+ 0x9B: 333, 0x9C: 722, 0x9E: 444, 0x9F: 722},
271
+ 'Times-Bold': {0x82: 333, 0x83: 500, 0x84: 500, 0x85: 1000,
272
+ 0x86: 500, 0x87: 500, 0x88: 333, 0x89: 1000, 0x8A: 556, 0x8B: 333,
273
+ 0x8C: 1000, 0x8E: 667, 0x91: 333, 0x92: 333, 0x93: 500, 0x94: 500,
274
+ 0x95: 350, 0x96: 500, 0x97: 1000, 0x98: 333, 0x99: 1000, 0x9A: 389,
275
+ 0x9B: 333, 0x9C: 722, 0x9E: 444, 0x9F: 722},
276
+ 'Times-Italic': {0x82: 333, 0x83: 500, 0x84: 556, 0x85: 889,
277
+ 0x86: 500, 0x87: 500, 0x88: 333, 0x89: 1000, 0x8A: 500, 0x8B: 333,
278
+ 0x8C: 944, 0x8E: 556, 0x91: 333, 0x92: 333, 0x93: 556, 0x94: 556,
279
+ 0x95: 350, 0x96: 500, 0x97: 889, 0x98: 333, 0x99: 980, 0x9A: 389,
280
+ 0x9B: 333, 0x9C: 667, 0x9E: 389, 0x9F: 556},
281
+ 'Times-BoldItalic': {0x82: 333, 0x83: 500, 0x84: 500, 0x85: 1000,
282
+ 0x86: 500, 0x87: 500, 0x88: 333, 0x89: 1000, 0x8A: 556, 0x8B: 333,
283
+ 0x8C: 944, 0x8E: 611, 0x91: 333, 0x92: 333, 0x93: 500, 0x94: 500,
284
+ 0x95: 350, 0x96: 500, 0x97: 1000, 0x98: 333, 0x99: 1000, 0x9A: 389,
285
+ 0x9B: 333, 0x9C: 722, 0x9E: 389, 0x9F: 611},
286
+ }
287
+ _WINANSI_HI['Helvetica-Oblique'] = _WINANSI_HI['Helvetica']
288
+ _WINANSI_HI['Helvetica-BoldOblique'] = _WINANSI_HI['Helvetica-Bold']
289
+ _COURIER_HI = {k: 600 for k in _WINANSI_HI['Helvetica']}
290
+
291
+
292
+ def _overlay(base, hi):
293
+ t = list(base)
294
+ for k, v in hi.items():
295
+ t[k] = v
296
+ return tuple(t)
297
+
298
+
299
+ WIDTHS = {
300
+ 'Courier': _overlay(_COURIER, _COURIER_HI),
301
+ 'Courier-Bold': _overlay(_COURIER, _COURIER_HI),
302
+ 'Courier-Oblique': _overlay(_COURIER, _COURIER_HI),
303
+ 'Courier-BoldOblique': _overlay(_COURIER, _COURIER_HI),
304
+ 'Helvetica': _overlay(_HELVETICA, _WINANSI_HI['Helvetica']),
305
+ 'Helvetica-Bold': _overlay(_HELVETICA_BOLD, _WINANSI_HI['Helvetica-Bold']),
306
+ 'Helvetica-Oblique': _overlay(_HELVETICA_OBLIQUE,
307
+ _WINANSI_HI['Helvetica-Oblique']),
308
+ 'Helvetica-BoldOblique': _overlay(_HELVETICA_BOLDOBLIQUE,
309
+ _WINANSI_HI['Helvetica-BoldOblique']),
310
+ 'Times-Roman': _overlay(_TIMES_ROMAN, _WINANSI_HI['Times-Roman']),
311
+ 'Times-Bold': _overlay(_TIMES_BOLD, _WINANSI_HI['Times-Bold']),
312
+ 'Times-Italic': _overlay(_TIMES_ITALIC, _WINANSI_HI['Times-Italic']),
313
+ 'Times-BoldItalic': _overlay(_TIMES_BOLDITALIC,
314
+ _WINANSI_HI['Times-BoldItalic']),
315
+ 'Symbol': _SYMBOL,
316
+ 'ZapfDingbats': _ZAPFDINGBATS,
317
+ }
318
+
319
+
320
+ def string_width_1000(text, basefont):
321
+ """Natural width of `text` set in `basefont`, in 1/1000 em.
322
+
323
+ `text` is measured as pdf.py will WRITE it -- encoded cp1252 (the
324
+ declared /WinAnsiEncoding), with anything outside that repertoire
325
+ replaced by '?', which is exactly what `pdf._esc` does. Measuring the
326
+ str directly would count a character the PDF never receives.
327
+
328
+ An unknown basefont falls back to Courier's fixed 600: a face this table
329
+ does not carry cannot be measured, and 600 is this emitter's own default
330
+ pitch, not a guess at the missing face."""
331
+ table = WIDTHS.get(basefont, _COURIER)
332
+ return sum(table[b] for b in text.encode('cp1252', 'replace'))
333
+
334
+
335
+ def string_width_pt(text, basefont, size):
336
+ """Natural width of `text` in POINTS at `size`."""
337
+ return string_width_1000(text, basefont) * size / 1000.0