stationery 0.6.0 → 0.8.0
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +21 -0
- data/README.md +198 -18
- data/lib/stationery/builder.rb +5 -3
- data/lib/stationery/canvas/text.rb +4 -3
- data/lib/stationery/canvas.rb +24 -2
- data/lib/stationery/cli/render.rb +19 -4
- data/lib/stationery/document.rb +72 -11
- data/lib/stationery/elements.rb +1 -1
- data/lib/stationery/errors.rb +13 -0
- data/lib/stationery/fonts/fallback.rb +3 -3
- data/lib/stationery/fonts/font.rb +39 -21
- data/lib/stationery/fonts/gsub/single_subst.rb +37 -0
- data/lib/stationery/fonts/gsub.rb +65 -20
- data/lib/stationery/fonts/ligatures.rb +6 -4
- data/lib/stationery/hyphenation/patterns/LICENSES.md +60 -0
- data/lib/stationery/hyphenation/patterns/de-1996.pat.txt +36709 -0
- data/lib/stationery/hyphenation/patterns/en-us.hyp.txt +14 -0
- data/lib/stationery/hyphenation/patterns/en-us.pat.txt +4938 -0
- data/lib/stationery/hyphenation/patterns/sv.pat.txt +4693 -0
- data/lib/stationery/hyphenation.rb +132 -0
- data/lib/stationery/images/jpeg.rb +2 -1
- data/lib/stationery/images/png.rb +66 -0
- data/lib/stationery/images/resampled.rb +80 -0
- data/lib/stationery/layout/image.rb +28 -2
- data/lib/stationery/layout/paginator.rb +1 -1
- data/lib/stationery/layout/text.rb +2 -2
- data/lib/stationery/minitest.rb +17 -0
- data/lib/stationery/page_templates.rb +2 -1
- data/lib/stationery/pdf/assembler.rb +40 -6
- data/lib/stationery/pdf/attachments.rb +76 -0
- data/lib/stationery/pdf/conformance.rb +139 -0
- data/lib/stationery/pdf/factur_x.rb +117 -0
- data/lib/stationery/pdf/icc/LICENSE.md +14 -0
- data/lib/stationery/pdf/icc/sRGB2014.icc +0 -0
- data/lib/stationery/pdf/page_labels.rb +71 -0
- data/lib/stationery/pdf/stream.rb +5 -3
- data/lib/stationery/pdf/xmp.rb +149 -0
- data/lib/stationery/resources.rb +3 -0
- data/lib/stationery/svg/clip_path.rb +69 -0
- data/lib/stationery/svg/document.rb +26 -22
- data/lib/stationery/svg/painter.rb +11 -0
- data/lib/stationery/svg/region.rb +25 -0
- data/lib/stationery/svg/shapes.rb +2 -0
- data/lib/stationery/svg/style.rb +25 -14
- data/lib/stationery/svg/viewport.rb +78 -0
- data/lib/stationery/svg/walker.rb +142 -0
- data/lib/stationery/testing/inspector.rb +81 -0
- data/lib/stationery/testing/matchers.rb +77 -0
- data/lib/stationery/text/entities.rb +14 -4
- data/lib/stationery/text/paragraph.rb +1 -1
- data/lib/stationery/text/style.rb +14 -3
- data/lib/stationery/text/wrapper.rb +73 -12
- data/lib/stationery/version.rb +1 -1
- data/lib/stationery/warnings.rb +10 -0
- data/lib/stationery.rb +12 -0
- metadata +20 -1
data/lib/stationery/elements.rb
CHANGED
|
@@ -123,7 +123,7 @@ module Stationery
|
|
|
123
123
|
# `alt:` describes the image in a tagged PDF (false: decorative). Sizing,
|
|
124
124
|
# `fit: :cover`, `radius:` and `rotate:` as for Layout::Image.
|
|
125
125
|
def image(source, align: nil, **)
|
|
126
|
-
node = Layout::Image.new(source, **)
|
|
126
|
+
node = Layout::Image.new(source, **@_builder.images, **)
|
|
127
127
|
@_builder.add(align ? Layout::Flow.new([node], align:) : node)
|
|
128
128
|
end
|
|
129
129
|
|
data/lib/stationery/errors.rb
CHANGED
|
@@ -20,4 +20,17 @@ module Stationery
|
|
|
20
20
|
super("#{lines.size} #{noun}:\n#{lines.join("\n")}")
|
|
21
21
|
end
|
|
22
22
|
end
|
|
23
|
+
|
|
24
|
+
# Raised when a render cannot keep the conformance it claims (PDF/A,
|
|
25
|
+
# PDF/UA): `levels` are the claimed levels, `issues` what breaks them.
|
|
26
|
+
class ConformanceError < Error
|
|
27
|
+
attr_reader :levels, :issues
|
|
28
|
+
|
|
29
|
+
def initialize(levels, issues)
|
|
30
|
+
@levels = levels
|
|
31
|
+
@issues = issues
|
|
32
|
+
super("not #{levels.map { |level| Stationery::PDF::Conformance.label(level) }.join(" + ")}:\n" \
|
|
33
|
+
"#{issues.map { |issue| " #{issue}" }.join("\n")}")
|
|
34
|
+
end
|
|
35
|
+
end
|
|
23
36
|
end
|
|
@@ -6,13 +6,13 @@ module Stationery
|
|
|
6
6
|
# run's family, then the book's fallbacks in order, then bundled Inter. A
|
|
7
7
|
# glyph no font has stays in the run's family and draws as .notdef.
|
|
8
8
|
#
|
|
9
|
-
# Whitespace (any Unicode White_Space), joiners, variation
|
|
10
|
-
# combining marks carry the family of the character before them (or
|
|
9
|
+
# Whitespace (any Unicode White_Space), soft hyphens, joiners, variation
|
|
10
|
+
# selectors and combining marks carry the family of the character before them (or
|
|
11
11
|
# after them at the start of a run) so words are not chopped and marks
|
|
12
12
|
# stay with their base; whitespace a font lacks draws as a blank of the
|
|
13
13
|
# right width (see Font::WHITESPACE).
|
|
14
14
|
class Fallback
|
|
15
|
-
CARRIED = /[\p{Space}
|
|
15
|
+
CARRIED = /[\p{Space}︀-️\p{M}]/
|
|
16
16
|
|
|
17
17
|
def self.carried?(char) = CARRIED.match?(char)
|
|
18
18
|
|
|
@@ -23,6 +23,7 @@ module Stationery
|
|
|
23
23
|
0x2005 => 0.25, 0x2006 => 1.0 / 6, 0x2009 => 0.2, 0x200A => 0.125, 0x205F => 4.0 / 18,
|
|
24
24
|
0x3000 => 1.0 }.freeze
|
|
25
25
|
SPACE_LIKE = { 0x2007 => "0", 0x2008 => "." }.freeze
|
|
26
|
+
NO_FEATURES = [].freeze
|
|
26
27
|
|
|
27
28
|
attr_reader :ttf
|
|
28
29
|
|
|
@@ -32,9 +33,9 @@ module Stationery
|
|
|
32
33
|
@pairs = {}
|
|
33
34
|
@glyphs = {}
|
|
34
35
|
@blanks = {}
|
|
35
|
-
@shapes = {
|
|
36
|
-
@advances = {
|
|
37
|
-
@kerns = {
|
|
36
|
+
@shapes = {}
|
|
37
|
+
@advances = {}
|
|
38
|
+
@kerns = {}
|
|
38
39
|
@cid_keyed = ttf.cff? && ttf.cff.cid_keyed?
|
|
39
40
|
end
|
|
40
41
|
|
|
@@ -44,14 +45,19 @@ module Stationery
|
|
|
44
45
|
# word again (wrapping, then laying out the line) allocates nothing.
|
|
45
46
|
# Letter spacing is added per glyph, so a ligature counts once; any
|
|
46
47
|
# letter spacing turns ligatures off, as it does when drawing.
|
|
47
|
-
|
|
48
|
+
# `features:` are OpenType feature tags applied on top of `liga`.
|
|
49
|
+
def width_of(text, size, letter_spacing: 0, kerning: false, ligatures: true, features: NO_FEATURES)
|
|
48
50
|
ligatures &&= letter_spacing.zero?
|
|
49
|
-
|
|
51
|
+
key = shape_key(ligatures, features)
|
|
52
|
+
width = scale(advance_units(text, key), size) + (letter_spacing * shape(text, key).first.size)
|
|
50
53
|
return width unless kerning
|
|
51
54
|
|
|
52
|
-
width + (kerning_units(text,
|
|
55
|
+
width + (kerning_units(text, key) * size / 1000.0)
|
|
53
56
|
end
|
|
54
57
|
|
|
58
|
+
# The GSUB feature tags this font can apply.
|
|
59
|
+
def features = @ttf.ligatures.features
|
|
60
|
+
|
|
55
61
|
def ascender(size) = scale(@ttf.ascender, size)
|
|
56
62
|
def descender(size) = -scale(@ttf.descender, size)
|
|
57
63
|
def line_gap(size) = scale(@ttf.line_gap, size)
|
|
@@ -69,10 +75,11 @@ module Stationery
|
|
|
69
75
|
|
|
70
76
|
def encode(text) = glyph_run(text).gids.map { |gid| code(gid) }.pack("n*")
|
|
71
77
|
|
|
72
|
-
# `ligatures:` substitutes the font's standard ligatures
|
|
73
|
-
#
|
|
74
|
-
|
|
75
|
-
|
|
78
|
+
# `ligatures:` substitutes the font's standard ligatures and `features:`
|
|
79
|
+
# any further OpenType features; `kerning:` then fills the adjustments
|
|
80
|
+
# with pair kerning between the glyphs.
|
|
81
|
+
def glyph_run(text, kerning: false, ligatures: true, features: NO_FEATURES)
|
|
82
|
+
gids, chars, blanks = shape(text, shape_key(ligatures, features))
|
|
76
83
|
gids.each_with_index { |gid, i| @used[gid] ||= blanks[i] ? " " : chars[i] }
|
|
77
84
|
adjust = gids.each_with_index.map do |gid, i|
|
|
78
85
|
kern = kerning && i + 1 < gids.size ? pair(gid, gids[i + 1]) : 0
|
|
@@ -118,19 +125,30 @@ module Stationery
|
|
|
118
125
|
|
|
119
126
|
private
|
|
120
127
|
|
|
128
|
+
# The feature tags to substitute with: `liga` when ligatures are on, plus
|
|
129
|
+
# the requested features. Frozen and shared, so it keys the memos cheaply.
|
|
130
|
+
def shape_key(ligatures, features)
|
|
131
|
+
features = Text::Style.features(features) unless features.frozen? && features.all?(String)
|
|
132
|
+
return features unless ligatures
|
|
133
|
+
return Gsub::LIGA if features.empty?
|
|
134
|
+
|
|
135
|
+
@keys ||= {}
|
|
136
|
+
@keys[features] ||= (features + Gsub::LIGA).sort.freeze
|
|
137
|
+
end
|
|
138
|
+
|
|
121
139
|
# [gids, source text of each glyph, extra advance in font units after
|
|
122
|
-
# each blank or nil], remembered per string.
|
|
123
|
-
def shape(text,
|
|
124
|
-
@shapes[
|
|
140
|
+
# each blank or nil], remembered per string and feature tags.
|
|
141
|
+
def shape(text, tags)
|
|
142
|
+
(@shapes[tags] ||= {})[text] ||= begin
|
|
125
143
|
gids = text.each_char.map { |char| glyph_for(char) }
|
|
126
|
-
gids, chars =
|
|
144
|
+
gids, chars = tags.empty? ? [gids, text.chars] : substitute(gids, text, tags)
|
|
127
145
|
[gids, chars, chars.map { |char| blank_units(char) }].each(&:freeze).freeze
|
|
128
146
|
end
|
|
129
147
|
end
|
|
130
148
|
|
|
131
|
-
def
|
|
149
|
+
def substitute(gids, text, tags)
|
|
132
150
|
start = 0
|
|
133
|
-
glyphs = @ttf.ligatures.substitute(gids)
|
|
151
|
+
glyphs = @ttf.ligatures.substitute(gids, tags)
|
|
134
152
|
chars = glyphs.map { |_gid, count| text[start, count].tap { start += count } }
|
|
135
153
|
[glyphs.map(&:first), chars]
|
|
136
154
|
end
|
|
@@ -152,15 +170,15 @@ module Stationery
|
|
|
152
170
|
width - space
|
|
153
171
|
end
|
|
154
172
|
|
|
155
|
-
def advance_units(text,
|
|
156
|
-
@advances[
|
|
157
|
-
gids, _, blanks = shape(text,
|
|
173
|
+
def advance_units(text, tags)
|
|
174
|
+
(@advances[tags] ||= {})[text] ||= begin
|
|
175
|
+
gids, _, blanks = shape(text, tags)
|
|
158
176
|
gids.sum { |gid| @ttf.advance(gid) } + blanks.sum { |units| units || 0 }
|
|
159
177
|
end
|
|
160
178
|
end
|
|
161
179
|
|
|
162
|
-
def kerning_units(text,
|
|
163
|
-
@kerns[
|
|
180
|
+
def kerning_units(text, tags)
|
|
181
|
+
(@kerns[tags] ||= {})[text] ||= shape(text, tags).first.each_cons(2).sum { |left, right| pair(left, right) }
|
|
164
182
|
end
|
|
165
183
|
|
|
166
184
|
# Kerning between two glyphs in thousandths of an em.
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Stationery
|
|
4
|
+
module Fonts
|
|
5
|
+
class Gsub
|
|
6
|
+
# SingleSubst (GSUB lookup type 1): one glyph for another. Format 1
|
|
7
|
+
# adds a delta to every covered glyph, format 2 lists the substitute
|
|
8
|
+
# for each covered glyph in coverage order. Small caps, oldstyle and
|
|
9
|
+
# tabular figures, stylistic sets and slashed zero are all this.
|
|
10
|
+
class SingleSubst
|
|
11
|
+
def self.read(ttf, offset)
|
|
12
|
+
format = ttf.u16(offset)
|
|
13
|
+
coverage = Gpos::Coverage.read(ttf, offset + ttf.u16(offset + 2))
|
|
14
|
+
case format
|
|
15
|
+
when 1
|
|
16
|
+
delta = ttf.i16(offset + 4)
|
|
17
|
+
new(coverage.to_h { |gid| [gid, (gid + delta) & 0xFFFF] })
|
|
18
|
+
when 2
|
|
19
|
+
substitutes = ttf.data.byteslice(offset + 6, ttf.u16(offset + 4) * 2).unpack("n*")
|
|
20
|
+
new(coverage.zip(substitutes).to_h.compact)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def initialize(map)
|
|
25
|
+
@map = map.freeze
|
|
26
|
+
freeze
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# [substitute gid, 1] for a covered glyph at `index`, or nil.
|
|
30
|
+
def match(gids, index)
|
|
31
|
+
gid = @map[gids[index]]
|
|
32
|
+
[gid, 1] if gid
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -2,51 +2,96 @@
|
|
|
2
2
|
|
|
3
3
|
module Stationery
|
|
4
4
|
module Fonts
|
|
5
|
-
#
|
|
6
|
-
# (
|
|
7
|
-
#
|
|
8
|
-
#
|
|
5
|
+
# Glyph substitution from the font's GSUB table: every feature's
|
|
6
|
+
# SingleSubst (type 1) and LigatureSubst (type 4) lookups, directly or
|
|
7
|
+
# behind Extension lookups. `liga` gives the standard ligatures; `smcp`,
|
|
8
|
+
# `onum`, `tnum`, `dlig`, `ss01` and the rest are applied on request.
|
|
9
|
+
# Contextual lookups (types 5, 6 and 8) are not read, so `calt` and
|
|
10
|
+
# `clig` do nothing. Scripts, languages and lookup flags are not
|
|
11
|
+
# distinguished.
|
|
9
12
|
class Gsub
|
|
13
|
+
SINGLE = 1
|
|
10
14
|
LIGATURE = 4
|
|
11
15
|
EXTENSION = 7
|
|
16
|
+
LIGA = ["liga"].freeze
|
|
12
17
|
|
|
13
|
-
# nil when the font has no GSUB table or no
|
|
18
|
+
# nil when the font has no GSUB table, an unknown version, or no lookup
|
|
19
|
+
# of a supported type behind any feature.
|
|
14
20
|
def self.parse(ttf)
|
|
15
21
|
base = ttf.table_offset("GSUB")
|
|
16
22
|
return unless base && ttf.u16(base) == 1
|
|
17
23
|
|
|
18
|
-
lookups =
|
|
19
|
-
|
|
24
|
+
lookups = {}
|
|
25
|
+
features = feature_indices(ttf, base + ttf.u16(base + 6)).transform_values do |indices|
|
|
26
|
+
indices.filter_map do |i|
|
|
27
|
+
subtables = lookups[i] ||= lookup(ttf, base + ttf.u16(base + 8), i)
|
|
28
|
+
[i, subtables] unless subtables.empty?
|
|
29
|
+
end.freeze
|
|
30
|
+
end
|
|
31
|
+
features.reject! { |_, lookups_for| lookups_for.empty? }
|
|
32
|
+
new(features) if features.any?
|
|
20
33
|
end
|
|
21
34
|
|
|
22
|
-
#
|
|
23
|
-
|
|
35
|
+
# { tag => [lookup index, ...] } from the FeatureList, every record of a
|
|
36
|
+
# tag merged, in LookupList order.
|
|
37
|
+
def self.feature_indices(ttf, list)
|
|
38
|
+
Array.new(ttf.u16(list)) { |i| list + 2 + (i * 6) }.each_with_object({}) do |record, features|
|
|
39
|
+
tag = ttf.data.byteslice(record, 4)
|
|
40
|
+
feature = list + ttf.u16(record + 4)
|
|
41
|
+
indices = Array.new(ttf.u16(feature + 2)) { |j| ttf.u16(feature + 4 + (j * 2)) }
|
|
42
|
+
features[tag] = ((features[tag] || []) | indices).sort
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
private_class_method :feature_indices
|
|
46
|
+
|
|
47
|
+
# The `index`th lookup's supported subtables; other types have none.
|
|
48
|
+
def self.lookup(ttf, list, index)
|
|
49
|
+
offset = list + ttf.u16(list + 2 + (index * 2))
|
|
24
50
|
type = ttf.u16(offset)
|
|
25
51
|
subtables = Array.new(ttf.u16(offset + 4)) { |i| offset + ttf.u16(offset + 6 + (i * 2)) }
|
|
26
52
|
subtables.filter_map do |subtable|
|
|
27
|
-
if type ==
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
53
|
+
if type == EXTENSION
|
|
54
|
+
read(ttf.u16(subtable + 2), ttf, subtable + ttf.u32(subtable + 4))
|
|
55
|
+
else
|
|
56
|
+
read(type, ttf, subtable)
|
|
31
57
|
end
|
|
32
58
|
end.freeze
|
|
33
59
|
end
|
|
34
60
|
private_class_method :lookup
|
|
35
61
|
|
|
36
|
-
def
|
|
37
|
-
|
|
62
|
+
def self.read(type, ttf, offset)
|
|
63
|
+
case type
|
|
64
|
+
when SINGLE then SingleSubst.read(ttf, offset)
|
|
65
|
+
when LIGATURE then LigatureSubst.read(ttf, offset)
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
private_class_method :read
|
|
69
|
+
|
|
70
|
+
def initialize(features)
|
|
71
|
+
@features = features.freeze
|
|
72
|
+
@plans = {}
|
|
38
73
|
freeze
|
|
39
74
|
end
|
|
40
75
|
|
|
41
|
-
#
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
76
|
+
# The feature tags this font can apply, e.g. ["liga", "onum", "tnum"].
|
|
77
|
+
def features = @features.keys
|
|
78
|
+
|
|
79
|
+
# [[gid, number of source glyphs it stands for], ...] after applying the
|
|
80
|
+
# lookups of `tags` (feature tag Strings) in LookupList order, each once.
|
|
81
|
+
# Within a lookup the first subtable matching at a position wins and its
|
|
82
|
+
# glyph is not matched again by that lookup.
|
|
83
|
+
def substitute(gids, tags = LIGA)
|
|
84
|
+
plan(tags).reduce(gids.map { |gid| [gid, 1] }) { |glyphs, subtables| apply(subtables, glyphs) }
|
|
46
85
|
end
|
|
47
86
|
|
|
48
87
|
private
|
|
49
88
|
|
|
89
|
+
# The lookups the tags name, merged and ordered; remembered per tag list.
|
|
90
|
+
def plan(tags)
|
|
91
|
+
@plans[tags] ||= tags.flat_map { |tag| @features[tag] || [] }.uniq(&:first).sort_by(&:first)
|
|
92
|
+
.map(&:last).freeze
|
|
93
|
+
end
|
|
94
|
+
|
|
50
95
|
def apply(subtables, glyphs)
|
|
51
96
|
ids = glyphs.map(&:first)
|
|
52
97
|
result = []
|
|
@@ -2,12 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
module Stationery
|
|
4
4
|
module Fonts
|
|
5
|
-
# Chooses where a font's
|
|
6
|
-
# `substitute(gids)` with [[gid, source glyph
|
|
5
|
+
# Chooses where a font's glyph substitutions come from. Every source
|
|
6
|
+
# answers `substitute(gids, feature_tags)` with [[gid, source glyph
|
|
7
|
+
# count], ...] and `features` with the tags it can apply.
|
|
7
8
|
module Ligatures
|
|
8
|
-
# For fonts without
|
|
9
|
+
# For fonts without a usable GSUB table: every glyph stands for itself.
|
|
9
10
|
module NONE
|
|
10
|
-
def self.substitute(gids) = gids.map { |gid| [gid, 1] }
|
|
11
|
+
def self.substitute(gids, _tags = Gsub::LIGA) = gids.map { |gid| [gid, 1] }
|
|
12
|
+
def self.features = []
|
|
11
13
|
end
|
|
12
14
|
|
|
13
15
|
def self.for(ttf) = Gsub.parse(ttf) || NONE
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Hyphenation patterns
|
|
2
|
+
|
|
3
|
+
The `*.pat.txt` and `*.hyp.txt` files in this directory are the plain-text
|
|
4
|
+
(UTF-8) pattern and exception lists from the TeX `hyph-utf8` package
|
|
5
|
+
(https://github.com/hyphenation/tex-hyphen, `hyph-utf8/tex/generic/hyph-utf8/patterns/txt/`),
|
|
6
|
+
unmodified. Each file's own copyright and licence follow, copied from the header
|
|
7
|
+
of its `.tex` source in the same package. The Ruby code that reads them
|
|
8
|
+
(`lib/stationery/hyphenation.rb`) is stationery's and under stationery's licence.
|
|
9
|
+
|
|
10
|
+
## en-us.pat.txt, en-us.hyp.txt — Hyphenation patterns for American English
|
|
11
|
+
|
|
12
|
+
Copyright (C) 1990, 2004, 2005 Gerard D.C. Kuiken. Source: `hyph-en-us.tex`
|
|
13
|
+
(`ushyphmax.tex`, version 2005-05-30). Based on Liang's patterns and the
|
|
14
|
+
Hyphenation Exception Log published in TUGboat, Volume 10 (1989), No. 3.
|
|
15
|
+
|
|
16
|
+
> Copying and distribution of this file, with or without modification, are
|
|
17
|
+
> permitted in any medium without royalty provided the copyright notice and
|
|
18
|
+
> this notice are preserved.
|
|
19
|
+
|
|
20
|
+
Typesetting minimums: 2 letters before a break, 3 after.
|
|
21
|
+
|
|
22
|
+
## de-1996.pat.txt — German Hyphenation Patterns (Reformed Orthography, 2006)
|
|
23
|
+
|
|
24
|
+
TeX-Trennmuster für die reformierte (2006) deutsche Rechtschreibung, version
|
|
25
|
+
2024-02-28, by the Deutschsprachige Trennmustermannschaft (trennmuster@dante.de).
|
|
26
|
+
Copyright (c) 2013-2024 Stephan Hennig, Werner Lemberg, Günter Milde, Sander van
|
|
27
|
+
Geloven, Georg Pfeiffer, Gisbert W. Selke, Tobias Wendorf, Keno Wehr. Source:
|
|
28
|
+
`hyph-de-1996.tex`; generated from
|
|
29
|
+
https://repo.or.cz/w/wortliste.git?a=commit;h=304aaa2188a75e57afe36bad0443d90a9c715b8e.
|
|
30
|
+
Licence: MIT (https://opensource.org/licenses/mit-license.php).
|
|
31
|
+
|
|
32
|
+
> Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
33
|
+
> of this software and associated documentation files (the “Software”), to deal
|
|
34
|
+
> in the Software without restriction, including without limitation the rights
|
|
35
|
+
> to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
36
|
+
> copies of the Software, and to permit persons to whom the Software is
|
|
37
|
+
> furnished to do so, subject to the following conditions:
|
|
38
|
+
>
|
|
39
|
+
> The above copyright notice and this permission notice shall be included in
|
|
40
|
+
> all copies or substantial portions of the Software.
|
|
41
|
+
>
|
|
42
|
+
> THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
43
|
+
> IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
44
|
+
> FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
45
|
+
> AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
46
|
+
> LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
47
|
+
> OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
48
|
+
> SOFTWARE.
|
|
49
|
+
|
|
50
|
+
Typesetting minimums: 2 letters before a break, 2 after.
|
|
51
|
+
|
|
52
|
+
## sv.pat.txt — Hyphenation patterns for Swedish
|
|
53
|
+
|
|
54
|
+
Copyright (C) 1994 Jan Michael Rynning (jmr (at) incolumitas.se), version
|
|
55
|
+
1994-03-03. Source: `hyph-sv.tex`. Licence: LaTeX Project Public License,
|
|
56
|
+
version 1.2 or later (https://www.latex-project.org/lppl/). This file is
|
|
57
|
+
distributed unmodified, as the "Current Maintainer" released it; the LPPL
|
|
58
|
+
requires that a modified version be renamed and identified as such.
|
|
59
|
+
|
|
60
|
+
Typesetting minimums: 2 letters before a break, 2 after.
|